sound updates for 6.9-rc1

This was a relatively calm development cycle.  Most of changes are
 rather small device-specific fixes and enhancements.  The only
 significant changes in ALSA core are code refactoring with the recent
 cleanup infrastructure, which should bring no functionality changes.
 Some highlights below:
 
 Core:
 - Lots of cleanups in ALSA core code with automatic kfree cleanup
   and locking guard macros
 - New ALSA core kunit test
 
 ASoC:
 - SoundWire support for AMD ACP 6.3 systems
 - Support for reporting version information for AVS firmware
 - Support DSPless mode for Intel Soundwire systems
 - Support for configuring CS35L56 amplifiers using EFI calibration
    data
 - Log which component is being operated on as part of power management
    trace events.
 - Support for Microchip SAM9x7, NXP i.MX95 and Qualcomm WCD939x
 
 HD- and USB-audio:
 - More Cirrus HD-audio codec support
 - TAS2781 HD-audio codec fixes
 - Scarlett2 mixer fixes
 
 Others:
 - Enhancement of virtio driver for audio control supports
 - Cleanups of legacy PM code with new macros
 - Firewire sound updates
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmXyzFQOHHRpd2FpQHN1
 c2UuZGUACgkQLtJE4w1nLE80WQ//bQeLEUF9HQqprCW96jFiGeO3/0Zb5pdCCrZw
 VYRxzeGBfMfVFvXSC4/Rp3zr4Dbc+sOg9GXAD6PVAo/QudIDkuX1pk/gRN2NFXQ5
 bimdZ6obM4WCl7isbDIbn/ifOx05F7p0+J9T9nAPrvBG4lpzXoMhGz75YnwaPlrh
 q5MKEZcuONlZPHZrBy/UsrYqWrnWUi2yWgQ5gRg/PTM4dgUAy2pH7NpKNxOiRntJ
 eqBfdvglSWQDH9kPgmeTggtFN8Axy+pd+g9M5pi/KOJfoBpWuv2nK31gnymdqV4H
 UrmwU/VAL2Y0zU34RCZQvPFre6S+487FEf/g+qgVTDqi0kxxFT2btcaTjggjLwEy
 p/SJlqNnA7W7D67/qf4MPNOEp88Dd6o1YN7o01vyC9RoX5FAbzvNLF8oH4BwGxs+
 HI+5aJUY1f2MGwN3NpPW5E12d1RSgSi9L9l/R8oAQmonARr3drj3tkndhFjndgXG
 IctwHlkYRSibe6m5k6sDEcil70UNl5M6sr/IjPmDvYudjdKHisowrxqF+nPrAYdM
 0z3fW333+OQf0XVd9iPLBmq+PpiAY1AhCJeF/hPr3D5qDZInhcd8CouFie+QGkHT
 Z5j5CvhNLgRdmlW9jvfBPBBCT7u8jr6JFszA3g6wpWUx6ndAGsI1z6iC+h23NpZj
 dxmJU00=
 =h9kz
 -----END PGP SIGNATURE-----

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

Pull sound updates from Takashi Iwai:
 "This was a relatively calm development cycle. Most of changes are
  rather small device-specific fixes and enhancements. The only
  significant changes in ALSA core are code refactoring with the recent
  cleanup infrastructure, which should bring no functionality changes.
  Some highlights below:

  Core:
   - Lots of cleanups in ALSA core code with automatic kfree cleanup and
     locking guard macros
   - New ALSA core kunit test

  ASoC:
   - SoundWire support for AMD ACP 6.3 systems
   - Support for reporting version information for AVS firmware
   - Support DSPless mode for Intel Soundwire systems
   - Support for configuring CS35L56 amplifiers using EFI calibration
     data
   - Log which component is being operated on as part of power
     management trace events.
   - Support for Microchip SAM9x7, NXP i.MX95 and Qualcomm WCD939x

  HD- and USB-audio:
   - More Cirrus HD-audio codec support
   - TAS2781 HD-audio codec fixes
   - Scarlett2 mixer fixes

  Others:
   - Enhancement of virtio driver for audio control supports
   - Cleanups of legacy PM code with new macros
   - Firewire sound updates"

* tag 'sound-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (307 commits)
  ALSA: usb-audio: Stop parsing channels bits when all channels are found.
  ALSA: hda/tas2781: remove unnecessary runtime_pm calls
  ALSA: hda/realtek - ALC236 fix volume mute & mic mute LED on some HP models
  ALSA: aaci: Delete unused variable in aaci_do_suspend
  ALSA: scarlett2: Fix Scarlett 4th Gen input gain range again
  ALSA: scarlett2: Fix Scarlett 4th Gen input gain range
  ALSA: scarlett2: Fix Scarlett 4th Gen autogain status values
  ALSA: scarlett2: Fix Scarlett 4th Gen 4i4 low-voltage detection
  ALSA: hda/tas2781: restore power state after system_resume
  ALSA: hda/tas2781: do not call pm_runtime_force_* in system_resume/suspend
  ALSA: hda/tas2781: do not reset cur_* values in runtime_suspend
  ALSA: hda/tas2781: add lock to system_suspend
  ALSA: hda/tas2781: use dev_dbg in system_resume
  ALSA: hda/realtek: fix ALC285 issues on HP Envy x360 laptops
  platform/x86: serial-multi-instantiate: Add support for CS35L54 and CS35L57
  ALSA: hda: cs35l56: Add support for CS35L54 and CS35L57
  ASoC: cs35l56: Add support for CS35L54 and CS35L57
  ASoC: Intel: catpt: Carefully use PCI bitwise constants
  ALSA: hda: hda_component: Include sound/hda_codec.h
  ALSA: hda: hda_component: Add missing #include guards
  ...
This commit is contained in:
Linus Torvalds 2024-03-14 11:10:43 -07:00
commit fe46a7dd18
344 changed files with 16601 additions and 5314 deletions

View File

@ -0,0 +1,8 @@
What: /sys/devices/pci0000:00/<dev>/avs/fw_version
Date: February 2024
Contact: Cezary Rojewski <cezary.rojewski@intel.com>
Description:
Version of AudioDSP firmware ASoC avs driver is communicating
with.
Format: %d.%d.%d.%d, type:major:minor:build.

View File

@ -0,0 +1,84 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/atmel,asoc-wm8904.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Atmel wm8904 audio codec complex
maintainers:
- Dharma Balasubiramani <dharma.b@microchip.com>
description:
The ASoC audio complex configuration for Atmel with WM8904 audio codec.
properties:
compatible:
const: atmel,asoc-wm8904
atmel,model:
$ref: /schemas/types.yaml#/definitions/string
description: The user-visible name of this sound complex.
atmel,ssc-controller:
$ref: /schemas/types.yaml#/definitions/phandle
description: The phandle of the SSC controller.
atmel,audio-codec:
$ref: /schemas/types.yaml#/definitions/phandle
description: The phandle of the WM8731 audio codec.
atmel,audio-routing:
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.
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
items:
enum:
# Board Connectors
- Headphone Jack
- Line In Jack
- Mic
# WM8904 CODEC Pins
- IN1L
- IN1R
- IN2L
- IN2R
- IN3L
- IN3R
- HPOUTL
- HPOUTR
- LINEOUTL
- LINEOUTR
- MICBIAS
required:
- compatible
- atmel,model
- atmel,audio-routing
- atmel,ssc-controller
- atmel,audio-codec
additionalProperties: false
examples:
- |
sound {
compatible = "atmel,asoc-wm8904";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pck0_as_mck>;
atmel,model = "wm8904 @ AT91SAM9N12EK";
atmel,audio-routing =
"Headphone Jack", "HPOUTL",
"Headphone Jack", "HPOUTR",
"IN2L", "Line In Jack",
"IN2R", "Line In Jack",
"Mic", "MICBIAS",
"IN1L", "Mic";
atmel,ssc-controller = <&ssc0>;
atmel,audio-codec = <&wm8904>;
};

View File

@ -0,0 +1,76 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/atmel,sam9x5-wm8731-audio.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Atmel at91sam9x5ek wm8731 audio complex
maintainers:
- Dharma Balasubiramani <dharma.b@microchip.com>
description:
The audio complex configuration for Atmel at91sam9x5ek with WM8731 audio codec.
properties:
compatible:
const: atmel,sam9x5-wm8731-audio
atmel,model:
$ref: /schemas/types.yaml#/definitions/string
description: The user-visible name of this sound complex.
atmel,ssc-controller:
$ref: /schemas/types.yaml#/definitions/phandle
description: The phandle of the SSC controller.
atmel,audio-codec:
$ref: /schemas/types.yaml#/definitions/phandle
description: The phandle of the WM8731 audio codec.
atmel,audio-routing:
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.
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
items:
enum:
# Board Connectors
- Headphone Jack
- Line In Jack
# CODEC Pins
- LOUT
- ROUT
- LHPOUT
- RHPOUT
- LLINEIN
- RLINEIN
- MICIN
required:
- compatible
- atmel,model
- atmel,ssc-controller
- atmel,audio-codec
- atmel,audio-routing
additionalProperties: false
examples:
- |
sound {
compatible = "atmel,sam9x5-wm8731-audio";
atmel,model = "wm8731 @ AT91SAM9X5EK";
atmel,audio-routing =
"Headphone Jack", "RHPOUT",
"Headphone Jack", "LHPOUT",
"LLINEIN", "Line In Jack",
"RLINEIN", "Line In Jack";
atmel,ssc-controller = <&ssc0>;
atmel,audio-codec = <&wm8731>;
};

View File

@ -18,7 +18,12 @@ description:
properties:
compatible:
const: atmel,sama5d2-classd
oneOf:
- items:
- const: atmel,sama5d2-classd
- items:
- const: microchip,sam9x7-classd
- const: atmel,sama5d2-classd
reg:
maxItems: 1

View File

@ -1,35 +0,0 @@
* Atmel at91sam9x5ek wm8731 audio complex
Required properties:
- compatible: "atmel,sam9x5-wm8731-audio"
- atmel,model: The user-visible name of this sound complex.
- atmel,ssc-controller: The phandle of the SSC controller
- atmel,audio-codec: The phandle of the WM8731 audio codec
- atmel,audio-routing: A list of the connections between audio components.
Each entry is a pair of strings, the first being the connection's sink,
the second being the connection's source.
Available audio endpoints for the audio-routing table:
Board connectors:
* Headphone Jack
* Line In Jack
wm8731 pins:
cf Documentation/devicetree/bindings/sound/wlf,wm8731.yaml
Example:
sound {
compatible = "atmel,sam9x5-wm8731-audio";
atmel,model = "wm8731 @ AT91SAM9X5EK";
atmel,audio-routing =
"Headphone Jack", "RHPOUT",
"Headphone Jack", "LHPOUT",
"LLINEIN", "Line In Jack",
"RLINEIN", "Line In Jack";
atmel,ssc-controller = <&ssc0>;
atmel,audio-codec = <&wm8731>;
};

View File

@ -1,55 +0,0 @@
Atmel ASoC driver with wm8904 audio codec complex
Required properties:
- compatible: "atmel,asoc-wm8904"
- atmel,model: The user-visible name of this sound complex.
- atmel,audio-routing: A list of the connections between audio components.
Each entry is a pair of strings, the first being the connection's sink,
the second being the connection's source. Valid names for sources and
sinks are the WM8904's pins, and the jacks on the board:
WM8904 pins:
* IN1L
* IN1R
* IN2L
* IN2R
* IN3L
* IN3R
* HPOUTL
* HPOUTR
* LINEOUTL
* LINEOUTR
* MICBIAS
Board connectors:
* Headphone Jack
* Line In Jack
* Mic
- atmel,ssc-controller: The phandle of the SSC controller
- atmel,audio-codec: The phandle of the WM8904 audio codec
Optional properties:
- pinctrl-names, pinctrl-0: Please refer to pinctrl-bindings.txt
Example:
sound {
compatible = "atmel,asoc-wm8904";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pck0_as_mck>;
atmel,model = "wm8904 @ AT91SAM9N12EK";
atmel,audio-routing =
"Headphone Jack", "HPOUTL",
"Headphone Jack", "HPOUTR",
"IN2L", "Line In Jack",
"IN2R", "Line In Jack",
"Mic", "MICBIAS",
"IN1L", "Mic";
atmel,ssc-controller = <&ssc0>;
atmel,audio-codec = <&wm8904>;
};

View File

@ -51,7 +51,7 @@ definitions:
- $ref: /schemas/types.yaml#/definitions/phandle
clocks:
description: Indicates system clock
$ref: /schemas/types.yaml#/definitions/phandle
maxItems: 1
system-clock-frequency:
$ref: simple-card.yaml#/definitions/system-clock-frequency
system-clock-direction-out:

View File

@ -25,6 +25,9 @@ properties:
reg:
maxItems: 1
interrupts:
maxItems: 1
'#sound-dai-cells':
const: 1

View File

@ -38,6 +38,7 @@ properties:
default: 0x0f
everest,mic1-src:
deprecated: true
$ref: /schemas/types.yaml#/definitions/uint8
description:
the value of reg 2A when headset plugged.
@ -46,6 +47,7 @@ properties:
default: 0x22
everest,mic2-src:
deprecated: true
$ref: /schemas/types.yaml#/definitions/uint8
description:
the value of reg 2A when headset unplugged.
@ -87,7 +89,7 @@ properties:
0 means the chip detect jack type again after button released.
minimum: 0
maximum: 0x7f
default: 0x45
default: 0x00
required:
- compatible
@ -107,10 +109,8 @@ examples:
clocks = <&clks 10>;
clock-names = "mclk";
#sound-dai-cells = <0>;
everest,mic1-src = [22];
everest,mic2-src = [44];
everest,jack-pol = [0e];
everest,interrupt-src = [08];
everest,interrupt-clk = [45];
everest,interrupt-clk = [00];
};
};

View File

@ -1,80 +0,0 @@
Freescale Asynchronous Sample Rate Converter (ASRC) Controller
The Asynchronous Sample Rate Converter (ASRC) converts the sampling rate of a
signal associated with an input clock into a signal associated with a different
output clock. The driver currently works as a Front End of DPCM with other Back
Ends Audio controller such as ESAI, SSI and SAI. It has three pairs to support
three substreams within totally 10 channels.
Required properties:
- compatible : Compatible list, should contain one of the following
compatibles:
"fsl,imx35-asrc",
"fsl,imx53-asrc",
"fsl,imx8qm-asrc",
"fsl,imx8qxp-asrc",
- reg : Offset and length of the register set for the device.
- interrupts : Contains the spdif interrupt.
- dmas : Generic dma devicetree binding as described in
Documentation/devicetree/bindings/dma/dma.txt.
- dma-names : Contains "rxa", "rxb", "rxc", "txa", "txb" and "txc".
- clocks : Contains an entry for each entry in clock-names.
- clock-names : Contains the following entries
"mem" Peripheral access clock to access registers.
"ipg" Peripheral clock to driver module.
"asrck_<0-f>" Clock sources for input and output clock.
"spba" The spba clock is required when ASRC is placed as a
bus slave of the Shared Peripheral Bus and when two
or more bus masters (CPU, DMA or DSP) try to access
it. This property is optional depending on the SoC
design.
- fsl,asrc-rate : Defines a mutual sample rate used by DPCM Back Ends.
- fsl,asrc-width : Defines a mutual sample width used by DPCM Back Ends.
- fsl,asrc-clk-map : Defines clock map used in driver. which is required
by imx8qm/imx8qxp platform
<0> - select the map for asrc0 in imx8qm/imx8qxp
<1> - select the map for asrc1 in imx8qm/imx8qxp
Optional properties:
- big-endian : If this property is absent, the little endian mode
will be in use as default. Otherwise, the big endian
mode will be in use for all the device registers.
- fsl,asrc-format : Defines a mutual sample format used by DPCM Back
Ends, which can replace the fsl,asrc-width.
The value is 2 (S16_LE), or 6 (S24_LE).
Example:
asrc: asrc@2034000 {
compatible = "fsl,imx53-asrc";
reg = <0x02034000 0x4000>;
interrupts = <0 50 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks 107>, <&clks 107>, <&clks 0>,
<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
<&clks 107>, <&clks 0>, <&clks 0>;
clock-names = "mem", "ipg", "asrck0",
"asrck_1", "asrck_2", "asrck_3", "asrck_4",
"asrck_5", "asrck_6", "asrck_7", "asrck_8",
"asrck_9", "asrck_a", "asrck_b", "asrck_c",
"asrck_d", "asrck_e", "asrck_f";
dmas = <&sdma 17 23 1>, <&sdma 18 23 1>, <&sdma 19 23 1>,
<&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>;
dma-names = "rxa", "rxb", "rxc",
"txa", "txb", "txc";
fsl,asrc-rate = <48000>;
fsl,asrc-width = <16>;
};

View File

@ -51,8 +51,8 @@ properties:
- const: ctx3_tx
firmware-name:
$ref: /schemas/types.yaml#/definitions/string
const: imx/easrc/easrc-imx8mn.bin
items:
- const: imx/easrc/easrc-imx8mn.bin
description: The coefficient table for the filters
fsl,asrc-rate:

View File

@ -0,0 +1,162 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/fsl,imx-asrc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale Asynchronous Sample Rate Converter (ASRC) Controller
description:
The Asynchronous Sample Rate Converter (ASRC) converts the sampling rate of
a signal associated with an input clock into a signal associated with a
different output clock. The driver currently works as a Front End of DPCM
with other Back Ends Audio controller such as ESAI, SSI and SAI. It has
three pairs to support three substreams within totally 10 channels.
maintainers:
- Shawn Guo <shawnguo@kernel.org>
- Sascha Hauer <s.hauer@pengutronix.de>
properties:
compatible:
oneOf:
- enum:
- fsl,imx35-asrc
- fsl,imx53-asrc
- fsl,imx8qm-asrc
- fsl,imx8qxp-asrc
- items:
- enum:
- fsl,imx6sx-asrc
- fsl,imx6ul-asrc
- const: fsl,imx53-asrc
reg:
maxItems: 1
interrupts:
maxItems: 1
dmas:
maxItems: 6
dma-names:
items:
- const: rxa
- const: rxb
- const: rxc
- const: txa
- const: txb
- const: txc
clocks:
maxItems: 19
clock-names:
items:
- const: mem
- const: ipg
- const: asrck_0
- const: asrck_1
- const: asrck_2
- const: asrck_3
- const: asrck_4
- const: asrck_5
- const: asrck_6
- const: asrck_7
- const: asrck_8
- const: asrck_9
- const: asrck_a
- const: asrck_b
- const: asrck_c
- const: asrck_d
- const: asrck_e
- const: asrck_f
- const: spba
fsl,asrc-rate:
$ref: /schemas/types.yaml#/definitions/uint32
description: The mutual sample rate used by DPCM Back Ends
fsl,asrc-width:
$ref: /schemas/types.yaml#/definitions/uint32
description: The mutual sample width used by DPCM Back Ends
enum: [16, 24]
fsl,asrc-clk-map:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Defines clock map used in driver
<0> - select the map for asrc0 in imx8qm/imx8qxp
<1> - select the map for asrc1 in imx8qm/imx8qxp
enum: [0, 1]
big-endian:
type: boolean
description:
If this property is absent, the little endian mode will be in use as
default. Otherwise, the big endian mode will be in use for all the
device registers.
fsl,asrc-format:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Defines a mutual sample format used by DPCM Back Ends, which can
replace the fsl,asrc-width. The value is 2 (S16_LE), or 6 (S24_LE).
enum: [2, 6]
required:
- compatible
- reg
- interrupts
- dmas
- dma-names
- clocks
- clock-names
- fsl,asrc-rate
- fsl,asrc-width
allOf:
- if:
properties:
compatible:
contains:
enum:
- fsl,imx8qm-asrc
- fsl,imx8qxp-asrc
then:
required:
- fsl,asrc-clk-map
else:
properties:
fsl,asrc-clk-map: false
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/clock/imx6qdl-clock.h>
asrc: asrc@2034000 {
compatible = "fsl,imx53-asrc";
reg = <0x02034000 0x4000>;
interrupts = <0 50 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6QDL_CLK_ASRC_IPG>,
<&clks IMX6QDL_CLK_ASRC_MEM>, <&clks 0>,
<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
<&clks IMX6QDL_CLK_ASRC>, <&clks 0>, <&clks 0>,
<&clks IMX6QDL_CLK_SPBA>;
clock-names = "mem", "ipg", "asrck_0",
"asrck_1", "asrck_2", "asrck_3", "asrck_4",
"asrck_5", "asrck_6", "asrck_7", "asrck_8",
"asrck_9", "asrck_a", "asrck_b", "asrck_c",
"asrck_d", "asrck_e", "asrck_f", "spba";
dmas = <&sdma 17 23 1>, <&sdma 18 23 1>, <&sdma 19 23 1>,
<&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>;
dma-names = "rxa", "rxb", "rxc",
"txa", "txb", "txc";
fsl,asrc-rate = <48000>;
fsl,asrc-width = <16>;
};

View File

@ -15,10 +15,16 @@ description: |
properties:
compatible:
enum:
- fsl,imx8mm-micfil
- fsl,imx8mp-micfil
- fsl,imx93-micfil
oneOf:
- items:
- enum:
- fsl,imx95-micfil
- const: fsl,imx93-micfil
- enum:
- fsl,imx8mm-micfil
- fsl,imx8mp-micfil
- fsl,imx93-micfil
reg:
maxItems: 1

View File

@ -39,6 +39,7 @@ properties:
- fsl,imx8qm-sai
- fsl,imx8ulp-sai
- fsl,imx93-sai
- fsl,imx95-sai
- fsl,vf610-sai
reg:
@ -75,12 +76,17 @@ properties:
- const: pll11k
minItems: 4
power-domains:
maxItems: 1
dmas:
minItems: 1
items:
- description: DMA controller phandle and request line for RX
- description: DMA controller phandle and request line for TX
dma-names:
minItems: 1
items:
- const: rx
- const: tx

View File

@ -51,7 +51,7 @@ properties:
maxItems: 1
firmware-name:
$ref: /schemas/types.yaml#/definitions/string
maxItems: 1
description:
Filters coefficients file to load. If this property is omitted, internal
filters are disabled.

View File

@ -24,9 +24,14 @@ properties:
const: 0
compatible:
enum:
- microchip,sam9x60-i2smcc
- microchip,sama7g5-i2smcc
oneOf:
- enum:
- microchip,sam9x60-i2smcc
- microchip,sama7g5-i2smcc
- items:
- enum:
- microchip,sam9x7-i2smcc
- const: microchip,sam9x60-i2smcc
reg:
maxItems: 1

View File

@ -107,7 +107,7 @@ patternProperties:
properties:
sound-dai:
minItems: 1
maxItems: 4
maxItems: 8
required:
- link-name

View File

@ -15,6 +15,7 @@ description: |
allOf:
- $ref: dai-common.yaml#
- $ref: qcom,wcd93xx-common.yaml#
properties:
compatible:
@ -22,92 +23,12 @@ properties:
- qcom,wcd9380-codec
- qcom,wcd9385-codec
reset-gpios:
description: GPIO spec for reset line to use
maxItems: 1
us-euro-gpios:
description: GPIO spec for swapping gnd and mic segments
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
vdd-mic-bias-supply:
description: A reference to the 3.8V mic bias 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"
unevaluatedProperties: false

View File

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

View File

@ -0,0 +1,96 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/qcom,wcd939x.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm WCD9380/WCD9385 Audio Codec
maintainers:
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
description: |
Qualcomm WCD9390/WCD9395 Codec is a standalone Hi-Fi audio codec IC.
It has RX and TX Soundwire devices.
The WCD9390/WCD9395 IC has a functionally separate USB-C Mux subsystem
accessible over an I2C interface.
The Audio Headphone and Microphone data path between the Codec and the USB-C Mux
subsystems are external to the IC, thus requiring DT port-endpoint graph description
to handle USB-C altmode & orientation switching for Audio Accessory Mode.
allOf:
- $ref: dai-common.yaml#
- $ref: qcom,wcd93xx-common.yaml#
properties:
compatible:
oneOf:
- const: qcom,wcd9390-codec
- items:
- const: qcom,wcd9395-codec
- const: qcom,wcd9390-codec
mode-switch:
description: Flag the port as possible handler of altmode switching
type: boolean
orientation-switch:
description: Flag the port as possible handler of orientation switching
type: boolean
port:
$ref: /schemas/graph.yaml#/properties/port
description:
A port node to link the WCD939x Codec node to USB MUX subsystems for the
purpose of handling altmode muxing and orientation switching to detect and
enable Audio Accessory Mode.
required:
- compatible
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
codec {
compatible = "qcom,wcd9390-codec";
reset-gpios = <&tlmm 32 IRQ_TYPE_NONE>;
#sound-dai-cells = <1>;
qcom,tx-device = <&wcd939x_tx>;
qcom,rx-device = <&wcd939x_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>;
wcd939x_rx: codec@0,4 {
compatible = "sdw20217010e00";
reg = <0 4>;
qcom,rx-port-mapping = <1 2 3 4 5 6>;
};
};
soundwire@3230000 {
#address-cells = <2>;
#size-cells = <0>;
reg = <0x03230000 0x2000>;
wcd938x_tx: codec@0,3 {
compatible = "sdw20217010e00";
reg = <0 3>;
qcom,tx-port-mapping = <2 3 4 5>;
};
};
...

View File

@ -0,0 +1,95 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/qcom,wcd93xx-common.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Common properties for Qualcomm WCD93xx Audio Codec
maintainers:
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
properties:
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
vdd-mic-bias-supply:
description: A reference to the 3.8V mic bias 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:
- reset-gpios
- qcom,tx-device
- qcom,rx-device
- qcom,micbias1-microvolt
- qcom,micbias2-microvolt
- qcom,micbias3-microvolt
- qcom,micbias4-microvolt
- "#sound-dai-cells"
additionalProperties: true

View File

@ -28,6 +28,10 @@ properties:
description: Powerdown/Shutdown line to use (pin SD_N)
maxItems: 1
reset-gpios:
description: Powerdown/Shutdown line to use (pin SD_N)
maxItems: 1
'#sound-dai-cells':
const: 0
@ -37,11 +41,16 @@ properties:
required:
- compatible
- reg
- powerdown-gpios
- '#sound-dai-cells'
- vdd-1p8-supply
- vdd-io-supply
oneOf:
- required:
- powerdown-gpios
- required:
- reset-gpios
unevaluatedProperties: false
examples:

View File

@ -0,0 +1,41 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/realtek,rt1015.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: RT1015 Mono Class D Audio Amplifier
maintainers:
- Jack Yu <jack.yu@realtek.com>
properties:
compatible:
enum:
- realtek,rt1015
reg:
maxItems: 1
realtek,power-up-delay-ms:
description: Set a delay time for flush work to be completed,
this vlaue is adjustable depending on platform.
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
codec@28 {
compatible = "realtek,rt1015";
reg = <0x28>;
realtek,power-up-delay-ms = <50>;
};
};

View File

@ -1,23 +0,0 @@
RT1015 Mono Class D Audio Amplifier
This device supports I2C only.
Required properties:
- compatible : "realtek,rt1015".
- reg : The I2C address of the device.
Optional properties:
- realtek,power-up-delay-ms
Set a delay time for flush work to be completed,
this value is adjustable depending on platform.
Example:
rt1015: codec@28 {
compatible = "realtek,rt1015";
reg = <0x28>;
realtek,power-up-delay-ms = <50>;
};

View File

@ -25,8 +25,11 @@ properties:
description: Phandles to the codecs.
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
- description: Phandle to the WM5110 audio codec.
- description: Phandle to the HDMI transmitter node.
- items:
- description: Phandle to the WM5110 audio codec.
- items:
- description: Phandle to the HDMI transmitter node.
samsung,audio-routing:
description: |

View File

@ -3864,14 +3864,16 @@ corresponding destructor.
And next, set suspend/resume callbacks to the pci_driver::
static SIMPLE_DEV_PM_OPS(snd_my_pm_ops, mychip_suspend, mychip_resume);
static DEFINE_SIMPLE_DEV_PM_OPS(snd_my_pm_ops, mychip_suspend, mychip_resume);
static struct pci_driver driver = {
.name = KBUILD_MODNAME,
.id_table = snd_my_ids,
.probe = snd_my_probe,
.remove = snd_my_remove,
.driver.pm = &snd_my_pm_ops,
.driver = {
.pm = &snd_my_pm_ops,
},
};
Module Parameters

View File

@ -5042,6 +5042,7 @@ F: include/linux/mfd/cs42l43*
F: include/sound/cs*
F: sound/pci/hda/cirrus*
F: sound/pci/hda/cs*
F: sound/pci/hda/hda_component*
F: sound/pci/hda/hda_cs_dsp_ctl.*
F: sound/soc/codecs/cs*
@ -20515,6 +20516,12 @@ F: include/uapi/sound/compress_*
F: sound/core/compress_offload.c
F: sound/soc/soc-compress.c
SOUND - CORE KUNIT TEST
M: Ivan Orlov <ivan.orlov0322@gmail.com>
L: linux-sound@vger.kernel.org
S: Supported
F: sound/core/sound_kunit.c
SOUND - DMAENGINE HELPERS
M: Lars-Peter Clausen <lars@metafoo.de>
S: Supported

View File

@ -1760,7 +1760,9 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
{"BSG1160", },
{"BSG2150", },
{"CSC3551", },
{"CSC3554", },
{"CSC3556", },
{"CSC3557", },
{"INT33FE", },
{"INT3515", },
/* Non-conforming _HID for Cirrus Logic already released */

View File

@ -522,7 +522,7 @@ void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp)
{
cs_dsp_debugfs_clear(dsp);
debugfs_remove_recursive(dsp->debugfs_root);
dsp->debugfs_root = NULL;
dsp->debugfs_root = ERR_PTR(-ENODEV);
}
EXPORT_SYMBOL_NS_GPL(cs_dsp_cleanup_debugfs, FW_CS_DSP);
#else
@ -2246,6 +2246,11 @@ static int cs_dsp_common_init(struct cs_dsp *dsp)
mutex_init(&dsp->pwr_lock);
#ifdef CONFIG_DEBUG_FS
/* Ensure this is invalid if client never provides a debugfs root */
dsp->debugfs_root = ERR_PTR(-ENODEV);
#endif
return 0;
}

View File

@ -329,6 +329,19 @@ static const struct smi_node cs35l41_hda = {
.bus_type = SMI_AUTO_DETECT,
};
static const struct smi_node cs35l54_hda = {
.instances = {
{ "cs35l54-hda", IRQ_RESOURCE_AUTO, 0 },
{ "cs35l54-hda", IRQ_RESOURCE_AUTO, 0 },
{ "cs35l54-hda", IRQ_RESOURCE_AUTO, 0 },
{ "cs35l54-hda", IRQ_RESOURCE_AUTO, 0 },
/* a 5th entry is an alias address, not a real device */
{ "cs35l54-hda_dummy_dev" },
{}
},
.bus_type = SMI_AUTO_DETECT,
};
static const struct smi_node cs35l56_hda = {
.instances = {
{ "cs35l56-hda", IRQ_RESOURCE_AUTO, 0 },
@ -342,6 +355,19 @@ static const struct smi_node cs35l56_hda = {
.bus_type = SMI_AUTO_DETECT,
};
static const struct smi_node cs35l57_hda = {
.instances = {
{ "cs35l57-hda", IRQ_RESOURCE_AUTO, 0 },
{ "cs35l57-hda", IRQ_RESOURCE_AUTO, 0 },
{ "cs35l57-hda", IRQ_RESOURCE_AUTO, 0 },
{ "cs35l57-hda", IRQ_RESOURCE_AUTO, 0 },
/* a 5th entry is an alias address, not a real device */
{ "cs35l57-hda_dummy_dev" },
{}
},
.bus_type = SMI_AUTO_DETECT,
};
/*
* Note new device-ids must also be added to ignore_serial_bus_ids in
* drivers/acpi/scan.c: acpi_device_enumeration_by_parent().
@ -350,7 +376,9 @@ static const struct acpi_device_id smi_acpi_ids[] = {
{ "BSG1160", (unsigned long)&bsg1160_data },
{ "BSG2150", (unsigned long)&bsg2150_data },
{ "CSC3551", (unsigned long)&cs35l41_hda },
{ "CSC3554", (unsigned long)&cs35l54_hda },
{ "CSC3556", (unsigned long)&cs35l56_hda },
{ "CSC3557", (unsigned long)&cs35l57_hda },
{ "INT3515", (unsigned long)&int3515_data },
/* Non-conforming _HID for Cirrus Logic already released */
{ "CLSA0100", (unsigned long)&cs35l41_hda },

View File

@ -20,7 +20,7 @@ soundwire-bus-y += irq.o
endif
#AMD driver
soundwire-amd-y := amd_manager.o
soundwire-amd-y := amd_init.o amd_manager.o
obj-$(CONFIG_SOUNDWIRE_AMD) += soundwire-amd.o
#Cadence Objs

View File

@ -0,0 +1,235 @@
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
/*
* SoundWire AMD Manager Initialize routines
*
* Initializes and creates SDW devices based on ACPI and Hardware values
*
* Copyright 2024 Advanced Micro Devices, Inc.
*/
#include <linux/acpi.h>
#include <linux/export.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include "amd_init.h"
#define ACP_PAD_PULLDOWN_CTRL 0x0001448
#define ACP_SW_PAD_KEEPER_EN 0x0001454
#define AMD_SDW_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7f9a
#define AMD_SDW0_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7f9f
#define AMD_SDW1_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7ffa
#define AMD_SDW0_PAD_EN_MASK 1
#define AMD_SDW1_PAD_EN_MASK 0x10
#define AMD_SDW_PAD_EN_MASK (AMD_SDW0_PAD_EN_MASK | AMD_SDW1_PAD_EN_MASK)
static int amd_enable_sdw_pads(void __iomem *mmio, u32 link_mask, struct device *dev)
{
u32 val;
u32 pad_keeper_en_mask, pad_pulldown_ctrl_mask;
switch (link_mask) {
case 1:
pad_keeper_en_mask = AMD_SDW0_PAD_EN_MASK;
pad_pulldown_ctrl_mask = AMD_SDW0_PAD_PULLDOWN_CTRL_ENABLE_MASK;
break;
case 2:
pad_keeper_en_mask = AMD_SDW1_PAD_EN_MASK;
pad_pulldown_ctrl_mask = AMD_SDW1_PAD_PULLDOWN_CTRL_ENABLE_MASK;
break;
case 3:
pad_keeper_en_mask = AMD_SDW_PAD_EN_MASK;
pad_pulldown_ctrl_mask = AMD_SDW_PAD_PULLDOWN_CTRL_ENABLE_MASK;
break;
default:
dev_err(dev, "No SDW Links are enabled\n");
return -ENODEV;
}
val = readl(mmio + ACP_SW_PAD_KEEPER_EN);
val |= pad_keeper_en_mask;
writel(val, mmio + ACP_SW_PAD_KEEPER_EN);
val = readl(mmio + ACP_PAD_PULLDOWN_CTRL);
val &= pad_pulldown_ctrl_mask;
writel(val, mmio + ACP_PAD_PULLDOWN_CTRL);
return 0;
}
static int sdw_amd_cleanup(struct sdw_amd_ctx *ctx)
{
int i;
for (i = 0; i < ctx->count; i++) {
if (!(ctx->link_mask & BIT(i)))
continue;
platform_device_unregister(ctx->pdev[i]);
}
return 0;
}
static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
{
struct sdw_amd_ctx *ctx;
struct acpi_device *adev;
struct resource *sdw_res;
struct acp_sdw_pdata sdw_pdata[2];
struct platform_device_info pdevinfo[2];
u32 link_mask;
int count, index;
int ret;
if (!res)
return NULL;
adev = acpi_fetch_acpi_dev(res->handle);
if (!adev)
return NULL;
if (!res->count)
return NULL;
count = res->count;
dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
ret = amd_enable_sdw_pads(res->mmio_base, res->link_mask, res->parent);
if (ret)
return NULL;
/*
* we need to alloc/free memory manually and can't use devm:
* this routine may be called from a workqueue, and not from
* the parent .probe.
* If devm_ was used, the memory might never be freed on errors.
*/
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return NULL;
ctx->count = count;
ctx->link_mask = res->link_mask;
sdw_res = kzalloc(sizeof(*sdw_res), GFP_KERNEL);
if (!sdw_res) {
kfree(ctx);
return NULL;
}
sdw_res->flags = IORESOURCE_MEM;
sdw_res->start = res->addr;
sdw_res->end = res->addr + res->reg_range;
memset(&pdevinfo, 0, sizeof(pdevinfo));
link_mask = ctx->link_mask;
for (index = 0; index < count; index++) {
if (!(link_mask & BIT(index)))
continue;
sdw_pdata[index].instance = index;
sdw_pdata[index].acp_sdw_lock = res->acp_lock;
pdevinfo[index].name = "amd_sdw_manager";
pdevinfo[index].id = index;
pdevinfo[index].parent = res->parent;
pdevinfo[index].num_res = 1;
pdevinfo[index].res = sdw_res;
pdevinfo[index].data = &sdw_pdata[index];
pdevinfo[index].size_data = sizeof(struct acp_sdw_pdata);
pdevinfo[index].fwnode = acpi_fwnode_handle(adev);
ctx->pdev[index] = platform_device_register_full(&pdevinfo[index]);
if (IS_ERR(ctx->pdev[index]))
goto err;
}
kfree(sdw_res);
return ctx;
err:
while (index--) {
if (!(link_mask & BIT(index)))
continue;
platform_device_unregister(ctx->pdev[index]);
}
kfree(sdw_res);
kfree(ctx);
return NULL;
}
static int sdw_amd_startup(struct sdw_amd_ctx *ctx)
{
struct amd_sdw_manager *amd_manager;
int i, ret;
/* Startup SDW Manager devices */
for (i = 0; i < ctx->count; i++) {
if (!(ctx->link_mask & BIT(i)))
continue;
amd_manager = dev_get_drvdata(&ctx->pdev[i]->dev);
ret = amd_sdw_manager_start(amd_manager);
if (ret)
return ret;
}
return 0;
}
int sdw_amd_probe(struct sdw_amd_res *res, struct sdw_amd_ctx **sdw_ctx)
{
*sdw_ctx = sdw_amd_probe_controller(res);
if (!*sdw_ctx)
return -ENODEV;
return sdw_amd_startup(*sdw_ctx);
}
EXPORT_SYMBOL_NS(sdw_amd_probe, SOUNDWIRE_AMD_INIT);
void sdw_amd_exit(struct sdw_amd_ctx *ctx)
{
sdw_amd_cleanup(ctx);
kfree(ctx->ids);
kfree(ctx);
}
EXPORT_SYMBOL_NS(sdw_amd_exit, SOUNDWIRE_AMD_INIT);
int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx)
{
struct amd_sdw_manager *amd_manager;
struct sdw_bus *bus;
struct sdw_slave *slave;
struct list_head *node;
int index;
int i = 0;
int num_slaves = 0;
for (index = 0; index < ctx->count; index++) {
if (!(ctx->link_mask & BIT(index)))
continue;
amd_manager = dev_get_drvdata(&ctx->pdev[index]->dev);
if (!amd_manager)
return -ENODEV;
bus = &amd_manager->bus;
/* Calculate number of slaves */
list_for_each(node, &bus->slaves)
num_slaves++;
}
ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL);
if (!ctx->ids)
return -ENOMEM;
ctx->num_slaves = num_slaves;
for (index = 0; index < ctx->count; index++) {
if (!(ctx->link_mask & BIT(index)))
continue;
amd_manager = dev_get_drvdata(&ctx->pdev[index]->dev);
if (amd_manager) {
bus = &amd_manager->bus;
list_for_each_entry(slave, &bus->slaves, node) {
ctx->ids[i].id = slave->id;
ctx->ids[i].link_id = bus->link_id;
i++;
}
}
}
return 0;
}
EXPORT_SYMBOL_NS(sdw_amd_get_slave_info, SOUNDWIRE_AMD_INIT);
MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
MODULE_DESCRIPTION("AMD SoundWire Init Library");
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -0,0 +1,13 @@
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
/*
* Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
*/
#ifndef __AMD_INIT_H
#define __AMD_INIT_H
#include <linux/soundwire/sdw_amd.h>
int amd_sdw_manager_start(struct amd_sdw_manager *amd_manager);
#endif

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0+
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
/*
* SoundWire AMD Manager driver
*
* Copyright 2023 Advanced Micro Devices, Inc.
* Copyright 2023-24 Advanced Micro Devices, Inc.
*/
#include <linux/completion.h>
@ -19,29 +19,13 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "bus.h"
#include "amd_init.h"
#include "amd_manager.h"
#define DRV_NAME "amd_sdw_manager"
#define to_amd_sdw(b) container_of(b, struct amd_sdw_manager, bus)
static void amd_enable_sdw_pads(struct amd_sdw_manager *amd_manager)
{
u32 sw_pad_pulldown_val;
u32 val;
mutex_lock(amd_manager->acp_sdw_lock);
val = readl(amd_manager->acp_mmio + ACP_SW_PAD_KEEPER_EN);
val |= amd_manager->reg_mask->sw_pad_enable_mask;
writel(val, amd_manager->acp_mmio + ACP_SW_PAD_KEEPER_EN);
usleep_range(1000, 1500);
sw_pad_pulldown_val = readl(amd_manager->acp_mmio + ACP_PAD_PULLDOWN_CTRL);
sw_pad_pulldown_val &= amd_manager->reg_mask->sw_pad_pulldown_mask;
writel(sw_pad_pulldown_val, amd_manager->acp_mmio + ACP_PAD_PULLDOWN_CTRL);
mutex_unlock(amd_manager->acp_sdw_lock);
}
static int amd_init_sdw_manager(struct amd_sdw_manager *amd_manager)
{
u32 val;
@ -102,12 +86,11 @@ static int amd_disable_sdw_manager(struct amd_sdw_manager *amd_manager)
static void amd_enable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
{
struct sdw_manager_reg_mask *reg_mask = amd_manager->reg_mask;
u32 val;
mutex_lock(amd_manager->acp_sdw_lock);
val = readl(amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance));
val |= reg_mask->acp_sdw_intr_mask;
val |= sdw_manager_reg_mask_array[amd_manager->instance];
writel(val, amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance));
mutex_unlock(amd_manager->acp_sdw_lock);
@ -120,12 +103,11 @@ static void amd_enable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
static void amd_disable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
{
struct sdw_manager_reg_mask *reg_mask = amd_manager->reg_mask;
u32 val;
mutex_lock(amd_manager->acp_sdw_lock);
val = readl(amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance));
val &= ~reg_mask->acp_sdw_intr_mask;
val &= ~sdw_manager_reg_mask_array[amd_manager->instance];
writel(val, amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance));
mutex_unlock(amd_manager->acp_sdw_lock);
@ -864,23 +846,20 @@ static void amd_sdw_irq_thread(struct work_struct *work)
writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_0TO7);
}
static void amd_sdw_probe_work(struct work_struct *work)
int amd_sdw_manager_start(struct amd_sdw_manager *amd_manager)
{
struct amd_sdw_manager *amd_manager = container_of(work, struct amd_sdw_manager,
probe_work);
struct sdw_master_prop *prop;
int ret;
prop = &amd_manager->bus.prop;
if (!prop->hw_disabled) {
amd_enable_sdw_pads(amd_manager);
ret = amd_init_sdw_manager(amd_manager);
if (ret)
return;
return ret;
amd_enable_sdw_interrupts(amd_manager);
ret = amd_enable_sdw_manager(amd_manager);
if (ret)
return;
return ret;
amd_sdw_set_frameshape(amd_manager);
}
/* Enable runtime PM */
@ -889,6 +868,7 @@ static void amd_sdw_probe_work(struct work_struct *work)
pm_runtime_mark_last_busy(amd_manager->dev);
pm_runtime_set_active(amd_manager->dev);
pm_runtime_enable(amd_manager->dev);
return 0;
}
static int amd_sdw_manager_probe(struct platform_device *pdev)
@ -948,7 +928,6 @@ static int amd_sdw_manager_probe(struct platform_device *pdev)
return -EINVAL;
}
amd_manager->reg_mask = &sdw_manager_reg_mask_array[amd_manager->instance];
params = &amd_manager->bus.params;
params->col = AMD_SDW_DEFAULT_COLUMNS;
@ -972,11 +951,6 @@ static int amd_sdw_manager_probe(struct platform_device *pdev)
dev_set_drvdata(dev, amd_manager);
INIT_WORK(&amd_manager->amd_sdw_irq_thread, amd_sdw_irq_thread);
INIT_WORK(&amd_manager->amd_sdw_work, amd_sdw_update_slave_status_work);
INIT_WORK(&amd_manager->probe_work, amd_sdw_probe_work);
/*
* Instead of having lengthy probe sequence, use deferred probe.
*/
schedule_work(&amd_manager->probe_work);
return 0;
}
@ -986,7 +960,6 @@ static void amd_sdw_manager_remove(struct platform_device *pdev)
int ret;
pm_runtime_disable(&pdev->dev);
cancel_work_sync(&amd_manager->probe_work);
amd_disable_sdw_interrupts(amd_manager);
sdw_bus_master_delete(&amd_manager->bus);
ret = amd_disable_sdw_manager(amd_manager);
@ -1215,5 +1188,5 @@ module_platform_driver(amd_sdw_driver);
MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
MODULE_DESCRIPTION("AMD SoundWire driver");
MODULE_LICENSE("GPL");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS("platform:" DRV_NAME);

View File

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
/*
* Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
* Copyright (C) 2023-24 Advanced Micro Devices, Inc. All rights reserved.
*/
#ifndef __AMD_MANAGER_H
@ -243,16 +243,8 @@ static struct sdw_manager_dp_reg sdw1_manager_dp_reg[AMD_SDW1_MAX_DAI] = {
ACP_SW_AUDIO1_RX_OFFSET, ACP_SW_AUDIO1_RX_CHANNEL_ENABLE_DP0}
};
static struct sdw_manager_reg_mask sdw_manager_reg_mask_array[2] = {
{
AMD_SDW0_PAD_KEEPER_EN_MASK,
AMD_SDW0_PAD_PULLDOWN_CTRL_ENABLE_MASK,
AMD_SDW0_EXT_INTR_MASK
},
{
AMD_SDW1_PAD_KEEPER_EN_MASK,
AMD_SDW1_PAD_PULLDOWN_CTRL_ENABLE_MASK,
static u32 sdw_manager_reg_mask_array[AMD_SDW_MAX_MANAGER_COUNT] = {
AMD_SDW0_EXT_INTR_MASK,
AMD_SDW1_EXT_INTR_MASK
}
};
#endif

View File

@ -130,6 +130,14 @@ static const struct dmi_system_id adr_remap_quirk_table[] = {
},
.driver_data = (void *)intel_rooks_county,
},
{
/* quirk used for NUC15 LAPRC710 skew */
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
DMI_MATCH(DMI_BOARD_NAME, "LAPRC710"),
},
.driver_data = (void *)intel_rooks_county,
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),

View File

@ -123,7 +123,6 @@ struct cs_dsp_client_ops;
* @sysclk_mask: Mask of frequency bits within sysclk register (ADSP1 only)
* @sysclk_shift: Shift of frequency bits within sysclk register (ADSP1 only)
* @alg_regions: List of currently loaded algorithm regions
* @fw_file_name: Filename of the current firmware
* @fw_name: Name of the current firmware
* @fw_id: ID of the current firmware, obtained from the wmfw
* @fw_id_version: Version of the firmware, obtained from the wmfw

View File

@ -1,11 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
/*
* Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
* Copyright (C) 2023-24 Advanced Micro Devices, Inc. All rights reserved.
*/
#ifndef __SDW_AMD_H
#define __SDW_AMD_H
#include <linux/acpi.h>
#include <linux/soundwire/sdw.h>
/* AMD pm_runtime quirk definitions */
@ -25,6 +26,7 @@
#define AMD_SDW_POWER_OFF_MODE 2
#define ACP_SDW0 0
#define ACP_SDW1 1
#define AMD_SDW_MAX_MANAGER_COUNT 2
struct acp_sdw_pdata {
u16 instance;
@ -32,12 +34,6 @@ struct acp_sdw_pdata {
struct mutex *acp_sdw_lock;
};
struct sdw_manager_reg_mask {
u32 sw_pad_enable_mask;
u32 sw_pad_pulldown_mask;
u32 acp_sdw_intr_mask;
};
/**
* struct sdw_amd_dai_runtime: AMD sdw dai runtime data
*
@ -59,10 +55,8 @@ struct sdw_amd_dai_runtime {
* @dev: linux device
* @mmio: SoundWire registers mmio base
* @acp_mmio: acp registers mmio base
* @reg_mask: register mask structure per manager instance
* @amd_sdw_irq_thread: SoundWire manager irq workqueue
* @amd_sdw_work: peripheral status work queue
* @probe_work: SoundWire manager probe workqueue
* @acp_sdw_lock: mutex to protect acp share register access
* @status: peripheral devices status array
* @num_din_ports: number of input ports
@ -83,10 +77,8 @@ struct amd_sdw_manager {
void __iomem *mmio;
void __iomem *acp_mmio;
struct sdw_manager_reg_mask *reg_mask;
struct work_struct amd_sdw_irq_thread;
struct work_struct amd_sdw_work;
struct work_struct probe_work;
/* mutex to protect acp common register access */
struct mutex *acp_sdw_lock;
@ -106,4 +98,71 @@ struct amd_sdw_manager {
struct sdw_amd_dai_runtime **dai_runtime_array;
};
/**
* struct sdw_amd_acpi_info - Soundwire AMD information found in ACPI tables
* @handle: ACPI controller handle
* @count: maximum no of soundwire manager links supported on AMD platform.
* @link_mask: bit-wise mask listing links enabled by BIOS menu
*/
struct sdw_amd_acpi_info {
acpi_handle handle;
int count;
u32 link_mask;
};
/**
* struct sdw_amd_ctx - context allocated by the controller driver probe
*
* @count: link count
* @num_slaves: total number of devices exposed across all enabled links
* @link_mask: bit-wise mask listing SoundWire links reported by the
* Controller
* @ids: array of slave_id, representing Slaves exposed across all enabled
* links
* @pdev: platform device structure
*/
struct sdw_amd_ctx {
int count;
int num_slaves;
u32 link_mask;
struct sdw_extended_slave_id *ids;
struct platform_device *pdev[AMD_SDW_MAX_MANAGER_COUNT];
};
/**
* struct sdw_amd_res - Soundwire AMD global resource structure,
* typically populated by the DSP driver/Legacy driver
*
* @addr: acp pci device resource start address
* @reg_range: ACP register range
* @link_mask: bit-wise mask listing links selected by the DSP driver/
* legacy driver
* @count: link count
* @mmio_base: mmio base of SoundWire registers
* @handle: ACPI parent handle
* @parent: parent device
* @dev: device implementing hwparams and free callbacks
* @acp_lock: mutex protecting acp common registers access
*/
struct sdw_amd_res {
u32 addr;
u32 reg_range;
u32 link_mask;
int count;
void __iomem *mmio_base;
acpi_handle handle;
struct device *parent;
struct device *dev;
/* use to protect acp common registers access */
struct mutex *acp_lock;
};
int sdw_amd_probe(struct sdw_amd_res *res, struct sdw_amd_ctx **ctx);
void sdw_amd_exit(struct sdw_amd_ctx *ctx);
int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx);
int amd_sdw_scan_controller(struct sdw_amd_acpi_info *info);
#endif

View File

@ -420,8 +420,6 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
* @bus_lock_spinlock: spinlock for SPI bus locking
* @bus_lock_mutex: mutex for exclusion of multiple callers
* @bus_lock_flag: indicates that the SPI bus is locked for exclusive use
* @multi_cs_cap: indicates that the SPI Controller can assert/de-assert
* more than one chip select at once.
* @setup: updates the device mode and clocking records used by a
* device's SPI controller; protocol code may call this. This
* must fail if an unrecognized or unsupported mode is requested.

View File

@ -65,6 +65,9 @@ int snd_ak4531_mixer(struct snd_card *card, struct snd_ak4531 *_ak4531,
#ifdef CONFIG_PM
void snd_ak4531_suspend(struct snd_ak4531 *ak4531);
void snd_ak4531_resume(struct snd_ak4531 *ak4531);
#else
static inline void snd_ak4531_suspend(struct snd_ak4531 *ak4531) {}
static inline void snd_ak4531_resume(struct snd_ak4531 *ak4531) {}
#endif
#endif /* __SOUND_AK4531_CODEC_H */

View File

@ -0,0 +1,66 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2024 Cirrus Logic, Inc. and
* Cirrus Logic International Semiconductor Ltd.
*/
#ifndef CS_AMP_LIB_H
#define CS_AMP_LIB_H
#include <linux/efi.h>
#include <linux/types.h>
struct cs_dsp;
struct cirrus_amp_cal_data {
u32 calTarget[2];
u32 calTime[2];
s8 calAmbient;
u8 calStatus;
u16 calR;
} __packed;
struct cirrus_amp_efi_data {
u32 size;
u32 count;
struct cirrus_amp_cal_data data[];
} __packed;
/**
* struct cirrus_amp_cal_controls - definition of firmware calibration controls
* @alg_id: ID of algorithm containing the controls.
* @mem_region: DSP memory region containing the controls.
* @ambient: Name of control for calAmbient value.
* @calr: Name of control for calR value.
* @status: Name of control for calStatus value.
* @checksum: Name of control for checksum value.
*/
struct cirrus_amp_cal_controls {
unsigned int alg_id;
int mem_region;
const char *ambient;
const char *calr;
const char *status;
const char *checksum;
};
int cs_amp_write_cal_coeffs(struct cs_dsp *dsp,
const struct cirrus_amp_cal_controls *controls,
const struct cirrus_amp_cal_data *data);
int cs_amp_get_efi_calibration_data(struct device *dev, u64 target_uid, int amp_index,
struct cirrus_amp_cal_data *out_data);
struct cs_amp_test_hooks {
efi_status_t (*get_efi_variable)(efi_char16_t *name,
efi_guid_t *guid,
unsigned long *size,
void *buf);
int (*write_cal_coeff)(struct cs_dsp *dsp,
const struct cirrus_amp_cal_controls *controls,
const char *ctl_name, u32 val);
};
extern const struct cs_amp_test_hooks * const cs_amp_test_hooks;
#endif /* CS_AMP_LIB_H */

View File

@ -12,6 +12,7 @@
#include <linux/firmware/cirrus/cs_dsp.h>
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
#include <sound/cs-amp-lib.h>
#define CS35L56_DEVID 0x0000000
#define CS35L56_REVID 0x0000004
@ -23,6 +24,9 @@
#define CS35L56_BLOCK_ENABLES2 0x000201C
#define CS35L56_REFCLK_INPUT 0x0002C04
#define CS35L56_GLOBAL_SAMPLE_RATE 0x0002C0C
#define CS35L56_OTP_MEM_53 0x00300D4
#define CS35L56_OTP_MEM_54 0x00300D8
#define CS35L56_OTP_MEM_55 0x00300DC
#define CS35L56_ASP1_ENABLES1 0x0004800
#define CS35L56_ASP1_CONTROL1 0x0004804
#define CS35L56_ASP1_CONTROL2 0x0004808
@ -257,11 +261,15 @@ struct cs35l56_base {
struct regmap *regmap;
int irq;
struct mutex irq_lock;
u8 type;
u8 rev;
bool init_done;
bool fw_patched;
bool secured;
bool can_hibernate;
bool cal_data_valid;
s8 cal_index;
struct cirrus_amp_cal_data cal_data;
struct gpio_desc *reset_gpio;
};
@ -269,6 +277,8 @@ extern struct regmap_config cs35l56_regmap_i2c;
extern struct regmap_config cs35l56_regmap_spi;
extern struct regmap_config cs35l56_regmap_sdw;
extern const struct cirrus_amp_cal_controls cs35l56_calibration_controls;
extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC];
extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC];
@ -286,6 +296,7 @@ int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base);
int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base);
int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire);
void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp);
int cs35l56_get_calibration(struct cs35l56_base *cs35l56_base);
int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base,
bool *fw_missing, unsigned int *fw_version);
int cs35l56_hw_init(struct cs35l56_base *cs35l56_base);

View File

@ -809,8 +809,7 @@
#define CS42L42_PLL_LOCK_TIMEOUT_US 1250
#define CS42L42_HP_ADC_EN_TIME_US 20000
#define CS42L42_PDN_DONE_POLL_US 1000
#define CS42L42_PDN_DONE_TIMEOUT_US 200000
#define CS42L42_PDN_DONE_TIME_MS 100
#define CS42L42_FILT_DISCHARGE_TIME_MS 46
#define CS42L42_PDN_DONE_TIMEOUT_US 235000
#define CS42L42_PDN_DONE_TIME_MS 65
#endif /* __CS42L42_H */

View File

@ -103,7 +103,7 @@ struct snd_emux {
int ports[SNDRV_EMUX_MAX_PORTS]; /* The ports for this device */
struct snd_emux_port *portptrs[SNDRV_EMUX_MAX_PORTS];
int used; /* use counter */
char *name; /* name of the device (internal) */
const char *name; /* name of the device (internal) */
struct snd_rawmidi **vmidi;
struct timer_list tlist; /* for pending note-offs */
int timer_active;

View File

@ -181,4 +181,4 @@ hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool enabl
{
return 0;
}
#endif /* CONFIG_SND_SOC_SOF_HDA */
#endif /* CONFIG_SND_SOC_SOF_HDA_MLINK */

View File

@ -131,6 +131,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094
#define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20
#define AZX_REG_VS_LTRP_GB_MASK GENMASK(6, 0)
/* PCI space */
#define AZX_PCIREG_TCSEL 0x44

View File

@ -659,6 +659,18 @@ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
flags = _snd_pcm_stream_lock_irqsave_nested(substream); \
} while (0)
/* definitions for guard(); use like guard(pcm_stream_lock) */
DEFINE_LOCK_GUARD_1(pcm_stream_lock, struct snd_pcm_substream,
snd_pcm_stream_lock(_T->lock),
snd_pcm_stream_unlock(_T->lock))
DEFINE_LOCK_GUARD_1(pcm_stream_lock_irq, struct snd_pcm_substream,
snd_pcm_stream_lock_irq(_T->lock),
snd_pcm_stream_unlock_irq(_T->lock))
DEFINE_LOCK_GUARD_1(pcm_stream_lock_irqsave, struct snd_pcm_substream,
snd_pcm_stream_lock_irqsave(_T->lock, _T->flags),
snd_pcm_stream_unlock_irqrestore(_T->lock, _T->flags),
unsigned long flags)
/**
* snd_pcm_group_for_each_entry - iterate over the linked substreams
* @s: the iterator

View File

@ -290,6 +290,9 @@ int snd_sbmixer_new(struct snd_sb *chip);
#ifdef CONFIG_PM
void snd_sbmixer_suspend(struct snd_sb *chip);
void snd_sbmixer_resume(struct snd_sb *chip);
#else
static inline void snd_sbmixer_suspend(struct snd_sb *chip) {}
static inline void snd_sbmixer_resume(struct snd_sb *chip) {}
#endif
/* sb8_init.c */

View File

@ -1401,8 +1401,8 @@ void snd_soc_remove_pcm_runtime(struct snd_soc_card *card,
void snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platforms,
struct snd_soc_dai_link_component *cpus);
struct of_phandle_args *snd_soc_copy_dai_args(struct device *dev,
struct of_phandle_args *args);
struct snd_soc_dai *snd_soc_get_dai_via_args(struct of_phandle_args *dai_args);
const struct of_phandle_args *args);
struct snd_soc_dai *snd_soc_get_dai_via_args(const struct of_phandle_args *dai_args);
struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv,
bool legacy_dai_naming);

View File

@ -26,4 +26,11 @@ struct sof_ipc_dai_acpdmic_params {
uint32_t pdm_ch;
} __packed;
/* ACP_SDW Configuration Request - SOF_IPC_DAI_AMD_SDW_CONFIG */
struct sof_ipc_dai_acp_sdw_params {
struct sof_ipc_hdr hdr;
u32 rate;
u32 channels;
} __packed;
#endif

View File

@ -89,6 +89,7 @@ enum sof_ipc_dai_type {
SOF_DAI_AMD_SP_VIRTUAL, /**< AMD ACP SP VIRTUAL */
SOF_DAI_AMD_HS_VIRTUAL, /**< AMD ACP HS VIRTUAL */
SOF_DAI_IMX_MICFIL, /** < i.MX MICFIL PDM */
SOF_DAI_AMD_SDW, /**< AMD ACP SDW */
};
/* general purpose DAI configuration */
@ -119,6 +120,7 @@ struct sof_ipc_dai_config {
struct sof_ipc_dai_acp_params acphs;
struct sof_ipc_dai_mtk_afe_params afe;
struct sof_ipc_dai_micfil_params micfil;
struct sof_ipc_dai_acp_sdw_params acp_sdw;
};
} __packed;

View File

@ -103,7 +103,6 @@ struct tasdevice_priv {
struct tm tm;
enum device_catlog_id catlog_id;
const char *acpi_subsystem_id;
unsigned char cal_binaryname[TASDEVICE_MAX_CHANNELS][64];
unsigned char crc8_lkp_tbl[CRC8_TABLE_SIZE];
unsigned char coef_binaryname[64];

View File

@ -17,71 +17,76 @@ struct snd_soc_card;
struct snd_soc_dapm_widget;
struct snd_soc_dapm_path;
DECLARE_EVENT_CLASS(snd_soc_card,
DECLARE_EVENT_CLASS(snd_soc_dapm,
TP_PROTO(struct snd_soc_card *card, int val),
TP_PROTO(struct snd_soc_dapm_context *dapm, int val),
TP_ARGS(card, val),
TP_ARGS(dapm, val),
TP_STRUCT__entry(
__string( name, card->name )
__field( int, val )
__string( card_name, dapm->card->name)
__string( comp_name, dapm->component ? dapm->component->name : "(none)")
__field( int, val)
),
TP_fast_assign(
__assign_str(name, card->name);
__assign_str(card_name, dapm->card->name);
__assign_str(comp_name, dapm->component ? dapm->component->name : "(none)");
__entry->val = val;
),
TP_printk("card=%s val=%d", __get_str(name), (int)__entry->val)
TP_printk("card=%s component=%s val=%d",
__get_str(card_name), __get_str(comp_name), (int)__entry->val)
);
DEFINE_EVENT(snd_soc_card, snd_soc_bias_level_start,
DEFINE_EVENT(snd_soc_dapm, snd_soc_bias_level_start,
TP_PROTO(struct snd_soc_card *card, int val),
TP_PROTO(struct snd_soc_dapm_context *dapm, int val),
TP_ARGS(card, val)
TP_ARGS(dapm, val)
);
DEFINE_EVENT(snd_soc_card, snd_soc_bias_level_done,
DEFINE_EVENT(snd_soc_dapm, snd_soc_bias_level_done,
TP_PROTO(struct snd_soc_card *card, int val),
TP_PROTO(struct snd_soc_dapm_context *dapm, int val),
TP_ARGS(card, val)
TP_ARGS(dapm, val)
);
DECLARE_EVENT_CLASS(snd_soc_dapm_basic,
TP_PROTO(struct snd_soc_card *card),
TP_PROTO(struct snd_soc_card *card, int event),
TP_ARGS(card),
TP_ARGS(card, event),
TP_STRUCT__entry(
__string( name, card->name )
__field( int, event )
),
TP_fast_assign(
__assign_str(name, card->name);
__entry->event = event;
),
TP_printk("card=%s", __get_str(name))
TP_printk("card=%s event=%d", __get_str(name), (int)__entry->event)
);
DEFINE_EVENT(snd_soc_dapm_basic, snd_soc_dapm_start,
TP_PROTO(struct snd_soc_card *card),
TP_PROTO(struct snd_soc_card *card, int event),
TP_ARGS(card)
TP_ARGS(card, event)
);
DEFINE_EVENT(snd_soc_dapm_basic, snd_soc_dapm_done,
TP_PROTO(struct snd_soc_card *card),
TP_PROTO(struct snd_soc_card *card, int event),
TP_ARGS(card)
TP_ARGS(card, event)
);

View File

@ -7,6 +7,14 @@
#include <linux/virtio_types.h>
/*******************************************************************************
* FEATURE BITS
*/
enum {
/* device supports control elements */
VIRTIO_SND_F_CTLS = 0
};
/*******************************************************************************
* CONFIGURATION SPACE
*/
@ -17,6 +25,8 @@ struct virtio_snd_config {
__le32 streams;
/* # of available channel maps */
__le32 chmaps;
/* # of available control elements */
__le32 controls;
};
enum {
@ -55,6 +65,15 @@ enum {
/* channel map control request types */
VIRTIO_SND_R_CHMAP_INFO = 0x0200,
/* control element request types */
VIRTIO_SND_R_CTL_INFO = 0x0300,
VIRTIO_SND_R_CTL_ENUM_ITEMS,
VIRTIO_SND_R_CTL_READ,
VIRTIO_SND_R_CTL_WRITE,
VIRTIO_SND_R_CTL_TLV_READ,
VIRTIO_SND_R_CTL_TLV_WRITE,
VIRTIO_SND_R_CTL_TLV_COMMAND,
/* jack event types */
VIRTIO_SND_EVT_JACK_CONNECTED = 0x1000,
VIRTIO_SND_EVT_JACK_DISCONNECTED,
@ -63,6 +82,9 @@ enum {
VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED = 0x1100,
VIRTIO_SND_EVT_PCM_XRUN,
/* control element event types */
VIRTIO_SND_EVT_CTL_NOTIFY = 0x1200,
/* common status codes */
VIRTIO_SND_S_OK = 0x8000,
VIRTIO_SND_S_BAD_MSG,
@ -331,4 +353,136 @@ struct virtio_snd_chmap_info {
__u8 positions[VIRTIO_SND_CHMAP_MAX_SIZE];
};
/*******************************************************************************
* CONTROL ELEMENTS MESSAGES
*/
struct virtio_snd_ctl_hdr {
/* VIRTIO_SND_R_CTL_XXX */
struct virtio_snd_hdr hdr;
/* 0 ... virtio_snd_config::controls - 1 */
__le32 control_id;
};
/* supported roles for control elements */
enum {
VIRTIO_SND_CTL_ROLE_UNDEFINED = 0,
VIRTIO_SND_CTL_ROLE_VOLUME,
VIRTIO_SND_CTL_ROLE_MUTE,
VIRTIO_SND_CTL_ROLE_GAIN
};
/* supported value types for control elements */
enum {
VIRTIO_SND_CTL_TYPE_BOOLEAN = 0,
VIRTIO_SND_CTL_TYPE_INTEGER,
VIRTIO_SND_CTL_TYPE_INTEGER64,
VIRTIO_SND_CTL_TYPE_ENUMERATED,
VIRTIO_SND_CTL_TYPE_BYTES,
VIRTIO_SND_CTL_TYPE_IEC958
};
/* supported access rights for control elements */
enum {
VIRTIO_SND_CTL_ACCESS_READ = 0,
VIRTIO_SND_CTL_ACCESS_WRITE,
VIRTIO_SND_CTL_ACCESS_VOLATILE,
VIRTIO_SND_CTL_ACCESS_INACTIVE,
VIRTIO_SND_CTL_ACCESS_TLV_READ,
VIRTIO_SND_CTL_ACCESS_TLV_WRITE,
VIRTIO_SND_CTL_ACCESS_TLV_COMMAND
};
struct virtio_snd_ctl_info {
/* common header */
struct virtio_snd_info hdr;
/* element role (VIRTIO_SND_CTL_ROLE_XXX) */
__le32 role;
/* element value type (VIRTIO_SND_CTL_TYPE_XXX) */
__le32 type;
/* element access right bit map (1 << VIRTIO_SND_CTL_ACCESS_XXX) */
__le32 access;
/* # of members in the element value */
__le32 count;
/* index for an element with a non-unique name */
__le32 index;
/* name identifier string for the element */
__u8 name[44];
/* additional information about the element's value */
union {
/* VIRTIO_SND_CTL_TYPE_INTEGER */
struct {
/* minimum supported value */
__le32 min;
/* maximum supported value */
__le32 max;
/* fixed step size for value (0 = variable size) */
__le32 step;
} integer;
/* VIRTIO_SND_CTL_TYPE_INTEGER64 */
struct {
/* minimum supported value */
__le64 min;
/* maximum supported value */
__le64 max;
/* fixed step size for value (0 = variable size) */
__le64 step;
} integer64;
/* VIRTIO_SND_CTL_TYPE_ENUMERATED */
struct {
/* # of options supported for value */
__le32 items;
} enumerated;
} value;
};
struct virtio_snd_ctl_enum_item {
/* option name */
__u8 item[64];
};
struct virtio_snd_ctl_iec958 {
/* AES/IEC958 channel status bits */
__u8 status[24];
/* AES/IEC958 subcode bits */
__u8 subcode[147];
/* nothing */
__u8 pad;
/* AES/IEC958 subframe bits */
__u8 dig_subframe[4];
};
struct virtio_snd_ctl_value {
union {
/* VIRTIO_SND_CTL_TYPE_BOOLEAN|INTEGER value */
__le32 integer[128];
/* VIRTIO_SND_CTL_TYPE_INTEGER64 value */
__le64 integer64[64];
/* VIRTIO_SND_CTL_TYPE_ENUMERATED value (option indexes) */
__le32 enumerated[128];
/* VIRTIO_SND_CTL_TYPE_BYTES value */
__u8 bytes[512];
/* VIRTIO_SND_CTL_TYPE_IEC958 value */
struct virtio_snd_ctl_iec958 iec958;
} value;
};
/* supported event reason types */
enum {
/* element's value has changed */
VIRTIO_SND_CTL_EVT_MASK_VALUE = 0,
/* element's information has changed */
VIRTIO_SND_CTL_EVT_MASK_INFO,
/* element's metadata has changed */
VIRTIO_SND_CTL_EVT_MASK_TLV
};
struct virtio_snd_ctl_event {
/* VIRTIO_SND_EVT_CTL_NOTIFY */
struct virtio_snd_hdr hdr;
/* 0 ... virtio_snd_config::controls - 1 */
__le16 control_id;
/* event reason bit map (1 << VIRTIO_SND_CTL_EVT_MASK_XXX) */
__le16 mask;
};
#endif /* VIRTIO_SND_IF_H */

View File

@ -19,6 +19,8 @@ enum avs_tplg_token {
AVS_TKN_MANIFEST_NUM_MODCFGS_EXT_U32 = 6,
AVS_TKN_MANIFEST_NUM_PPLCFGS_U32 = 7,
AVS_TKN_MANIFEST_NUM_BINDINGS_U32 = 8,
AVS_TKN_MANIFEST_NUM_CONDPATH_TMPLS_U32 = 9,
AVS_TKN_MANIFEST_NUM_INIT_CONFIGS_U32 = 10,
/* struct avs_tplg_library */
AVS_TKN_LIBRARY_ID_U32 = 101,
@ -109,6 +111,8 @@ enum avs_tplg_token {
AVS_TKN_MOD_PROC_DOMAIN_U8 = 1705,
AVS_TKN_MOD_MODCFG_EXT_ID_U32 = 1706,
AVS_TKN_MOD_KCONTROL_ID_U32 = 1707,
AVS_TKN_MOD_INIT_CONFIG_NUM_IDS_U32 = 1708,
AVS_TKN_MOD_INIT_CONFIG_ID_U32 = 1709,
/* struct avs_tplg_path_template */
AVS_TKN_PATH_TMPL_ID_U32 = 1801,
@ -125,6 +129,11 @@ enum avs_tplg_token {
/* struct avs_tplg_kcontrol */
AVS_TKN_KCONTROL_ID_U32 = 2301,
/* struct avs_tplg_init_config */
AVS_TKN_INIT_CONFIG_ID_U32 = 2401,
AVS_TKN_INIT_CONFIG_PARAM_U8 = 2402,
AVS_TKN_INIT_CONFIG_LENGTH_U32 = 2403,
};
#endif

View File

@ -218,4 +218,8 @@
#define SOF_TKN_IMX_MICFIL_RATE 2000
#define SOF_TKN_IMX_MICFIL_CH 2001
/* ACP SDW */
#define SOF_TKN_AMD_ACP_SDW_RATE 2100
#define SOF_TKN_AMD_ACP_SDW_CH 2101
#endif

View File

@ -1126,7 +1126,6 @@ static void aoa_fabric_layout_remove(struct soundbus_dev *sdev)
sdev->pcmname = NULL;
}
#ifdef CONFIG_PM_SLEEP
static int aoa_fabric_layout_suspend(struct device *dev)
{
struct layout_dev *ldev = dev_get_drvdata(dev);
@ -1147,11 +1146,9 @@ static int aoa_fabric_layout_resume(struct device *dev)
return 0;
}
static SIMPLE_DEV_PM_OPS(aoa_fabric_layout_pm_ops,
static DEFINE_SIMPLE_DEV_PM_OPS(aoa_fabric_layout_pm_ops,
aoa_fabric_layout_suspend, aoa_fabric_layout_resume);
#endif
static struct soundbus_driver aoa_soundbus_driver = {
.name = "snd_aoa_soundbus_drv",
.owner = THIS_MODULE,
@ -1159,9 +1156,7 @@ static struct soundbus_driver aoa_soundbus_driver = {
.remove = aoa_fabric_layout_remove,
.driver = {
.owner = THIS_MODULE,
#ifdef CONFIG_PM_SLEEP
.pm = &aoa_fabric_layout_pm_ops,
#endif
}
};

View File

@ -127,7 +127,7 @@ static void soundbus_device_shutdown(struct device *dev)
/* soundbus_dev_attrs is declared in sysfs.c */
ATTRIBUTE_GROUPS(soundbus_dev);
static struct bus_type soundbus_bus_type = {
static const struct bus_type soundbus_bus_type = {
.name = "aoa-soundbus",
.probe = soundbus_probe,
.uevent = soundbus_uevent,

View File

@ -737,10 +737,8 @@ static const struct snd_pcm_ops aaci_capture_ops = {
/*
* Power Management.
*/
#ifdef CONFIG_PM
static int aaci_do_suspend(struct snd_card *card)
{
struct aaci *aaci = card->private_data;
snd_power_change_state(card, SNDRV_CTL_POWER_D3cold);
return 0;
}
@ -763,12 +761,7 @@ static int aaci_resume(struct device *dev)
return card ? aaci_do_resume(card) : 0;
}
static SIMPLE_DEV_PM_OPS(aaci_dev_pm_ops, aaci_suspend, aaci_resume);
#define AACI_DEV_PM_OPS (&aaci_dev_pm_ops)
#else
#define AACI_DEV_PM_OPS NULL
#endif
static DEFINE_SIMPLE_DEV_PM_OPS(aaci_dev_pm_ops, aaci_suspend, aaci_resume);
static const struct ac97_pcm ac97_defs[] = {
[0] = { /* Front PCM */
@ -1081,7 +1074,7 @@ MODULE_DEVICE_TABLE(amba, aaci_ids);
static struct amba_driver aaci_driver = {
.drv = {
.name = DRIVER_NAME,
.pm = AACI_DEV_PM_OPS,
.pm = &aaci_dev_pm_ops,
},
.probe = aaci_probe,
.remove = aaci_remove,

View File

@ -111,8 +111,6 @@ static int pxa2xx_ac97_pcm_prepare(struct snd_pcm_substream *substream)
return snd_ac97_set_rate(pxa2xx_ac97_ac97, reg, runtime->rate);
}
#ifdef CONFIG_PM_SLEEP
static int pxa2xx_ac97_do_suspend(struct snd_card *card)
{
pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
@ -164,8 +162,7 @@ static int pxa2xx_ac97_resume(struct device *dev)
return ret;
}
static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_suspend, pxa2xx_ac97_resume);
#endif
static DEFINE_SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_suspend, pxa2xx_ac97_resume);
static const struct snd_pcm_ops pxa2xx_ac97_pcm_ops = {
.open = pxa2xx_ac97_pcm_open,
@ -277,9 +274,7 @@ static struct platform_driver pxa2xx_ac97_driver = {
.remove_new = pxa2xx_ac97_remove,
.driver = {
.name = "pxa2xx-ac97",
#ifdef CONFIG_PM_SLEEP
.pm = &pxa2xx_ac97_pm_ops,
#endif
},
};

View File

@ -39,6 +39,23 @@ config SND_UMP_LEGACY_RAWMIDI
legacy MIDI 1.0 byte streams is created for each UMP Endpoint.
The device contains 16 substreams corresponding to UMP groups.
config SND_CORE_TEST
tristate "Sound core KUnit test"
depends on KUNIT
select SND_PCM
default KUNIT_ALL_TESTS
help
This options enables the sound core functions KUnit test.
KUnit tests run during boot and output the results to the debug
log in TAP format (https://testanything.org/). Only useful for
kernel devs running KUnit test harness and are not for inclusion
into a production build.
For more information on KUnit and unit tests in general, refer
to the KUnit documentation in Documentation/dev-tools/kunit/.
config SND_COMPRESS_OFFLOAD
tristate

View File

@ -48,6 +48,8 @@ obj-$(CONFIG_SND_SEQ_DEVICE) += snd-seq-device.o
obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o
obj-$(CONFIG_SND_UMP) += snd-ump.o
obj-$(CONFIG_SND_CORE_TEST) += sound_kunit.o
obj-$(CONFIG_SND_OSSEMUL) += oss/
obj-$(CONFIG_SND_SEQUENCER) += seq/

View File

@ -127,9 +127,8 @@ static int snd_compr_open(struct inode *inode, struct file *f)
init_waitqueue_head(&runtime->sleep);
data->stream.runtime = runtime;
f->private_data = (void *)data;
mutex_lock(&compr->lock);
ret = compr->ops->open(&data->stream);
mutex_unlock(&compr->lock);
scoped_guard(mutex, &compr->lock)
ret = compr->ops->open(&data->stream);
if (ret) {
kfree(runtime);
kfree(data);
@ -288,7 +287,7 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf,
return -EFAULT;
stream = &data->stream;
mutex_lock(&stream->device->lock);
guard(mutex)(&stream->device->lock);
/* write is allowed when stream is running or has been steup */
switch (stream->runtime->state) {
case SNDRV_PCM_STATE_SETUP:
@ -296,7 +295,6 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf,
case SNDRV_PCM_STATE_RUNNING:
break;
default:
mutex_unlock(&stream->device->lock);
return -EBADFD;
}
@ -322,7 +320,6 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf,
pr_debug("stream prepared, Houston we are good to go\n");
}
mutex_unlock(&stream->device->lock);
return retval;
}
@ -339,7 +336,7 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf,
return -EFAULT;
stream = &data->stream;
mutex_lock(&stream->device->lock);
guard(mutex)(&stream->device->lock);
/* read is allowed when stream is running, paused, draining and setup
* (yes setup is state which we transition to after stop, so if user
@ -350,11 +347,9 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf,
case SNDRV_PCM_STATE_PREPARED:
case SNDRV_PCM_STATE_SUSPENDED:
case SNDRV_PCM_STATE_DISCONNECTED:
retval = -EBADFD;
goto out;
return -EBADFD;
case SNDRV_PCM_STATE_XRUN:
retval = -EPIPE;
goto out;
return -EPIPE;
}
avail = snd_compr_get_avail(stream);
@ -363,17 +358,13 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf,
if (avail > count)
avail = count;
if (stream->ops->copy) {
if (stream->ops->copy)
retval = stream->ops->copy(stream, buf, avail);
} else {
retval = -ENXIO;
goto out;
}
else
return -ENXIO;
if (retval > 0)
stream->runtime->total_bytes_transferred += retval;
out:
mutex_unlock(&stream->device->lock);
return retval;
}
@ -402,13 +393,12 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait)
stream = &data->stream;
mutex_lock(&stream->device->lock);
guard(mutex)(&stream->device->lock);
switch (stream->runtime->state) {
case SNDRV_PCM_STATE_OPEN:
case SNDRV_PCM_STATE_XRUN:
retval = snd_compr_get_poll(stream) | EPOLLERR;
goto out;
return snd_compr_get_poll(stream) | EPOLLERR;
default:
break;
}
@ -433,11 +423,9 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait)
retval = snd_compr_get_poll(stream);
break;
default:
retval = snd_compr_get_poll(stream) | EPOLLERR;
break;
return snd_compr_get_poll(stream) | EPOLLERR;
}
out:
mutex_unlock(&stream->device->lock);
return retval;
}
@ -465,7 +453,7 @@ static int
snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
{
int retval;
struct snd_compr_codec_caps *caps;
struct snd_compr_codec_caps *caps __free(kfree) = NULL;
if (!stream->ops->get_codec_caps)
return -ENXIO;
@ -476,12 +464,9 @@ snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
retval = stream->ops->get_codec_caps(stream, caps);
if (retval)
goto out;
return retval;
if (copy_to_user((void __user *)arg, caps, sizeof(*caps)))
retval = -EFAULT;
out:
kfree(caps);
return -EFAULT;
return retval;
}
#endif /* !COMPR_CODEC_CAPS_OVERFLOW */
@ -586,7 +571,7 @@ static int snd_compress_check_input(struct snd_compr_params *params)
static int
snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
{
struct snd_compr_params *params;
struct snd_compr_params *params __free(kfree) = NULL;
int retval;
if (stream->runtime->state == SNDRV_PCM_STATE_OPEN || stream->next_track) {
@ -596,24 +581,22 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
*/
params = memdup_user((void __user *)arg, sizeof(*params));
if (IS_ERR(params))
return PTR_ERR(params);
return PTR_ERR(no_free_ptr(params));
retval = snd_compress_check_input(params);
if (retval)
goto out;
return retval;
retval = snd_compr_allocate_buffer(stream, params);
if (retval) {
retval = -ENOMEM;
goto out;
}
if (retval)
return -ENOMEM;
retval = stream->ops->set_params(stream, params);
if (retval)
goto out;
return retval;
if (stream->next_track)
goto out;
return retval;
stream->metadata_set = false;
stream->next_track = false;
@ -622,15 +605,13 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
} else {
return -EPERM;
}
out:
kfree(params);
return retval;
}
static int
snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg)
{
struct snd_codec *params;
struct snd_codec *params __free(kfree) = NULL;
int retval;
if (!stream->ops->get_params)
@ -641,12 +622,9 @@ snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg)
return -ENOMEM;
retval = stream->ops->get_params(stream, params);
if (retval)
goto out;
return retval;
if (copy_to_user((char __user *)arg, params, sizeof(*params)))
retval = -EFAULT;
out:
kfree(params);
return -EFAULT;
return retval;
}
@ -805,12 +783,10 @@ static void error_delayed_work(struct work_struct *work)
stream = container_of(work, struct snd_compr_stream, error_work.work);
mutex_lock(&stream->device->lock);
guard(mutex)(&stream->device->lock);
stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
wake_up(&stream->runtime->sleep);
mutex_unlock(&stream->device->lock);
}
/**
@ -967,70 +943,52 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{
struct snd_compr_file *data = f->private_data;
struct snd_compr_stream *stream;
int retval = -ENOTTY;
if (snd_BUG_ON(!data))
return -EFAULT;
stream = &data->stream;
mutex_lock(&stream->device->lock);
guard(mutex)(&stream->device->lock);
switch (_IOC_NR(cmd)) {
case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION):
retval = put_user(SNDRV_COMPRESS_VERSION,
return put_user(SNDRV_COMPRESS_VERSION,
(int __user *)arg) ? -EFAULT : 0;
break;
case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):
retval = snd_compr_get_caps(stream, arg);
break;
return snd_compr_get_caps(stream, arg);
#ifndef COMPR_CODEC_CAPS_OVERFLOW
case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS):
retval = snd_compr_get_codec_caps(stream, arg);
break;
return snd_compr_get_codec_caps(stream, arg);
#endif
case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS):
retval = snd_compr_set_params(stream, arg);
break;
return snd_compr_set_params(stream, arg);
case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS):
retval = snd_compr_get_params(stream, arg);
break;
return snd_compr_get_params(stream, arg);
case _IOC_NR(SNDRV_COMPRESS_SET_METADATA):
retval = snd_compr_set_metadata(stream, arg);
break;
return snd_compr_set_metadata(stream, arg);
case _IOC_NR(SNDRV_COMPRESS_GET_METADATA):
retval = snd_compr_get_metadata(stream, arg);
break;
return snd_compr_get_metadata(stream, arg);
case _IOC_NR(SNDRV_COMPRESS_TSTAMP):
retval = snd_compr_tstamp(stream, arg);
break;
return snd_compr_tstamp(stream, arg);
case _IOC_NR(SNDRV_COMPRESS_AVAIL):
retval = snd_compr_ioctl_avail(stream, arg);
break;
return snd_compr_ioctl_avail(stream, arg);
case _IOC_NR(SNDRV_COMPRESS_PAUSE):
retval = snd_compr_pause(stream);
break;
return snd_compr_pause(stream);
case _IOC_NR(SNDRV_COMPRESS_RESUME):
retval = snd_compr_resume(stream);
break;
return snd_compr_resume(stream);
case _IOC_NR(SNDRV_COMPRESS_START):
retval = snd_compr_start(stream);
break;
return snd_compr_start(stream);
case _IOC_NR(SNDRV_COMPRESS_STOP):
retval = snd_compr_stop(stream);
break;
return snd_compr_stop(stream);
case _IOC_NR(SNDRV_COMPRESS_DRAIN):
retval = snd_compr_drain(stream);
break;
return snd_compr_drain(stream);
case _IOC_NR(SNDRV_COMPRESS_PARTIAL_DRAIN):
retval = snd_compr_partial_drain(stream);
break;
return snd_compr_partial_drain(stream);
case _IOC_NR(SNDRV_COMPRESS_NEXT_TRACK):
retval = snd_compr_next_track(stream);
break;
return snd_compr_next_track(stream);
}
mutex_unlock(&stream->device->lock);
return retval;
return -ENOTTY;
}
/* support of 32bit userspace on 64bit platforms */

View File

@ -44,7 +44,6 @@ static int snd_ctl_remove_locked(struct snd_card *card,
static int snd_ctl_open(struct inode *inode, struct file *file)
{
unsigned long flags;
struct snd_card *card;
struct snd_ctl_file *ctl;
int i, err;
@ -80,9 +79,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
ctl->preferred_subdevice[i] = -1;
ctl->pid = get_pid(task_pid(current));
file->private_data = ctl;
write_lock_irqsave(&card->ctl_files_rwlock, flags);
list_add_tail(&ctl->list, &card->ctl_files);
write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
scoped_guard(write_lock_irqsave, &card->ctl_files_rwlock)
list_add_tail(&ctl->list, &card->ctl_files);
snd_card_unref(card);
return 0;
@ -98,21 +96,18 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl)
{
unsigned long flags;
struct snd_kctl_event *cread;
spin_lock_irqsave(&ctl->read_lock, flags);
guard(spinlock_irqsave)(&ctl->read_lock);
while (!list_empty(&ctl->events)) {
cread = snd_kctl_event(ctl->events.next);
list_del(&cread->list);
kfree(cread);
}
spin_unlock_irqrestore(&ctl->read_lock, flags);
}
static int snd_ctl_release(struct inode *inode, struct file *file)
{
unsigned long flags;
struct snd_card *card;
struct snd_ctl_file *ctl;
struct snd_kcontrol *control;
@ -121,15 +116,17 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
ctl = file->private_data;
file->private_data = NULL;
card = ctl->card;
write_lock_irqsave(&card->ctl_files_rwlock, flags);
list_del(&ctl->list);
write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
down_write(&card->controls_rwsem);
list_for_each_entry(control, &card->controls, list)
for (idx = 0; idx < control->count; idx++)
if (control->vd[idx].owner == ctl)
control->vd[idx].owner = NULL;
up_write(&card->controls_rwsem);
scoped_guard(write_lock_irqsave, &card->ctl_files_rwlock)
list_del(&ctl->list);
scoped_guard(rwsem_write, &card->controls_rwsem) {
list_for_each_entry(control, &card->controls, list)
for (idx = 0; idx < control->count; idx++)
if (control->vd[idx].owner == ctl)
control->vd[idx].owner = NULL;
}
snd_fasync_free(ctl->fasync);
snd_ctl_empty_read_queue(ctl);
put_pid(ctl->pid);
@ -152,7 +149,6 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
void snd_ctl_notify(struct snd_card *card, unsigned int mask,
struct snd_ctl_elem_id *id)
{
unsigned long flags;
struct snd_ctl_file *ctl;
struct snd_kctl_event *ev;
@ -160,34 +156,34 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
return;
if (card->shutdown)
return;
read_lock_irqsave(&card->ctl_files_rwlock, flags);
guard(read_lock_irqsave)(&card->ctl_files_rwlock);
#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
card->mixer_oss_change_count++;
#endif
list_for_each_entry(ctl, &card->ctl_files, list) {
if (!ctl->subscribed)
continue;
spin_lock(&ctl->read_lock);
list_for_each_entry(ev, &ctl->events, list) {
if (ev->id.numid == id->numid) {
ev->mask |= mask;
goto _found;
scoped_guard(spinlock, &ctl->read_lock) {
list_for_each_entry(ev, &ctl->events, list) {
if (ev->id.numid == id->numid) {
ev->mask |= mask;
goto _found;
}
}
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (ev) {
ev->id = *id;
ev->mask = mask;
list_add_tail(&ev->list, &ctl->events);
} else {
dev_err(card->dev, "No memory available to allocate event\n");
}
_found:
wake_up(&ctl->change_sleep);
}
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (ev) {
ev->id = *id;
ev->mask = mask;
list_add_tail(&ev->list, &ctl->events);
} else {
dev_err(card->dev, "No memory available to allocate event\n");
}
_found:
wake_up(&ctl->change_sleep);
spin_unlock(&ctl->read_lock);
snd_kill_fasync(ctl->fasync, SIGIO, POLL_IN);
}
read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
}
EXPORT_SYMBOL(snd_ctl_notify);
@ -210,10 +206,9 @@ void snd_ctl_notify_one(struct snd_card *card, unsigned int mask,
id.index += ioff;
id.numid += ioff;
snd_ctl_notify(card, mask, &id);
down_read(&snd_ctl_layer_rwsem);
guard(rwsem_read)(&snd_ctl_layer_rwsem);
for (lops = snd_ctl_layer; lops; lops = lops->next)
lops->lnotify(card, mask, kctl, ioff);
up_read(&snd_ctl_layer_rwsem);
}
EXPORT_SYMBOL(snd_ctl_notify_one);
@ -520,9 +515,9 @@ static int snd_ctl_add_replace(struct snd_card *card,
if (snd_BUG_ON(!card || !kcontrol->info))
goto error;
down_write(&card->controls_rwsem);
err = __snd_ctl_add_replace(card, kcontrol, mode);
up_write(&card->controls_rwsem);
scoped_guard(rwsem_write, &card->controls_rwsem)
err = __snd_ctl_add_replace(card, kcontrol, mode);
if (err < 0)
goto error;
return 0;
@ -616,12 +611,8 @@ static inline int snd_ctl_remove_locked(struct snd_card *card,
*/
int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
{
int ret;
down_write(&card->controls_rwsem);
ret = snd_ctl_remove_locked(card, kcontrol);
up_write(&card->controls_rwsem);
return ret;
guard(rwsem_write)(&card->controls_rwsem);
return snd_ctl_remove_locked(card, kcontrol);
}
EXPORT_SYMBOL(snd_ctl_remove);
@ -638,17 +629,12 @@ EXPORT_SYMBOL(snd_ctl_remove);
int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id)
{
struct snd_kcontrol *kctl;
int ret;
down_write(&card->controls_rwsem);
guard(rwsem_write)(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, id);
if (kctl == NULL) {
up_write(&card->controls_rwsem);
if (kctl == NULL)
return -ENOENT;
}
ret = snd_ctl_remove_locked(card, kctl);
up_write(&card->controls_rwsem);
return ret;
return snd_ctl_remove_locked(card, kctl);
}
EXPORT_SYMBOL(snd_ctl_remove_id);
@ -667,27 +653,18 @@ static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file,
{
struct snd_card *card = file->card;
struct snd_kcontrol *kctl;
int idx, ret;
int idx;
down_write(&card->controls_rwsem);
guard(rwsem_write)(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, id);
if (kctl == NULL) {
ret = -ENOENT;
goto error;
}
if (!(kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_USER)) {
ret = -EINVAL;
goto error;
}
if (kctl == NULL)
return -ENOENT;
if (!(kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_USER))
return -EINVAL;
for (idx = 0; idx < kctl->count; idx++)
if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file) {
ret = -EBUSY;
goto error;
}
ret = snd_ctl_remove_locked(card, kctl);
error:
up_write(&card->controls_rwsem);
return ret;
if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file)
return -EBUSY;
return snd_ctl_remove_locked(card, kctl);
}
/**
@ -764,18 +741,15 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
struct snd_kcontrol *kctl;
int saved_numid;
down_write(&card->controls_rwsem);
guard(rwsem_write)(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, src_id);
if (kctl == NULL) {
up_write(&card->controls_rwsem);
if (kctl == NULL)
return -ENOENT;
}
saved_numid = kctl->id.numid;
remove_hash_entries(card, kctl);
kctl->id = *dst_id;
kctl->id.numid = saved_numid;
add_hash_entries(card, kctl);
up_write(&card->controls_rwsem);
return 0;
}
EXPORT_SYMBOL(snd_ctl_rename_id);
@ -793,7 +767,7 @@ EXPORT_SYMBOL(snd_ctl_rename_id);
void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl,
const char *name)
{
down_write(&card->controls_rwsem);
guard(rwsem_write)(&card->controls_rwsem);
remove_hash_entries(card, kctl);
if (strscpy(kctl->id.name, name, sizeof(kctl->id.name)) < 0)
@ -801,7 +775,6 @@ void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl,
name, kctl->id.name);
add_hash_entries(card, kctl);
up_write(&card->controls_rwsem);
}
EXPORT_SYMBOL(snd_ctl_rename);
@ -859,12 +832,8 @@ EXPORT_SYMBOL(snd_ctl_find_numid_locked);
struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card,
unsigned int numid)
{
struct snd_kcontrol *kctl;
down_read(&card->controls_rwsem);
kctl = snd_ctl_find_numid_locked(card, numid);
up_read(&card->controls_rwsem);
return kctl;
guard(rwsem_read)(&card->controls_rwsem);
return snd_ctl_find_numid_locked(card, numid);
}
EXPORT_SYMBOL(snd_ctl_find_numid);
@ -920,37 +889,30 @@ EXPORT_SYMBOL(snd_ctl_find_id_locked);
struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
const struct snd_ctl_elem_id *id)
{
struct snd_kcontrol *kctl;
down_read(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, id);
up_read(&card->controls_rwsem);
return kctl;
guard(rwsem_read)(&card->controls_rwsem);
return snd_ctl_find_id_locked(card, id);
}
EXPORT_SYMBOL(snd_ctl_find_id);
static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
unsigned int cmd, void __user *arg)
{
struct snd_ctl_card_info *info;
struct snd_ctl_card_info *info __free(kfree) = NULL;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (! info)
return -ENOMEM;
down_read(&snd_ioctl_rwsem);
info->card = card->number;
strscpy(info->id, card->id, sizeof(info->id));
strscpy(info->driver, card->driver, sizeof(info->driver));
strscpy(info->name, card->shortname, sizeof(info->name));
strscpy(info->longname, card->longname, sizeof(info->longname));
strscpy(info->mixername, card->mixername, sizeof(info->mixername));
strscpy(info->components, card->components, sizeof(info->components));
up_read(&snd_ioctl_rwsem);
if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info))) {
kfree(info);
return -EFAULT;
scoped_guard(rwsem_read, &snd_ioctl_rwsem) {
info->card = card->number;
strscpy(info->id, card->id, sizeof(info->id));
strscpy(info->driver, card->driver, sizeof(info->driver));
strscpy(info->name, card->shortname, sizeof(info->name));
strscpy(info->longname, card->longname, sizeof(info->longname));
strscpy(info->mixername, card->mixername, sizeof(info->mixername));
strscpy(info->components, card->components, sizeof(info->components));
}
kfree(info);
if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info)))
return -EFAULT;
return 0;
}
@ -960,37 +922,31 @@ static int snd_ctl_elem_list(struct snd_card *card,
struct snd_kcontrol *kctl;
struct snd_ctl_elem_id id;
unsigned int offset, space, jidx;
int err = 0;
offset = list->offset;
space = list->space;
down_read(&card->controls_rwsem);
guard(rwsem_read)(&card->controls_rwsem);
list->count = card->controls_count;
list->used = 0;
if (space > 0) {
list_for_each_entry(kctl, &card->controls, list) {
if (offset >= kctl->count) {
offset -= kctl->count;
continue;
}
for (jidx = offset; jidx < kctl->count; jidx++) {
snd_ctl_build_ioff(&id, kctl, jidx);
if (copy_to_user(list->pids + list->used, &id,
sizeof(id))) {
err = -EFAULT;
goto out;
}
list->used++;
if (!--space)
goto out;
}
offset = 0;
if (!space)
return 0;
list_for_each_entry(kctl, &card->controls, list) {
if (offset >= kctl->count) {
offset -= kctl->count;
continue;
}
for (jidx = offset; jidx < kctl->count; jidx++) {
snd_ctl_build_ioff(&id, kctl, jidx);
if (copy_to_user(list->pids + list->used, &id, sizeof(id)))
return -EFAULT;
list->used++;
if (!--space)
return 0;
}
offset = 0;
}
out:
up_read(&card->controls_rwsem);
return err;
return 0;
}
static int snd_ctl_elem_list_user(struct snd_card *card,
@ -1238,16 +1194,12 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
{
struct snd_card *card = ctl->card;
struct snd_kcontrol *kctl;
int result;
down_read(&card->controls_rwsem);
guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, &info->id);
if (kctl == NULL)
result = -ENOENT;
else
result = __snd_ctl_elem_info(card, kctl, info, ctl);
up_read(&card->controls_rwsem);
return result;
if (!kctl)
return -ENOENT;
return __snd_ctl_elem_info(card, kctl, info, ctl);
}
static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
@ -1279,19 +1231,15 @@ static int snd_ctl_elem_read(struct snd_card *card,
const u32 pattern = 0xdeadbeef;
int ret;
down_read(&card->controls_rwsem);
guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, &control->id);
if (kctl == NULL) {
ret = -ENOENT;
goto unlock;
}
if (!kctl)
return -ENOENT;
index_offset = snd_ctl_get_ioff(kctl, &control->id);
vd = &kctl->vd[index_offset];
if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL) {
ret = -EPERM;
goto unlock;
}
if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || !kctl->get)
return -EPERM;
snd_ctl_build_ioff(&control->id, kctl, index_offset);
@ -1301,7 +1249,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
info.id = control->id;
ret = __snd_ctl_elem_info(card, kctl, &info, NULL);
if (ret < 0)
goto unlock;
return ret;
#endif
if (!snd_ctl_skip_validation(&info))
@ -1311,7 +1259,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
ret = kctl->get(kctl, control);
snd_power_unref(card);
if (ret < 0)
goto unlock;
return ret;
if (!snd_ctl_skip_validation(&info) &&
sanity_check_elem_value(card, control, &info, pattern) < 0) {
dev_err(card->dev,
@ -1319,12 +1267,9 @@ static int snd_ctl_elem_read(struct snd_card *card,
control->id.iface, control->id.device,
control->id.subdevice, control->id.name,
control->id.index);
ret = -EINVAL;
goto unlock;
return -EINVAL;
}
unlock:
up_read(&card->controls_rwsem);
return ret;
return 0;
}
static int snd_ctl_elem_read_user(struct snd_card *card,
@ -1339,12 +1284,10 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
result = snd_ctl_elem_read(card, control);
if (result < 0)
goto error;
return result;
if (copy_to_user(_control, control, sizeof(*control)))
result = -EFAULT;
error:
kfree(control);
return -EFAULT;
return result;
}
@ -1406,23 +1349,21 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
struct snd_ctl_elem_value __user *_control)
{
struct snd_ctl_elem_value *control;
struct snd_ctl_elem_value *control __free(kfree) = NULL;
struct snd_card *card;
int result;
control = memdup_user(_control, sizeof(*control));
if (IS_ERR(control))
return PTR_ERR(control);
return PTR_ERR(no_free_ptr(control));
card = file->card;
result = snd_ctl_elem_write(card, file, control);
if (result < 0)
goto error;
return result;
if (copy_to_user(_control, control, sizeof(*control)))
result = -EFAULT;
error:
kfree(control);
return -EFAULT;
return result;
}
@ -1433,25 +1374,18 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file,
struct snd_ctl_elem_id id;
struct snd_kcontrol *kctl;
struct snd_kcontrol_volatile *vd;
int result;
if (copy_from_user(&id, _id, sizeof(id)))
return -EFAULT;
down_write(&card->controls_rwsem);
guard(rwsem_write)(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, &id);
if (kctl == NULL) {
result = -ENOENT;
} else {
vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
if (vd->owner != NULL)
result = -EBUSY;
else {
vd->owner = file;
result = 0;
}
}
up_write(&card->controls_rwsem);
return result;
if (!kctl)
return -ENOENT;
vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
if (vd->owner)
return -EBUSY;
vd->owner = file;
return 0;
}
static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
@ -1461,27 +1395,20 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
struct snd_ctl_elem_id id;
struct snd_kcontrol *kctl;
struct snd_kcontrol_volatile *vd;
int result;
if (copy_from_user(&id, _id, sizeof(id)))
return -EFAULT;
down_write(&card->controls_rwsem);
guard(rwsem_write)(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, &id);
if (kctl == NULL) {
result = -ENOENT;
} else {
vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
if (vd->owner == NULL)
result = -EINVAL;
else if (vd->owner != file)
result = -EPERM;
else {
vd->owner = NULL;
result = 0;
}
}
up_write(&card->controls_rwsem);
return result;
if (!kctl)
return -ENOENT;
vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
if (!vd->owner)
return -EINVAL;
if (vd->owner != file)
return -EPERM;
vd->owner = NULL;
return 0;
}
struct user_element {
@ -1763,11 +1690,9 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
private_size = value_sizes[info->type] * info->count;
alloc_size = compute_user_elem_size(private_size, count);
down_write(&card->controls_rwsem);
if (check_user_elem_overflow(card, alloc_size)) {
err = -ENOMEM;
goto unlock;
}
guard(rwsem_write)(&card->controls_rwsem);
if (check_user_elem_overflow(card, alloc_size))
return -ENOMEM;
/*
* Keep memory object for this userspace control. After passing this
@ -1777,13 +1702,12 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
*/
err = snd_ctl_new(&kctl, count, access, file);
if (err < 0)
goto unlock;
return err;
memcpy(&kctl->id, &info->id, sizeof(kctl->id));
ue = kzalloc(alloc_size, GFP_KERNEL);
if (!ue) {
kfree(kctl);
err = -ENOMEM;
goto unlock;
return -ENOMEM;
}
kctl->private_data = ue;
kctl->private_free = snd_ctl_elem_user_free;
@ -1801,7 +1725,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
err = snd_ctl_elem_init_enum_names(ue);
if (err < 0) {
snd_ctl_free_one(kctl);
goto unlock;
return err;
}
}
@ -1821,7 +1745,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
err = __snd_ctl_add_replace(card, kctl, CTL_ADD_EXCLUSIVE);
if (err < 0) {
snd_ctl_free_one(kctl);
goto unlock;
return err;
}
offset = snd_ctl_get_ioff(kctl, &info->id);
snd_ctl_build_ioff(&info->id, kctl, offset);
@ -1832,9 +1756,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
* applications because the field originally means PID of a process
* which locks the element.
*/
unlock:
up_write(&card->controls_rwsem);
return err;
return 0;
}
static int snd_ctl_elem_add_user(struct snd_ctl_file *file,
@ -2036,34 +1958,29 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
return snd_ctl_subscribe_events(ctl, ip);
case SNDRV_CTL_IOCTL_TLV_READ:
down_read(&ctl->card->controls_rwsem);
err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ);
up_read(&ctl->card->controls_rwsem);
scoped_guard(rwsem_read, &ctl->card->controls_rwsem)
err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ);
return err;
case SNDRV_CTL_IOCTL_TLV_WRITE:
down_write(&ctl->card->controls_rwsem);
err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE);
up_write(&ctl->card->controls_rwsem);
scoped_guard(rwsem_write, &ctl->card->controls_rwsem)
err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE);
return err;
case SNDRV_CTL_IOCTL_TLV_COMMAND:
down_write(&ctl->card->controls_rwsem);
err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD);
up_write(&ctl->card->controls_rwsem);
scoped_guard(rwsem_write, &ctl->card->controls_rwsem)
err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD);
return err;
case SNDRV_CTL_IOCTL_POWER:
return -ENOPROTOOPT;
case SNDRV_CTL_IOCTL_POWER_STATE:
return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0;
}
down_read(&snd_ioctl_rwsem);
guard(rwsem_read)(&snd_ioctl_rwsem);
list_for_each_entry(p, &snd_control_ioctls, list) {
err = p->fioctl(card, ctl, cmd, arg);
if (err != -ENOIOCTLCMD) {
up_read(&snd_ioctl_rwsem);
if (err != -ENOIOCTLCMD)
return err;
}
}
up_read(&snd_ioctl_rwsem);
dev_dbg(card->dev, "unknown ioctl = 0x%x\n", cmd);
return -ENOTTY;
}
@ -2155,9 +2072,8 @@ static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *
if (pn == NULL)
return -ENOMEM;
pn->fioctl = fcn;
down_write(&snd_ioctl_rwsem);
guard(rwsem_write)(&snd_ioctl_rwsem);
list_add_tail(&pn->list, lists);
up_write(&snd_ioctl_rwsem);
return 0;
}
@ -2200,16 +2116,14 @@ static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn,
if (snd_BUG_ON(!fcn))
return -EINVAL;
down_write(&snd_ioctl_rwsem);
guard(rwsem_write)(&snd_ioctl_rwsem);
list_for_each_entry(p, lists, list) {
if (p->fioctl == fcn) {
list_del(&p->list);
up_write(&snd_ioctl_rwsem);
kfree(p);
return 0;
}
}
up_write(&snd_ioctl_rwsem);
snd_BUG();
return -EINVAL;
}
@ -2256,9 +2170,8 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type)
{
struct snd_ctl_file *kctl;
int subdevice = -1;
unsigned long flags;
read_lock_irqsave(&card->ctl_files_rwlock, flags);
guard(read_lock_irqsave)(&card->ctl_files_rwlock);
list_for_each_entry(kctl, &card->ctl_files, list) {
if (kctl->pid == task_pid(current)) {
subdevice = kctl->preferred_subdevice[type];
@ -2266,7 +2179,6 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type)
break;
}
}
read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
return subdevice;
}
EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice);
@ -2296,13 +2208,11 @@ int snd_ctl_request_layer(const char *module_name)
if (module_name == NULL)
return 0;
down_read(&snd_ctl_layer_rwsem);
for (lops = snd_ctl_layer; lops; lops = lops->next)
if (strcmp(lops->module_name, module_name) == 0)
break;
up_read(&snd_ctl_layer_rwsem);
if (lops)
return 0;
scoped_guard(rwsem_read, &snd_ctl_layer_rwsem) {
for (lops = snd_ctl_layer; lops; lops = lops->next)
if (strcmp(lops->module_name, module_name) == 0)
return 0;
}
return request_module(module_name);
}
EXPORT_SYMBOL_GPL(snd_ctl_request_layer);
@ -2319,16 +2229,15 @@ void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops)
struct snd_card *card;
int card_number;
down_write(&snd_ctl_layer_rwsem);
lops->next = snd_ctl_layer;
snd_ctl_layer = lops;
up_write(&snd_ctl_layer_rwsem);
scoped_guard(rwsem_write, &snd_ctl_layer_rwsem) {
lops->next = snd_ctl_layer;
snd_ctl_layer = lops;
}
for (card_number = 0; card_number < SNDRV_CARDS; card_number++) {
card = snd_card_ref(card_number);
if (card) {
down_read(&card->controls_rwsem);
lops->lregister(card);
up_read(&card->controls_rwsem);
scoped_guard(rwsem_read, &card->controls_rwsem)
lops->lregister(card);
snd_card_unref(card);
}
}
@ -2347,7 +2256,7 @@ void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops)
{
struct snd_ctl_layer_ops *lops2, *prev_lops2;
down_write(&snd_ctl_layer_rwsem);
guard(rwsem_write)(&snd_ctl_layer_rwsem);
for (lops2 = snd_ctl_layer, prev_lops2 = NULL; lops2; lops2 = lops2->next) {
if (lops2 == lops) {
if (!prev_lops2)
@ -2358,7 +2267,6 @@ void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops)
}
prev_lops2 = lops2;
}
up_write(&snd_ctl_layer_rwsem);
}
EXPORT_SYMBOL_GPL(snd_ctl_disconnect_layer);
@ -2379,25 +2287,29 @@ static const struct file_operations snd_ctl_f_ops =
.fasync = snd_ctl_fasync,
};
/* call lops under rwsems; called from snd_ctl_dev_*() below() */
#define call_snd_ctl_lops(_card, _op) \
do { \
struct snd_ctl_layer_ops *lops; \
guard(rwsem_read)(&(_card)->controls_rwsem); \
guard(rwsem_read)(&snd_ctl_layer_rwsem); \
for (lops = snd_ctl_layer; lops; lops = lops->next) \
lops->_op(_card); \
} while (0)
/*
* registration of the control device
*/
static int snd_ctl_dev_register(struct snd_device *device)
{
struct snd_card *card = device->device_data;
struct snd_ctl_layer_ops *lops;
int err;
err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
&snd_ctl_f_ops, card, card->ctl_dev);
if (err < 0)
return err;
down_read(&card->controls_rwsem);
down_read(&snd_ctl_layer_rwsem);
for (lops = snd_ctl_layer; lops; lops = lops->next)
lops->lregister(card);
up_read(&snd_ctl_layer_rwsem);
up_read(&card->controls_rwsem);
call_snd_ctl_lops(card, lregister);
return 0;
}
@ -2408,23 +2320,15 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
{
struct snd_card *card = device->device_data;
struct snd_ctl_file *ctl;
struct snd_ctl_layer_ops *lops;
unsigned long flags;
read_lock_irqsave(&card->ctl_files_rwlock, flags);
list_for_each_entry(ctl, &card->ctl_files, list) {
wake_up(&ctl->change_sleep);
snd_kill_fasync(ctl->fasync, SIGIO, POLL_ERR);
scoped_guard(read_lock_irqsave, &card->ctl_files_rwlock) {
list_for_each_entry(ctl, &card->ctl_files, list) {
wake_up(&ctl->change_sleep);
snd_kill_fasync(ctl->fasync, SIGIO, POLL_ERR);
}
}
read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
down_read(&card->controls_rwsem);
down_read(&snd_ctl_layer_rwsem);
for (lops = snd_ctl_layer; lops; lops = lops->next)
lops->ldisconnect(card);
up_read(&snd_ctl_layer_rwsem);
up_read(&card->controls_rwsem);
call_snd_ctl_lops(card, ldisconnect);
return snd_unregister_device(card->ctl_dev);
}
@ -2436,17 +2340,17 @@ static int snd_ctl_dev_free(struct snd_device *device)
struct snd_card *card = device->device_data;
struct snd_kcontrol *control;
down_write(&card->controls_rwsem);
while (!list_empty(&card->controls)) {
control = snd_kcontrol(card->controls.next);
__snd_ctl_remove(card, control, false);
}
scoped_guard(rwsem_write, &card->controls_rwsem) {
while (!list_empty(&card->controls)) {
control = snd_kcontrol(card->controls.next);
__snd_ctl_remove(card, control, false);
}
#ifdef CONFIG_SND_CTL_FAST_LOOKUP
xa_destroy(&card->ctl_numids);
xa_destroy(&card->ctl_hash);
xa_destroy(&card->ctl_numids);
xa_destroy(&card->ctl_hash);
#endif
up_write(&card->controls_rwsem);
}
put_device(card->ctl_dev);
return 0;
}

View File

@ -79,61 +79,56 @@ struct snd_ctl_elem_info32 {
static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl,
struct snd_ctl_elem_info32 __user *data32)
{
struct snd_ctl_elem_info *data;
struct snd_ctl_elem_info *data __free(kfree) = NULL;
int err;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (! data)
return -ENOMEM;
err = -EFAULT;
/* copy id */
if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
goto error;
return -EFAULT;
/* we need to copy the item index.
* hope this doesn't break anything..
*/
if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
goto error;
return -EFAULT;
err = snd_ctl_elem_info(ctl, data);
if (err < 0)
goto error;
return err;
/* restore info to 32bit */
err = -EFAULT;
/* id, type, access, count */
if (copy_to_user(&data32->id, &data->id, sizeof(data->id)) ||
copy_to_user(&data32->type, &data->type, 3 * sizeof(u32)))
goto error;
return -EFAULT;
if (put_user(data->owner, &data32->owner))
goto error;
return -EFAULT;
switch (data->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
case SNDRV_CTL_ELEM_TYPE_INTEGER:
if (put_user(data->value.integer.min, &data32->value.integer.min) ||
put_user(data->value.integer.max, &data32->value.integer.max) ||
put_user(data->value.integer.step, &data32->value.integer.step))
goto error;
return -EFAULT;
break;
case SNDRV_CTL_ELEM_TYPE_INTEGER64:
if (copy_to_user(&data32->value.integer64,
&data->value.integer64,
sizeof(data->value.integer64)))
goto error;
return -EFAULT;
break;
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
if (copy_to_user(&data32->value.enumerated,
&data->value.enumerated,
sizeof(data->value.enumerated)))
goto error;
return -EFAULT;
break;
default:
break;
}
err = 0;
error:
kfree(data);
return err;
return 0;
}
/* read / write */
@ -169,31 +164,25 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
int *countp)
{
struct snd_kcontrol *kctl;
struct snd_ctl_elem_info *info;
struct snd_ctl_elem_info *info __free(kfree) = NULL;
int err;
down_read(&card->controls_rwsem);
guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, id);
if (! kctl) {
up_read(&card->controls_rwsem);
if (!kctl)
return -ENOENT;
}
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (info == NULL) {
up_read(&card->controls_rwsem);
if (info == NULL)
return -ENOMEM;
}
info->id = *id;
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;
*countp = info->count;
}
kfree(info);
return err;
}
@ -289,7 +278,7 @@ static int copy_ctl_value_to_user(void __user *userdata,
static int ctl_elem_read_user(struct snd_card *card,
void __user *userdata, void __user *valuep)
{
struct snd_ctl_elem_value *data;
struct snd_ctl_elem_value *data __free(kfree) = NULL;
int err, type, count;
data = kzalloc(sizeof(*data), GFP_KERNEL);
@ -299,21 +288,18 @@ static int ctl_elem_read_user(struct snd_card *card,
err = copy_ctl_value_from_user(card, data, userdata, valuep,
&type, &count);
if (err < 0)
goto error;
return err;
err = snd_ctl_elem_read(card, data);
if (err < 0)
goto error;
err = copy_ctl_value_to_user(userdata, valuep, data, type, count);
error:
kfree(data);
return err;
return err;
return copy_ctl_value_to_user(userdata, valuep, data, type, count);
}
static int ctl_elem_write_user(struct snd_ctl_file *file,
void __user *userdata, void __user *valuep)
{
struct snd_ctl_elem_value *data;
struct snd_ctl_elem_value *data __free(kfree) = NULL;
struct snd_card *card = file->card;
int err, type, count;
@ -324,15 +310,12 @@ static int ctl_elem_write_user(struct snd_ctl_file *file,
err = copy_ctl_value_from_user(card, data, userdata, valuep,
&type, &count);
if (err < 0)
goto error;
return err;
err = snd_ctl_elem_write(card, file, data);
if (err < 0)
goto error;
err = copy_ctl_value_to_user(userdata, valuep, data, type, count);
error:
kfree(data);
return err;
return err;
return copy_ctl_value_to_user(userdata, valuep, data, type, count);
}
static int snd_ctl_elem_read_user_compat(struct snd_card *card,
@ -366,49 +349,44 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file,
struct snd_ctl_elem_info32 __user *data32,
int replace)
{
struct snd_ctl_elem_info *data;
int err;
struct snd_ctl_elem_info *data __free(kfree) = NULL;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (! data)
return -ENOMEM;
err = -EFAULT;
/* id, type, access, count */ \
if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) ||
copy_from_user(&data->type, &data32->type, 3 * sizeof(u32)))
goto error;
return -EFAULT;
if (get_user(data->owner, &data32->owner))
goto error;
return -EFAULT;
switch (data->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
case SNDRV_CTL_ELEM_TYPE_INTEGER:
if (get_user(data->value.integer.min, &data32->value.integer.min) ||
get_user(data->value.integer.max, &data32->value.integer.max) ||
get_user(data->value.integer.step, &data32->value.integer.step))
goto error;
return -EFAULT;
break;
case SNDRV_CTL_ELEM_TYPE_INTEGER64:
if (copy_from_user(&data->value.integer64,
&data32->value.integer64,
sizeof(data->value.integer64)))
goto error;
return -EFAULT;
break;
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
if (copy_from_user(&data->value.enumerated,
&data32->value.enumerated,
sizeof(data->value.enumerated)))
goto error;
return -EFAULT;
data->value.enumerated.names_ptr =
(uintptr_t)compat_ptr(data->value.enumerated.names_ptr);
break;
default:
break;
}
err = snd_ctl_elem_add(file, data, replace);
error:
kfree(data);
return err;
return snd_ctl_elem_add(file, data, replace);
}
enum {
@ -468,16 +446,13 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
#endif /* CONFIG_X86_X32_ABI */
}
down_read(&snd_ioctl_rwsem);
guard(rwsem_read)(&snd_ioctl_rwsem);
list_for_each_entry(p, &snd_control_compat_ioctls, list) {
if (p->fioctl) {
err = p->fioctl(ctl->card, ctl, cmd, arg);
if (err != -ENOIOCTLCMD) {
up_read(&snd_ioctl_rwsem);
if (err != -ENOIOCTLCMD)
return err;
}
}
}
up_read(&snd_ioctl_rwsem);
return -ENOIOCTLCMD;
}

View File

@ -147,29 +147,27 @@ static void snd_ctl_led_set_state(struct snd_card *card, unsigned int access,
return;
route = -1;
found = false;
mutex_lock(&snd_ctl_led_mutex);
/* the card may not be registered (active) at this point */
if (card && !snd_ctl_led_card_valid[card->number]) {
mutex_unlock(&snd_ctl_led_mutex);
return;
}
list_for_each_entry(lctl, &led->controls, list) {
if (lctl->kctl == kctl && lctl->index_offset == ioff)
found = true;
UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
}
if (!found && kctl && card) {
lctl = kzalloc(sizeof(*lctl), GFP_KERNEL);
if (lctl) {
lctl->card = card;
lctl->access = access;
lctl->kctl = kctl;
lctl->index_offset = ioff;
list_add(&lctl->list, &led->controls);
scoped_guard(mutex, &snd_ctl_led_mutex) {
/* the card may not be registered (active) at this point */
if (card && !snd_ctl_led_card_valid[card->number])
return;
list_for_each_entry(lctl, &led->controls, list) {
if (lctl->kctl == kctl && lctl->index_offset == ioff)
found = true;
UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
}
if (!found && kctl && card) {
lctl = kzalloc(sizeof(*lctl), GFP_KERNEL);
if (lctl) {
lctl->card = card;
lctl->access = access;
lctl->kctl = kctl;
lctl->index_offset = ioff;
list_add(&lctl->list, &led->controls);
UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
}
}
}
mutex_unlock(&snd_ctl_led_mutex);
switch (led->mode) {
case MODE_OFF: route = 1; break;
case MODE_ON: route = 0; break;
@ -201,14 +199,13 @@ static unsigned int snd_ctl_led_remove(struct snd_kcontrol *kctl, unsigned int i
struct snd_ctl_led_ctl *lctl;
unsigned int ret = 0;
mutex_lock(&snd_ctl_led_mutex);
guard(mutex)(&snd_ctl_led_mutex);
lctl = snd_ctl_led_find(kctl, ioff);
if (lctl && (access == 0 || access != lctl->access)) {
ret = lctl->access;
list_del(&lctl->list);
kfree(lctl);
}
mutex_unlock(&snd_ctl_led_mutex);
return ret;
}
@ -239,44 +236,36 @@ static void snd_ctl_led_notify(struct snd_card *card, unsigned int mask,
}
}
DEFINE_FREE(snd_card_unref, struct snd_card *, if (_T) snd_card_unref(_T))
static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id,
unsigned int group, bool set)
{
struct snd_card *card;
struct snd_card *card __free(snd_card_unref) = NULL;
struct snd_kcontrol *kctl;
struct snd_kcontrol_volatile *vd;
unsigned int ioff, access, new_access;
int err = 0;
card = snd_card_ref(card_number);
if (card) {
down_write(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, id);
if (kctl) {
ioff = snd_ctl_get_ioff(kctl, id);
vd = &kctl->vd[ioff];
access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK;
if (access != 0 && access != group_to_access(group)) {
err = -EXDEV;
goto unlock;
}
new_access = vd->access & ~SNDRV_CTL_ELEM_ACCESS_LED_MASK;
if (set)
new_access |= group_to_access(group);
if (new_access != vd->access) {
vd->access = new_access;
snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, ioff);
}
} else {
err = -ENOENT;
}
unlock:
up_write(&card->controls_rwsem);
snd_card_unref(card);
} else {
err = -ENXIO;
if (!card)
return -ENXIO;
guard(rwsem_write)(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, id);
if (!kctl)
return -ENOENT;
ioff = snd_ctl_get_ioff(kctl, id);
vd = &kctl->vd[ioff];
access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK;
if (access != 0 && access != group_to_access(group))
return -EXDEV;
new_access = vd->access & ~SNDRV_CTL_ELEM_ACCESS_LED_MASK;
if (set)
new_access |= group_to_access(group);
if (new_access != vd->access) {
vd->access = new_access;
snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, ioff);
}
return err;
return 0;
}
static void snd_ctl_led_refresh(void)
@ -312,7 +301,7 @@ repeat:
static int snd_ctl_led_reset(int card_number, unsigned int group)
{
struct snd_card *card;
struct snd_card *card __free(snd_card_unref) = NULL;
struct snd_ctl_led *led;
struct snd_ctl_led_ctl *lctl;
struct snd_kcontrol_volatile *vd;
@ -322,26 +311,22 @@ static int snd_ctl_led_reset(int card_number, unsigned int group)
if (!card)
return -ENXIO;
mutex_lock(&snd_ctl_led_mutex);
if (!snd_ctl_led_card_valid[card_number]) {
mutex_unlock(&snd_ctl_led_mutex);
snd_card_unref(card);
return -ENXIO;
}
led = &snd_ctl_leds[group];
scoped_guard(mutex, &snd_ctl_led_mutex) {
if (!snd_ctl_led_card_valid[card_number])
return -ENXIO;
led = &snd_ctl_leds[group];
repeat:
list_for_each_entry(lctl, &led->controls, list)
if (lctl->card == card) {
vd = &lctl->kctl->vd[lctl->index_offset];
vd->access &= ~group_to_access(group);
snd_ctl_led_ctl_destroy(lctl);
change = true;
goto repeat;
}
mutex_unlock(&snd_ctl_led_mutex);
list_for_each_entry(lctl, &led->controls, list)
if (lctl->card == card) {
vd = &lctl->kctl->vd[lctl->index_offset];
vd->access &= ~group_to_access(group);
snd_ctl_led_ctl_destroy(lctl);
change = true;
goto repeat;
}
}
if (change)
snd_ctl_led_set_state(NULL, group_to_access(group), NULL, 0);
snd_card_unref(card);
return 0;
}
@ -353,9 +338,8 @@ static void snd_ctl_led_register(struct snd_card *card)
if (snd_BUG_ON(card->number < 0 ||
card->number >= ARRAY_SIZE(snd_ctl_led_card_valid)))
return;
mutex_lock(&snd_ctl_led_mutex);
snd_ctl_led_card_valid[card->number] = true;
mutex_unlock(&snd_ctl_led_mutex);
scoped_guard(mutex, &snd_ctl_led_mutex)
snd_ctl_led_card_valid[card->number] = true;
/* the register callback is already called with held card->controls_rwsem */
list_for_each_entry(kctl, &card->controls, list)
for (ioff = 0; ioff < kctl->count; ioff++)
@ -367,10 +351,10 @@ static void snd_ctl_led_register(struct snd_card *card)
static void snd_ctl_led_disconnect(struct snd_card *card)
{
snd_ctl_led_sysfs_remove(card);
mutex_lock(&snd_ctl_led_mutex);
snd_ctl_led_card_valid[card->number] = false;
snd_ctl_led_clean(card);
mutex_unlock(&snd_ctl_led_mutex);
scoped_guard(mutex, &snd_ctl_led_mutex) {
snd_ctl_led_card_valid[card->number] = false;
snd_ctl_led_clean(card);
}
snd_ctl_led_refresh();
}
@ -430,9 +414,8 @@ static ssize_t mode_store(struct device *dev,
else
return count;
mutex_lock(&snd_ctl_led_mutex);
led->mode = mode;
mutex_unlock(&snd_ctl_led_mutex);
scoped_guard(mutex, &snd_ctl_led_mutex)
led->mode = mode;
snd_ctl_led_set_state(NULL, group_to_access(led->group), NULL, 0);
return count;
@ -615,15 +598,15 @@ 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;
struct snd_card *card __free(snd_card_unref) = NULL;
struct snd_ctl_led_ctl *lctl;
size_t l = 0;
card = snd_card_ref(led_card->number);
if (!card)
return -ENXIO;
down_read(&card->controls_rwsem);
mutex_lock(&snd_ctl_led_mutex);
guard(rwsem_read)(&card->controls_rwsem);
guard(mutex)(&snd_ctl_led_mutex);
if (snd_ctl_led_card_valid[led_card->number]) {
list_for_each_entry(lctl, &led_card->led->controls, list) {
if (lctl->card != card)
@ -634,9 +617,6 @@ static ssize_t list_show(struct device *dev,
lctl->kctl->id.numid + lctl->index_offset);
}
}
mutex_unlock(&snd_ctl_led_mutex);
up_read(&card->controls_rwsem);
snd_card_unref(card);
return l;
}

View File

@ -35,12 +35,12 @@ static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
unsigned long ticks;
enum hrtimer_restart ret = HRTIMER_NORESTART;
spin_lock(&t->lock);
if (!t->running)
goto out; /* fast path */
stime->in_callback = true;
ticks = t->sticks;
spin_unlock(&t->lock);
scoped_guard(spinlock, &t->lock) {
if (!t->running)
return HRTIMER_NORESTART; /* fast path */
stime->in_callback = true;
ticks = t->sticks;
}
/* calculate the drift */
delta = ktime_sub(hrt->base->get_time(), hrtimer_get_expires(hrt));
@ -49,15 +49,13 @@ static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
snd_timer_interrupt(stime->timer, ticks);
spin_lock(&t->lock);
guard(spinlock)(&t->lock);
if (t->running) {
hrtimer_add_expires_ns(hrt, t->sticks * resolution);
ret = HRTIMER_RESTART;
}
stime->in_callback = false;
out:
spin_unlock(&t->lock);
return ret;
}
@ -80,10 +78,10 @@ static int snd_hrtimer_close(struct snd_timer *t)
struct snd_hrtimer *stime = t->private_data;
if (stime) {
spin_lock_irq(&t->lock);
t->running = 0; /* just to be sure */
stime->in_callback = 1; /* skip start/stop */
spin_unlock_irq(&t->lock);
scoped_guard(spinlock_irq, &t->lock) {
t->running = 0; /* just to be sure */
stime->in_callback = 1; /* skip start/stop */
}
hrtimer_cancel(&stime->hrt);
kfree(stime);

View File

@ -149,12 +149,12 @@ static int snd_hwdep_release(struct inode *inode, struct file * file)
struct snd_hwdep *hw = file->private_data;
struct module *mod = hw->card->module;
mutex_lock(&hw->open_mutex);
if (hw->ops.release)
err = hw->ops.release(hw, file);
if (hw->used > 0)
hw->used--;
mutex_unlock(&hw->open_mutex);
scoped_guard(mutex, &hw->open_mutex) {
if (hw->ops.release)
err = hw->ops.release(hw, file);
if (hw->used > 0)
hw->used--;
}
wake_up(&hw->open_wait);
snd_card_file_remove(hw->card, file);
@ -272,23 +272,23 @@ static int snd_hwdep_control_ioctl(struct snd_card *card,
if (get_user(device, (int __user *)arg))
return -EFAULT;
mutex_lock(&register_mutex);
if (device < 0)
device = 0;
else if (device < SNDRV_MINOR_HWDEPS)
device++;
else
device = SNDRV_MINOR_HWDEPS;
scoped_guard(mutex, &register_mutex) {
if (device < 0)
device = 0;
else if (device < SNDRV_MINOR_HWDEPS)
device++;
else
device = SNDRV_MINOR_HWDEPS;
while (device < SNDRV_MINOR_HWDEPS) {
if (snd_hwdep_search(card, device))
break;
device++;
while (device < SNDRV_MINOR_HWDEPS) {
if (snd_hwdep_search(card, device))
break;
device++;
}
if (device >= SNDRV_MINOR_HWDEPS)
device = -1;
}
if (device >= SNDRV_MINOR_HWDEPS)
device = -1;
mutex_unlock(&register_mutex);
if (put_user(device, (int __user *)arg))
return -EFAULT;
return 0;
@ -296,19 +296,18 @@ static int snd_hwdep_control_ioctl(struct snd_card *card,
case SNDRV_CTL_IOCTL_HWDEP_INFO:
{
struct snd_hwdep_info __user *info = (struct snd_hwdep_info __user *)arg;
int device, err;
int device;
struct snd_hwdep *hwdep;
if (get_user(device, &info->device))
return -EFAULT;
mutex_lock(&register_mutex);
hwdep = snd_hwdep_search(card, device);
if (hwdep)
err = snd_hwdep_info(hwdep, info);
else
err = -ENXIO;
mutex_unlock(&register_mutex);
return err;
scoped_guard(mutex, &register_mutex) {
hwdep = snd_hwdep_search(card, device);
if (!hwdep)
return -ENXIO;
return snd_hwdep_info(hwdep, info);
}
break;
}
}
return -ENOIOCTLCMD;
@ -422,11 +421,9 @@ static int snd_hwdep_dev_register(struct snd_device *device)
struct snd_card *card = hwdep->card;
int err;
mutex_lock(&register_mutex);
if (snd_hwdep_search(card, hwdep->device)) {
mutex_unlock(&register_mutex);
guard(mutex)(&register_mutex);
if (snd_hwdep_search(card, hwdep->device))
return -EBUSY;
}
list_add_tail(&hwdep->list, &snd_hwdep_devices);
err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP,
hwdep->card, hwdep->device,
@ -434,7 +431,6 @@ static int snd_hwdep_dev_register(struct snd_device *device)
if (err < 0) {
dev_err(hwdep->dev, "unable to register\n");
list_del(&hwdep->list);
mutex_unlock(&register_mutex);
return err;
}
@ -454,7 +450,6 @@ static int snd_hwdep_dev_register(struct snd_device *device)
hwdep->ossreg = 1;
}
#endif
mutex_unlock(&register_mutex);
return 0;
}
@ -464,12 +459,10 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
if (snd_BUG_ON(!hwdep))
return -ENXIO;
mutex_lock(&register_mutex);
if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep) {
mutex_unlock(&register_mutex);
guard(mutex)(&register_mutex);
if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep)
return -EINVAL;
}
mutex_lock(&hwdep->open_mutex);
guard(mutex)(&hwdep->open_mutex);
wake_up(&hwdep->open_wait);
#ifdef CONFIG_SND_OSSEMUL
if (hwdep->ossreg)
@ -477,8 +470,6 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
#endif
snd_unregister_device(hwdep->dev);
list_del_init(&hwdep->list);
mutex_unlock(&hwdep->open_mutex);
mutex_unlock(&register_mutex);
return 0;
}
@ -492,11 +483,10 @@ static void snd_hwdep_proc_read(struct snd_info_entry *entry,
{
struct snd_hwdep *hwdep;
mutex_lock(&register_mutex);
guard(mutex)(&register_mutex);
list_for_each_entry(hwdep, &snd_hwdep_devices, list)
snd_iprintf(buffer, "%02i-%02i: %s\n",
hwdep->card->number, hwdep->device, hwdep->name);
mutex_unlock(&register_mutex);
}
static struct snd_info_entry *snd_hwdep_proc_entry;

View File

@ -105,17 +105,15 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
{
struct snd_info_private_data *data;
struct snd_info_entry *entry;
loff_t ret = -EINVAL, size;
loff_t size;
data = file->private_data;
entry = data->entry;
mutex_lock(&entry->access);
if (entry->c.ops->llseek) {
ret = entry->c.ops->llseek(entry,
data->file_private_data,
file, offset, orig);
goto out;
}
guard(mutex)(&entry->access);
if (entry->c.ops->llseek)
return entry->c.ops->llseek(entry,
data->file_private_data,
file, offset, orig);
size = entry->size;
switch (orig) {
@ -126,21 +124,18 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
break;
case SEEK_END:
if (!size)
goto out;
return -EINVAL;
offset += size;
break;
default:
goto out;
return -EINVAL;
}
if (offset < 0)
goto out;
return -EINVAL;
if (size && offset > size)
offset = size;
file->f_pos = offset;
ret = offset;
out:
mutex_unlock(&entry->access);
return ret;
return offset;
}
static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
@ -238,10 +233,10 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
struct snd_info_private_data *data;
int mode, err;
mutex_lock(&info_mutex);
guard(mutex)(&info_mutex);
err = alloc_info_private(entry, &data);
if (err < 0)
goto unlock;
return err;
mode = file->f_flags & O_ACCMODE;
if (((mode == O_RDONLY || mode == O_RDWR) && !entry->c.ops->read) ||
@ -257,14 +252,11 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
}
file->private_data = data;
mutex_unlock(&info_mutex);
return 0;
error:
kfree(data);
module_put(entry->module);
unlock:
mutex_unlock(&info_mutex);
return err;
}
@ -306,7 +298,6 @@ static ssize_t snd_info_text_entry_write(struct file *file,
struct snd_info_buffer *buf;
loff_t pos;
size_t next;
int err = 0;
if (!entry->c.text.write)
return -EIO;
@ -317,34 +308,24 @@ static ssize_t snd_info_text_entry_write(struct file *file,
/* don't handle too large text inputs */
if (next > 16 * 1024)
return -EIO;
mutex_lock(&entry->access);
guard(mutex)(&entry->access);
buf = data->wbuffer;
if (!buf) {
data->wbuffer = buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf) {
err = -ENOMEM;
goto error;
}
if (!buf)
return -ENOMEM;
}
if (next > buf->len) {
char *nbuf = kvzalloc(PAGE_ALIGN(next), GFP_KERNEL);
if (!nbuf) {
err = -ENOMEM;
goto error;
}
if (!nbuf)
return -ENOMEM;
kvfree(buf->buffer);
buf->buffer = nbuf;
buf->len = PAGE_ALIGN(next);
}
if (copy_from_user(buf->buffer + pos, buffer, count)) {
err = -EFAULT;
goto error;
}
if (copy_from_user(buf->buffer + pos, buffer, count))
return -EFAULT;
buf->size = next;
error:
mutex_unlock(&entry->access);
if (err < 0)
return err;
*offset = next;
return count;
}
@ -369,10 +350,10 @@ static int snd_info_text_entry_open(struct inode *inode, struct file *file)
struct snd_info_private_data *data;
int err;
mutex_lock(&info_mutex);
guard(mutex)(&info_mutex);
err = alloc_info_private(entry, &data);
if (err < 0)
goto unlock;
return err;
data->rbuffer = kzalloc(sizeof(*data->rbuffer), GFP_KERNEL);
if (!data->rbuffer) {
@ -386,15 +367,12 @@ static int snd_info_text_entry_open(struct inode *inode, struct file *file)
err = single_open(file, snd_info_seq_show, data);
if (err < 0)
goto error;
mutex_unlock(&info_mutex);
return 0;
error:
kfree(data->rbuffer);
kfree(data);
module_put(entry->module);
unlock:
mutex_unlock(&info_mutex);
return err;
}
@ -549,7 +527,7 @@ int snd_info_card_register(struct snd_card *card)
*/
void snd_info_card_id_change(struct snd_card *card)
{
mutex_lock(&info_mutex);
guard(mutex)(&info_mutex);
if (card->proc_root_link) {
proc_remove(card->proc_root_link);
card->proc_root_link = NULL;
@ -558,7 +536,6 @@ void snd_info_card_id_change(struct snd_card *card)
card->proc_root_link = proc_symlink(card->id,
snd_proc_root->p,
card->proc_root->name);
mutex_unlock(&info_mutex);
}
/*
@ -574,12 +551,11 @@ void snd_info_card_disconnect(struct snd_card *card)
if (card->proc_root)
proc_remove(card->proc_root->p);
mutex_lock(&info_mutex);
guard(mutex)(&info_mutex);
if (card->proc_root)
snd_info_clear_entries(card->proc_root);
card->proc_root_link = NULL;
card->proc_root = NULL;
mutex_unlock(&info_mutex);
}
/*
@ -703,9 +679,8 @@ snd_info_create_entry(const char *name, struct snd_info_entry *parent,
entry->parent = parent;
entry->module = module;
if (parent) {
mutex_lock(&parent->access);
guard(mutex)(&parent->access);
list_add_tail(&entry->list, &parent->children);
mutex_unlock(&parent->access);
}
return entry;
}
@ -775,9 +750,8 @@ void snd_info_free_entry(struct snd_info_entry * entry)
return;
if (entry->p) {
proc_remove(entry->p);
mutex_lock(&info_mutex);
guard(mutex)(&info_mutex);
snd_info_clear_entries(entry);
mutex_unlock(&info_mutex);
}
/* free all children at first */
@ -786,9 +760,8 @@ void snd_info_free_entry(struct snd_info_entry * entry)
p = entry->parent;
if (p) {
mutex_lock(&p->access);
guard(mutex)(&p->access);
list_del(&entry->list);
mutex_unlock(&p->access);
}
kfree(entry->name);
if (entry->private_free)
@ -804,15 +777,13 @@ static int __snd_info_register(struct snd_info_entry *entry)
if (snd_BUG_ON(!entry))
return -ENXIO;
root = entry->parent == NULL ? snd_proc_root->p : entry->parent->p;
mutex_lock(&info_mutex);
guard(mutex)(&info_mutex);
if (entry->p || !root)
goto unlock;
return 0;
if (S_ISDIR(entry->mode)) {
p = proc_mkdir_mode(entry->name, entry->mode, root);
if (!p) {
mutex_unlock(&info_mutex);
if (!p)
return -ENOMEM;
}
} else {
const struct proc_ops *ops;
if (entry->content == SNDRV_INFO_CONTENT_DATA)
@ -821,15 +792,11 @@ static int __snd_info_register(struct snd_info_entry *entry)
ops = &snd_info_text_entry_ops;
p = proc_create_data(entry->name, entry->mode, root,
ops, entry);
if (!p) {
mutex_unlock(&info_mutex);
if (!p)
return -ENOMEM;
}
proc_set_size(p, entry->size);
}
entry->p = p;
unlock:
mutex_unlock(&info_mutex);
return 0;
}

View File

@ -29,20 +29,17 @@ int snd_oss_info_register(int dev, int num, char *string)
return -ENXIO;
if (snd_BUG_ON(num < 0 || num >= SNDRV_CARDS))
return -ENXIO;
mutex_lock(&strings);
guard(mutex)(&strings);
if (string == NULL) {
x = snd_sndstat_strings[num][dev];
kfree(x);
x = NULL;
} else {
x = kstrdup(string, GFP_KERNEL);
if (x == NULL) {
mutex_unlock(&strings);
if (x == NULL)
return -ENOMEM;
}
}
snd_sndstat_strings[num][dev] = x;
mutex_unlock(&strings);
return 0;
}
EXPORT_SYMBOL(snd_oss_info_register);
@ -53,7 +50,7 @@ static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int d
char *str;
snd_iprintf(buf, "\n%s:", id);
mutex_lock(&strings);
guard(mutex)(&strings);
for (idx = 0; idx < SNDRV_CARDS; idx++) {
str = snd_sndstat_strings[idx][dev];
if (str) {
@ -64,7 +61,6 @@ static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int d
snd_iprintf(buf, "%i: %s\n", idx, str);
}
}
mutex_unlock(&strings);
if (ok < 0)
snd_iprintf(buf, " NOT ENABLED IN CONFIG\n");
return ok;

View File

@ -284,30 +284,31 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
if (xid)
strscpy(card->id, xid, sizeof(card->id));
err = 0;
mutex_lock(&snd_card_mutex);
if (idx < 0) /* first check the matching module-name slot */
idx = get_slot_from_bitmask(idx, module_slot_match, module);
if (idx < 0) /* if not matched, assign an empty slot */
idx = get_slot_from_bitmask(idx, check_empty_slot, module);
if (idx < 0)
err = -ENODEV;
else if (idx < snd_ecards_limit) {
if (test_bit(idx, snd_cards_lock))
err = -EBUSY; /* invalid */
} else if (idx >= SNDRV_CARDS)
err = -ENODEV;
scoped_guard(mutex, &snd_card_mutex) {
if (idx < 0) /* first check the matching module-name slot */
idx = get_slot_from_bitmask(idx, module_slot_match, module);
if (idx < 0) /* if not matched, assign an empty slot */
idx = get_slot_from_bitmask(idx, check_empty_slot, module);
if (idx < 0)
err = -ENODEV;
else if (idx < snd_ecards_limit) {
if (test_bit(idx, snd_cards_lock))
err = -EBUSY; /* invalid */
} else if (idx >= SNDRV_CARDS)
err = -ENODEV;
if (!err) {
set_bit(idx, snd_cards_lock); /* lock it */
if (idx >= snd_ecards_limit)
snd_ecards_limit = idx + 1; /* increase the limit */
}
}
if (err < 0) {
mutex_unlock(&snd_card_mutex);
dev_err(parent, "cannot find the slot for index %d (range 0-%i), error: %d\n",
idx, snd_ecards_limit - 1, err);
idx, snd_ecards_limit - 1, err);
if (!card->managed)
kfree(card); /* manually free here, as no destructor called */
return err;
}
set_bit(idx, snd_cards_lock); /* lock it */
if (idx >= snd_ecards_limit)
snd_ecards_limit = idx + 1; /* increase the limit */
mutex_unlock(&snd_card_mutex);
card->dev = parent;
card->number = idx;
#ifdef MODULE
@ -386,11 +387,10 @@ struct snd_card *snd_card_ref(int idx)
{
struct snd_card *card;
mutex_lock(&snd_card_mutex);
guard(mutex)(&snd_card_mutex);
card = snd_cards[idx];
if (card)
get_device(&card->card_dev);
mutex_unlock(&snd_card_mutex);
return card;
}
EXPORT_SYMBOL_GPL(snd_card_ref);
@ -398,12 +398,8 @@ EXPORT_SYMBOL_GPL(snd_card_ref);
/* return non-zero if a card is already locked */
int snd_card_locked(int card)
{
int locked;
mutex_lock(&snd_card_mutex);
locked = test_bit(card, snd_cards_lock);
mutex_unlock(&snd_card_mutex);
return locked;
guard(mutex)(&snd_card_mutex);
return test_bit(card, snd_cards_lock);
}
static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
@ -427,15 +423,15 @@ static int snd_disconnect_release(struct inode *inode, struct file *file)
{
struct snd_monitor_file *df = NULL, *_df;
spin_lock(&shutdown_lock);
list_for_each_entry(_df, &shutdown_files, shutdown_list) {
if (_df->file == file) {
df = _df;
list_del_init(&df->shutdown_list);
break;
scoped_guard(spinlock, &shutdown_lock) {
list_for_each_entry(_df, &shutdown_files, shutdown_list) {
if (_df->file == file) {
df = _df;
list_del_init(&df->shutdown_list);
break;
}
}
}
spin_unlock(&shutdown_lock);
if (likely(df)) {
if ((file->f_flags & FASYNC) && df->disconnected_f_op->fasync)
@ -501,27 +497,24 @@ void snd_card_disconnect(struct snd_card *card)
if (!card)
return;
spin_lock(&card->files_lock);
if (card->shutdown) {
spin_unlock(&card->files_lock);
return;
scoped_guard(spinlock, &card->files_lock) {
if (card->shutdown)
return;
card->shutdown = 1;
/* replace file->f_op with special dummy operations */
list_for_each_entry(mfile, &card->files_list, list) {
/* it's critical part, use endless loop */
/* we have no room to fail */
mfile->disconnected_f_op = mfile->file->f_op;
scoped_guard(spinlock, &shutdown_lock)
list_add(&mfile->shutdown_list, &shutdown_files);
mfile->file->f_op = &snd_shutdown_f_ops;
fops_get(mfile->file->f_op);
}
}
card->shutdown = 1;
/* replace file->f_op with special dummy operations */
list_for_each_entry(mfile, &card->files_list, list) {
/* it's critical part, use endless loop */
/* we have no room to fail */
mfile->disconnected_f_op = mfile->file->f_op;
spin_lock(&shutdown_lock);
list_add(&mfile->shutdown_list, &shutdown_files);
spin_unlock(&shutdown_lock);
mfile->file->f_op = &snd_shutdown_f_ops;
fops_get(mfile->file->f_op);
}
spin_unlock(&card->files_lock);
/* notify all connected devices about disconnection */
/* at this point, they cannot respond to any calls except release() */
@ -544,10 +537,10 @@ void snd_card_disconnect(struct snd_card *card)
}
/* disable fops (user space) operations for ALSA API */
mutex_lock(&snd_card_mutex);
snd_cards[card->number] = NULL;
clear_bit(card->number, snd_cards_lock);
mutex_unlock(&snd_card_mutex);
scoped_guard(mutex, &snd_card_mutex) {
snd_cards[card->number] = NULL;
clear_bit(card->number, snd_cards_lock);
}
#ifdef CONFIG_PM
wake_up(&card->power_sleep);
@ -569,11 +562,10 @@ void snd_card_disconnect_sync(struct snd_card *card)
{
snd_card_disconnect(card);
spin_lock_irq(&card->files_lock);
guard(spinlock_irq)(&card->files_lock);
wait_event_lock_irq(card->remove_sleep,
list_empty(&card->files_list),
card->files_lock);
spin_unlock_irq(&card->files_lock);
}
EXPORT_SYMBOL_GPL(snd_card_disconnect_sync);
@ -767,9 +759,8 @@ void snd_card_set_id(struct snd_card *card, const char *nid)
/* check if user specified own card->id */
if (card->id[0] != '\0')
return;
mutex_lock(&snd_card_mutex);
guard(mutex)(&snd_card_mutex);
snd_card_set_id_no_lock(card, nid, nid);
mutex_unlock(&snd_card_mutex);
}
EXPORT_SYMBOL(snd_card_set_id);
@ -797,14 +788,11 @@ static ssize_t id_store(struct device *dev, struct device_attribute *attr,
}
memcpy(buf1, buf, copy);
buf1[copy] = '\0';
mutex_lock(&snd_card_mutex);
if (!card_id_ok(NULL, buf1)) {
mutex_unlock(&snd_card_mutex);
guard(mutex)(&snd_card_mutex);
if (!card_id_ok(NULL, buf1))
return -EEXIST;
}
strcpy(card->id, buf1);
snd_info_card_id_change(card);
mutex_unlock(&snd_card_mutex);
return count;
}
@ -897,26 +885,27 @@ int snd_card_register(struct snd_card *card)
err = snd_device_register_all(card);
if (err < 0)
return err;
mutex_lock(&snd_card_mutex);
if (snd_cards[card->number]) {
/* already registered */
mutex_unlock(&snd_card_mutex);
return snd_info_card_register(card); /* register pending info */
scoped_guard(mutex, &snd_card_mutex) {
if (snd_cards[card->number]) {
/* already registered */
return snd_info_card_register(card); /* register pending info */
}
if (*card->id) {
/* make a unique id name from the given string */
char tmpid[sizeof(card->id)];
memcpy(tmpid, card->id, sizeof(card->id));
snd_card_set_id_no_lock(card, tmpid, tmpid);
} else {
/* create an id from either shortname or longname */
const char *src;
src = *card->shortname ? card->shortname : card->longname;
snd_card_set_id_no_lock(card, src,
retrieve_id_from_card_name(src));
}
snd_cards[card->number] = card;
}
if (*card->id) {
/* make a unique id name from the given string */
char tmpid[sizeof(card->id)];
memcpy(tmpid, card->id, sizeof(card->id));
snd_card_set_id_no_lock(card, tmpid, tmpid);
} else {
/* create an id from either shortname or longname */
const char *src;
src = *card->shortname ? card->shortname : card->longname;
snd_card_set_id_no_lock(card, src,
retrieve_id_from_card_name(src));
}
snd_cards[card->number] = card;
mutex_unlock(&snd_card_mutex);
err = snd_info_card_register(card);
if (err < 0)
return err;
@ -937,7 +926,7 @@ static void snd_card_info_read(struct snd_info_entry *entry,
struct snd_card *card;
for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
mutex_lock(&snd_card_mutex);
guard(mutex)(&snd_card_mutex);
card = snd_cards[idx];
if (card) {
count++;
@ -949,7 +938,6 @@ static void snd_card_info_read(struct snd_info_entry *entry,
snd_iprintf(buffer, " %s\n",
card->longname);
}
mutex_unlock(&snd_card_mutex);
}
if (!count)
snd_iprintf(buffer, "--- no soundcards ---\n");
@ -962,13 +950,12 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer)
struct snd_card *card;
for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
mutex_lock(&snd_card_mutex);
guard(mutex)(&snd_card_mutex);
card = snd_cards[idx];
if (card) {
count++;
snd_iprintf(buffer, "%s\n", card->longname);
}
mutex_unlock(&snd_card_mutex);
}
if (!count) {
snd_iprintf(buffer, "--- no soundcards ---\n");
@ -985,12 +972,11 @@ static void snd_card_module_info_read(struct snd_info_entry *entry,
struct snd_card *card;
for (idx = 0; idx < SNDRV_CARDS; idx++) {
mutex_lock(&snd_card_mutex);
guard(mutex)(&snd_card_mutex);
card = snd_cards[idx];
if (card)
snd_iprintf(buffer, "%2i %s\n",
idx, card->module->name);
mutex_unlock(&snd_card_mutex);
}
}
#endif
@ -1072,15 +1058,13 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
mfile->file = file;
mfile->disconnected_f_op = NULL;
INIT_LIST_HEAD(&mfile->shutdown_list);
spin_lock(&card->files_lock);
guard(spinlock)(&card->files_lock);
if (card->shutdown) {
spin_unlock(&card->files_lock);
kfree(mfile);
return -ENODEV;
}
list_add(&mfile->list, &card->files_list);
get_device(&card->card_dev);
spin_unlock(&card->files_lock);
return 0;
}
EXPORT_SYMBOL(snd_card_file_add);
@ -1102,22 +1086,21 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
{
struct snd_monitor_file *mfile, *found = NULL;
spin_lock(&card->files_lock);
list_for_each_entry(mfile, &card->files_list, list) {
if (mfile->file == file) {
list_del(&mfile->list);
spin_lock(&shutdown_lock);
list_del(&mfile->shutdown_list);
spin_unlock(&shutdown_lock);
if (mfile->disconnected_f_op)
fops_put(mfile->disconnected_f_op);
found = mfile;
break;
scoped_guard(spinlock, &card->files_lock) {
list_for_each_entry(mfile, &card->files_list, list) {
if (mfile->file == file) {
list_del(&mfile->list);
scoped_guard(spinlock, &shutdown_lock)
list_del(&mfile->shutdown_list);
if (mfile->disconnected_f_op)
fops_put(mfile->disconnected_f_op);
found = mfile;
break;
}
}
if (list_empty(&card->files_list))
wake_up_all(&card->remove_sleep);
}
if (list_empty(&card->files_list))
wake_up_all(&card->remove_sleep);
spin_unlock(&card->files_lock);
if (!found) {
dev_err(card->dev, "card file remove problem (%p)\n", file);
return -ENOENT;

View File

@ -42,11 +42,9 @@ static int snd_jack_dev_disconnect(struct snd_device *device)
#ifdef CONFIG_SND_JACK_INPUT_DEV
struct snd_jack *jack = device->device_data;
mutex_lock(&jack->input_dev_lock);
if (!jack->input_dev) {
mutex_unlock(&jack->input_dev_lock);
guard(mutex)(&jack->input_dev_lock);
if (!jack->input_dev)
return 0;
}
/* If the input device is registered with the input subsystem
* then we need to use a different deallocator. */
@ -55,7 +53,6 @@ static int snd_jack_dev_disconnect(struct snd_device *device)
else
input_free_device(jack->input_dev);
jack->input_dev = NULL;
mutex_unlock(&jack->input_dev_lock);
#endif /* CONFIG_SND_JACK_INPUT_DEV */
return 0;
}
@ -92,11 +89,9 @@ static int snd_jack_dev_register(struct snd_device *device)
snprintf(jack->name, sizeof(jack->name), "%s %s",
card->shortname, jack->id);
mutex_lock(&jack->input_dev_lock);
if (!jack->input_dev) {
mutex_unlock(&jack->input_dev_lock);
guard(mutex)(&jack->input_dev_lock);
if (!jack->input_dev)
return 0;
}
jack->input_dev->name = jack->name;
@ -121,7 +116,6 @@ static int snd_jack_dev_register(struct snd_device *device)
if (err == 0)
jack->registered = 1;
mutex_unlock(&jack->input_dev_lock);
return err;
}
#endif /* CONFIG_SND_JACK_INPUT_DEV */
@ -586,14 +580,9 @@ EXPORT_SYMBOL(snd_jack_new);
void snd_jack_set_parent(struct snd_jack *jack, struct device *parent)
{
WARN_ON(jack->registered);
mutex_lock(&jack->input_dev_lock);
if (!jack->input_dev) {
mutex_unlock(&jack->input_dev_lock);
return;
}
jack->input_dev->dev.parent = parent;
mutex_unlock(&jack->input_dev_lock);
guard(mutex)(&jack->input_dev_lock);
if (jack->input_dev)
jack->input_dev->dev.parent = parent;
}
EXPORT_SYMBOL(snd_jack_set_parent);

View File

@ -130,13 +130,12 @@ static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer)
if (mixer == NULL)
return -EIO;
mutex_lock(&mixer->reg_mutex);
guard(mutex)(&mixer->reg_mutex);
for (chn = 0; chn < 31; chn++) {
pslot = &mixer->slots[chn];
if (pslot->put_volume || pslot->put_recsrc)
result |= 1 << chn;
}
mutex_unlock(&mixer->reg_mutex);
return result;
}
@ -148,13 +147,12 @@ static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer)
if (mixer == NULL)
return -EIO;
mutex_lock(&mixer->reg_mutex);
guard(mutex)(&mixer->reg_mutex);
for (chn = 0; chn < 31; chn++) {
pslot = &mixer->slots[chn];
if (pslot->put_volume && pslot->stereo)
result |= 1 << chn;
}
mutex_unlock(&mixer->reg_mutex);
return result;
}
@ -165,7 +163,7 @@ static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
if (mixer == NULL)
return -EIO;
mutex_lock(&mixer->reg_mutex);
guard(mutex)(&mixer->reg_mutex);
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
result = mixer->mask_recsrc;
} else {
@ -177,7 +175,6 @@ static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
result |= 1 << chn;
}
}
mutex_unlock(&mixer->reg_mutex);
return result;
}
@ -188,12 +185,12 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
if (mixer == NULL)
return -EIO;
mutex_lock(&mixer->reg_mutex);
guard(mutex)(&mixer->reg_mutex);
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
unsigned int index;
result = mixer->get_recsrc(fmixer, &index);
if (result < 0)
goto unlock;
return result;
result = 1 << index;
} else {
struct snd_mixer_oss_slot *pslot;
@ -209,8 +206,6 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
}
}
mixer->oss_recsrc = result;
unlock:
mutex_unlock(&mixer->reg_mutex);
return result;
}
@ -224,7 +219,7 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr
if (mixer == NULL)
return -EIO;
mutex_lock(&mixer->reg_mutex);
guard(mutex)(&mixer->reg_mutex);
if (mixer->get_recsrc && mixer->put_recsrc) { /* exclusive input */
if (recsrc & ~mixer->oss_recsrc)
recsrc &= ~mixer->oss_recsrc;
@ -250,7 +245,6 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr
}
}
}
mutex_unlock(&mixer->reg_mutex);
return result;
}
@ -262,7 +256,7 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
if (mixer == NULL || slot > 30)
return -EIO;
mutex_lock(&mixer->reg_mutex);
guard(mutex)(&mixer->reg_mutex);
pslot = &mixer->slots[slot];
left = pslot->volume[0];
right = pslot->volume[1];
@ -270,21 +264,15 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
result = pslot->get_volume(fmixer, pslot, &left, &right);
if (!pslot->stereo)
right = left;
if (snd_BUG_ON(left < 0 || left > 100)) {
result = -EIO;
goto unlock;
}
if (snd_BUG_ON(right < 0 || right > 100)) {
result = -EIO;
goto unlock;
}
if (snd_BUG_ON(left < 0 || left > 100))
return -EIO;
if (snd_BUG_ON(right < 0 || right > 100))
return -EIO;
if (result >= 0) {
pslot->volume[0] = left;
pslot->volume[1] = right;
result = (left & 0xff) | ((right & 0xff) << 8);
}
unlock:
mutex_unlock(&mixer->reg_mutex);
return result;
}
@ -297,7 +285,7 @@ static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
if (mixer == NULL || slot > 30)
return -EIO;
mutex_lock(&mixer->reg_mutex);
guard(mutex)(&mixer->reg_mutex);
pslot = &mixer->slots[slot];
if (left > 100)
left = 100;
@ -308,12 +296,10 @@ static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
if (pslot->put_volume)
result = pslot->put_volume(fmixer, pslot, left, right);
if (result < 0)
goto unlock;
return result;
pslot->volume[0] = left;
pslot->volume[1] = right;
result = (left & 0xff) | ((right & 0xff) << 8);
unlock:
mutex_unlock(&mixer->reg_mutex);
return result;
}
@ -532,37 +518,31 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,
unsigned int numid,
int *left, int *right)
{
struct snd_ctl_elem_info *uinfo;
struct snd_ctl_elem_value *uctl;
struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
struct snd_kcontrol *kctl;
struct snd_card *card = fmixer->card;
if (numid == ID_UNKNOWN)
return;
down_read(&card->controls_rwsem);
guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_numid_locked(card, numid);
if (!kctl) {
up_read(&card->controls_rwsem);
if (!kctl)
return;
}
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL)
goto __unalloc;
return;
if (kctl->info(kctl, uinfo))
goto __unalloc;
return;
if (kctl->get(kctl, uctl))
goto __unalloc;
return;
if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
goto __unalloc;
return;
*left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]);
if (uinfo->count > 1)
*right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]);
__unalloc:
up_read(&card->controls_rwsem);
kfree(uctl);
kfree(uinfo);
}
static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
@ -571,27 +551,25 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
int *left, int *right,
int route)
{
struct snd_ctl_elem_info *uinfo;
struct snd_ctl_elem_value *uctl;
struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
struct snd_kcontrol *kctl;
struct snd_card *card = fmixer->card;
if (numid == ID_UNKNOWN)
return;
down_read(&card->controls_rwsem);
guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_numid_locked(card, numid);
if (!kctl) {
up_read(&card->controls_rwsem);
if (!kctl)
return;
}
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL)
goto __unalloc;
return;
if (kctl->info(kctl, uinfo))
goto __unalloc;
return;
if (kctl->get(kctl, uctl))
goto __unalloc;
return;
if (!uctl->value.integer.value[0]) {
*left = 0;
if (uinfo->count == 1)
@ -599,10 +577,6 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
}
if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1])
*right = 0;
__unalloc:
up_read(&card->controls_rwsem);
kfree(uctl);
kfree(uinfo);
}
static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer,
@ -636,41 +610,35 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
unsigned int numid,
int left, int right)
{
struct snd_ctl_elem_info *uinfo;
struct snd_ctl_elem_value *uctl;
struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
struct snd_kcontrol *kctl;
struct snd_card *card = fmixer->card;
int res;
if (numid == ID_UNKNOWN)
return;
down_read(&card->controls_rwsem);
guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_numid_locked(card, numid);
if (!kctl) {
up_read(&card->controls_rwsem);
if (!kctl)
return;
}
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL)
goto __unalloc;
return;
if (kctl->info(kctl, uinfo))
goto __unalloc;
return;
if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
goto __unalloc;
return;
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);
res = kctl->put(kctl, uctl);
if (res < 0)
goto __unalloc;
return;
if (res > 0)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
__unalloc:
up_read(&card->controls_rwsem);
kfree(uctl);
kfree(uinfo);
}
static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
@ -679,26 +647,24 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
int left, int right,
int route)
{
struct snd_ctl_elem_info *uinfo;
struct snd_ctl_elem_value *uctl;
struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
struct snd_kcontrol *kctl;
struct snd_card *card = fmixer->card;
int res;
if (numid == ID_UNKNOWN)
return;
down_read(&card->controls_rwsem);
guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_numid_locked(card, numid);
if (!kctl) {
up_read(&card->controls_rwsem);
if (!kctl)
return;
}
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL)
goto __unalloc;
return;
if (kctl->info(kctl, uinfo))
goto __unalloc;
return;
if (uinfo->count > 1) {
uctl->value.integer.value[0] = left > 0 ? 1 : 0;
uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0;
@ -711,13 +677,9 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
}
res = kctl->put(kctl, uctl);
if (res < 0)
goto __unalloc;
return;
if (res > 0)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
__unalloc:
up_read(&card->controls_rwsem);
kfree(uctl);
kfree(uinfo);
}
static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
@ -822,28 +784,24 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
struct snd_kcontrol *kctl;
struct snd_mixer_oss_slot *pslot;
struct slot *slot;
struct snd_ctl_elem_info *uinfo;
struct snd_ctl_elem_value *uctl;
struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
int err, idx;
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL) {
err = -ENOMEM;
goto __free_only;
}
down_read(&card->controls_rwsem);
if (uinfo == NULL || uctl == NULL)
return -ENOMEM;
guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
if (! kctl) {
err = -ENOENT;
goto __unlock;
}
if (!kctl)
return -ENOENT;
err = kctl->info(kctl, uinfo);
if (err < 0)
goto __unlock;
return err;
err = kctl->get(kctl, uctl);
if (err < 0)
goto __unlock;
return err;
for (idx = 0; idx < 32; idx++) {
if (!(mixer->mask_recsrc & (1 << idx)))
continue;
@ -858,13 +816,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
break;
}
}
err = 0;
__unlock:
up_read(&card->controls_rwsem);
__free_only:
kfree(uctl);
kfree(uinfo);
return err;
return 0;
}
static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int active_index)
@ -874,26 +826,22 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
struct snd_kcontrol *kctl;
struct snd_mixer_oss_slot *pslot;
struct slot *slot = NULL;
struct snd_ctl_elem_info *uinfo;
struct snd_ctl_elem_value *uctl;
struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
int err;
unsigned int idx;
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL) {
err = -ENOMEM;
goto __free_only;
}
down_read(&card->controls_rwsem);
if (uinfo == NULL || uctl == NULL)
return -ENOMEM;
guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
if (! kctl) {
err = -ENOENT;
goto __unlock;
}
if (!kctl)
return -ENOENT;
err = kctl->info(kctl, uinfo);
if (err < 0)
goto __unlock;
return err;
for (idx = 0; idx < 32; idx++) {
if (!(mixer->mask_recsrc & (1 << idx)))
continue;
@ -907,20 +855,14 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
break;
slot = NULL;
}
if (! slot)
goto __unlock;
if (!slot)
return 0;
for (idx = 0; idx < uinfo->count; idx++)
uctl->value.enumerated.item[idx] = slot->capture_item;
err = kctl->put(kctl, uctl);
if (err > 0)
snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
err = 0;
__unlock:
up_read(&card->controls_rwsem);
__free_only:
kfree(uctl);
kfree(uinfo);
return err;
return 0;
}
struct snd_mixer_oss_assign_table {
@ -931,34 +873,26 @@ struct snd_mixer_oss_assign_table {
static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *slot, const char *name, int index, int item)
{
struct snd_ctl_elem_info *info;
struct snd_ctl_elem_info *info __free(kfree) = NULL;
struct snd_kcontrol *kcontrol;
struct snd_card *card = mixer->card;
int err;
down_read(&card->controls_rwsem);
kcontrol = snd_mixer_oss_test_id(mixer, name, index);
if (kcontrol == NULL) {
up_read(&card->controls_rwsem);
return 0;
scoped_guard(rwsem_read, &card->controls_rwsem) {
kcontrol = snd_mixer_oss_test_id(mixer, name, index);
if (kcontrol == NULL)
return 0;
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
err = kcontrol->info(kcontrol, info);
if (err < 0)
return err;
slot->numid[item] = kcontrol->id.numid;
}
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (! info) {
up_read(&card->controls_rwsem);
return -ENOMEM;
}
err = kcontrol->info(kcontrol, info);
if (err < 0) {
up_read(&card->controls_rwsem);
kfree(info);
return err;
}
slot->numid[item] = kcontrol->id.numid;
up_read(&card->controls_rwsem);
if (info->count > slot->channels)
slot->channels = info->count;
slot->present |= 1 << item;
kfree(info);
return 0;
}
@ -1068,24 +1002,19 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer,
memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */
if (snd_mixer_oss_build_test_all(mixer, ptr, &slot))
return 0;
down_read(&mixer->card->controls_rwsem);
guard(rwsem_read)(&mixer->card->controls_rwsem);
kctl = NULL;
if (!ptr->index)
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
if (kctl) {
struct snd_ctl_elem_info *uinfo;
struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
if (! uinfo) {
up_read(&mixer->card->controls_rwsem);
if (!uinfo)
return -ENOMEM;
}
if (kctl->info(kctl, uinfo)) {
up_read(&mixer->card->controls_rwsem);
kfree(uinfo);
if (kctl->info(kctl, uinfo))
return 0;
}
strcpy(str, ptr->name);
if (!strcmp(str, "Master"))
strcpy(str, "Mix");
@ -1097,20 +1026,15 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer,
} else {
for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) {
uinfo->value.enumerated.item = slot.capture_item;
if (kctl->info(kctl, uinfo)) {
up_read(&mixer->card->controls_rwsem);
kfree(uinfo);
if (kctl->info(kctl, uinfo))
return 0;
}
if (!strcmp(uinfo->value.enumerated.name, str)) {
slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
break;
}
}
}
kfree(uinfo);
}
up_read(&mixer->card->controls_rwsem);
if (slot.present != 0) {
pslot = kmalloc(sizeof(slot), GFP_KERNEL);
if (! pslot)
@ -1183,7 +1107,7 @@ static void snd_mixer_oss_proc_read(struct snd_info_entry *entry,
struct snd_mixer_oss *mixer = entry->private_data;
int i;
mutex_lock(&mixer->reg_mutex);
guard(mutex)(&mixer->reg_mutex);
for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) {
struct slot *p;
@ -1198,7 +1122,6 @@ static void snd_mixer_oss_proc_read(struct snd_info_entry *entry,
else
snd_iprintf(buffer, "\"\" 0\n");
}
mutex_unlock(&mixer->reg_mutex);
}
static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
@ -1225,9 +1148,8 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
cptr = snd_info_get_str(str, cptr, sizeof(str));
if (! *str) {
/* remove the entry */
mutex_lock(&mixer->reg_mutex);
mixer_slot_clear(&mixer->slots[ch]);
mutex_unlock(&mixer->reg_mutex);
scoped_guard(mutex, &mixer->reg_mutex)
mixer_slot_clear(&mixer->slots[ch]);
continue;
}
snd_info_get_str(idxstr, cptr, sizeof(idxstr));
@ -1236,28 +1158,27 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
pr_err("ALSA: mixer_oss: invalid index %d\n", idx);
continue;
}
mutex_lock(&mixer->reg_mutex);
slot = (struct slot *)mixer->slots[ch].private_data;
if (slot && slot->assigned &&
slot->assigned->index == idx && ! strcmp(slot->assigned->name, str))
/* not changed */
goto __unlock;
tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
if (!tbl)
goto __unlock;
tbl->oss_id = ch;
tbl->name = kstrdup(str, GFP_KERNEL);
if (! tbl->name) {
kfree(tbl);
goto __unlock;
scoped_guard(mutex, &mixer->reg_mutex) {
slot = (struct slot *)mixer->slots[ch].private_data;
if (slot && slot->assigned &&
slot->assigned->index == idx && !strcmp(slot->assigned->name, str))
/* not changed */
break;
tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
if (!tbl)
break;
tbl->oss_id = ch;
tbl->name = kstrdup(str, GFP_KERNEL);
if (!tbl->name) {
kfree(tbl);
break;
}
tbl->index = idx;
if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) {
kfree(tbl->name);
kfree(tbl);
}
}
tbl->index = idx;
if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) {
kfree(tbl->name);
kfree(tbl);
}
__unlock:
mutex_unlock(&mixer->reg_mutex);
}
}

View File

@ -377,7 +377,7 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
snd_pcm_hw_param_t var, unsigned int best,
int *dir)
{
struct snd_pcm_hw_params *save = NULL;
struct snd_pcm_hw_params *save __free(kfree) = NULL;
int v;
unsigned int saved_min;
int last = 0;
@ -404,38 +404,30 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
saved_min = min;
min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
if (min >= 0) {
struct snd_pcm_hw_params *params1;
struct snd_pcm_hw_params *params1 __free(kfree) = NULL;
if (max < 0)
goto _end;
if ((unsigned int)min == saved_min && mindir == valdir)
goto _end;
params1 = kmalloc(sizeof(*params1), GFP_KERNEL);
if (params1 == NULL) {
kfree(save);
if (params1 == NULL)
return -ENOMEM;
}
*params1 = *save;
max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
if (max < 0) {
kfree(params1);
if (max < 0)
goto _end;
}
if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
*params = *params1;
last = 1;
}
kfree(params1);
} else {
*params = *save;
max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
if (max < 0) {
kfree(save);
if (max < 0)
return max;
}
last = 1;
}
_end:
kfree(save);
if (last)
v = snd_pcm_hw_param_last(pcm, params, var, dir);
else
@ -789,7 +781,7 @@ static int choose_rate(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, unsigned int best_rate)
{
const struct snd_interval *it;
struct snd_pcm_hw_params *save;
struct snd_pcm_hw_params *save __free(kfree) = NULL;
unsigned int rate, prev;
save = kmalloc(sizeof(*save), GFP_KERNEL);
@ -808,10 +800,8 @@ static int choose_rate(struct snd_pcm_substream *substream,
ret = snd_pcm_hw_param_set(substream, params,
SNDRV_PCM_HW_PARAM_RATE,
rate, 0);
if (ret == (int)rate) {
kfree(save);
if (ret == (int)rate)
return rate;
}
*params = *save;
}
prev = rate;
@ -821,7 +811,6 @@ static int choose_rate(struct snd_pcm_substream *substream,
}
/* not found, use the nearest rate */
kfree(save);
return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
}
@ -1634,9 +1623,8 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
break;
result = 0;
set_current_state(TASK_INTERRUPTIBLE);
snd_pcm_stream_lock_irq(substream);
state = runtime->state;
snd_pcm_stream_unlock_irq(substream);
scoped_guard(pcm_stream_lock_irq, substream)
state = runtime->state;
if (state != SNDRV_PCM_STATE_RUNNING) {
set_current_state(TASK_RUNNING);
break;
@ -1847,7 +1835,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
struct snd_pcm_substream *substream;
int err;
int direct;
struct snd_pcm_hw_params *params;
struct snd_pcm_hw_params *params __free(kfree) = NULL;
unsigned int formats = 0;
const struct snd_mask *format_mask;
int fmt;
@ -1873,7 +1861,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
_snd_pcm_hw_params_any(params);
err = snd_pcm_hw_refine(substream, params);
if (err < 0)
goto error;
return err;
format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
for (fmt = 0; fmt < 32; ++fmt) {
if (snd_mask_test(format_mask, fmt)) {
@ -1883,9 +1871,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
}
}
error:
kfree(params);
return err < 0 ? err : formats;
return formats;
}
static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)
@ -2347,7 +2333,7 @@ static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream,
{
struct snd_pcm_oss_setup *setup;
mutex_lock(&pcm->streams[stream].oss.setup_mutex);
guard(mutex)(&pcm->streams[stream].oss.setup_mutex);
do {
for (setup = pcm->streams[stream].oss.setup_list; setup;
setup = setup->next) {
@ -2358,7 +2344,6 @@ static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream,
out:
if (setup)
*rsetup = *setup;
mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
}
static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream)
@ -2853,23 +2838,23 @@ static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait)
if (psubstream != NULL) {
struct snd_pcm_runtime *runtime = psubstream->runtime;
poll_wait(file, &runtime->sleep, wait);
snd_pcm_stream_lock_irq(psubstream);
if (runtime->state != SNDRV_PCM_STATE_DRAINING &&
(runtime->state != SNDRV_PCM_STATE_RUNNING ||
snd_pcm_oss_playback_ready(psubstream)))
mask |= EPOLLOUT | EPOLLWRNORM;
snd_pcm_stream_unlock_irq(psubstream);
scoped_guard(pcm_stream_lock_irq, psubstream) {
if (runtime->state != SNDRV_PCM_STATE_DRAINING &&
(runtime->state != SNDRV_PCM_STATE_RUNNING ||
snd_pcm_oss_playback_ready(psubstream)))
mask |= EPOLLOUT | EPOLLWRNORM;
}
}
if (csubstream != NULL) {
struct snd_pcm_runtime *runtime = csubstream->runtime;
snd_pcm_state_t ostate;
poll_wait(file, &runtime->sleep, wait);
snd_pcm_stream_lock_irq(csubstream);
ostate = runtime->state;
if (ostate != SNDRV_PCM_STATE_RUNNING ||
snd_pcm_oss_capture_ready(csubstream))
mask |= EPOLLIN | EPOLLRDNORM;
snd_pcm_stream_unlock_irq(csubstream);
scoped_guard(pcm_stream_lock_irq, csubstream) {
ostate = runtime->state;
if (ostate != SNDRV_PCM_STATE_RUNNING ||
snd_pcm_oss_capture_ready(csubstream))
mask |= EPOLLIN | EPOLLRDNORM;
}
if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) {
struct snd_pcm_oss_file ofile;
memset(&ofile, 0, sizeof(ofile));
@ -2964,7 +2949,7 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry,
{
struct snd_pcm_str *pstr = entry->private_data;
struct snd_pcm_oss_setup *setup = pstr->oss.setup_list;
mutex_lock(&pstr->oss.setup_mutex);
guard(mutex)(&pstr->oss.setup_mutex);
while (setup) {
snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n",
setup->task_name,
@ -2978,7 +2963,6 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry,
setup->nosilence ? " no-silence" : "");
setup = setup->next;
}
mutex_unlock(&pstr->oss.setup_mutex);
}
static void snd_pcm_oss_proc_free_setup_list(struct snd_pcm_str * pstr)
@ -3004,12 +2988,11 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
struct snd_pcm_oss_setup *setup, *setup1, template;
while (!snd_info_get_line(buffer, line, sizeof(line))) {
mutex_lock(&pstr->oss.setup_mutex);
guard(mutex)(&pstr->oss.setup_mutex);
memset(&template, 0, sizeof(template));
ptr = snd_info_get_str(task_name, line, sizeof(task_name));
if (!strcmp(task_name, "clear") || !strcmp(task_name, "erase")) {
snd_pcm_oss_proc_free_setup_list(pstr);
mutex_unlock(&pstr->oss.setup_mutex);
continue;
}
for (setup = pstr->oss.setup_list; setup; setup = setup->next) {
@ -3049,7 +3032,6 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
setup = kmalloc(sizeof(*setup), GFP_KERNEL);
if (! setup) {
buffer->error = -ENOMEM;
mutex_unlock(&pstr->oss.setup_mutex);
return;
}
if (pstr->oss.setup_list == NULL)
@ -3063,12 +3045,10 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
if (! template.task_name) {
kfree(setup);
buffer->error = -ENOMEM;
mutex_unlock(&pstr->oss.setup_mutex);
return;
}
}
*setup = template;
mutex_unlock(&pstr->oss.setup_mutex);
}
}

View File

@ -91,9 +91,8 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
if (get_user(device, (int __user *)arg))
return -EFAULT;
mutex_lock(&register_mutex);
device = snd_pcm_next(card, device);
mutex_unlock(&register_mutex);
scoped_guard(mutex, &register_mutex)
device = snd_pcm_next(card, device);
if (put_user(device, (int __user *)arg))
return -EFAULT;
return 0;
@ -106,7 +105,6 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
struct snd_pcm *pcm;
struct snd_pcm_str *pstr;
struct snd_pcm_substream *substream;
int err;
info = (struct snd_pcm_info __user *)arg;
if (get_user(device, &info->device))
@ -118,35 +116,23 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
stream = array_index_nospec(stream, 2);
if (get_user(subdevice, &info->subdevice))
return -EFAULT;
mutex_lock(&register_mutex);
guard(mutex)(&register_mutex);
pcm = snd_pcm_get(card, device);
if (pcm == NULL) {
err = -ENXIO;
goto _error;
}
if (pcm == NULL)
return -ENXIO;
pstr = &pcm->streams[stream];
if (pstr->substream_count == 0) {
err = -ENOENT;
goto _error;
}
if (subdevice >= pstr->substream_count) {
err = -ENXIO;
goto _error;
}
if (pstr->substream_count == 0)
return -ENOENT;
if (subdevice >= pstr->substream_count)
return -ENXIO;
for (substream = pstr->substream; substream;
substream = substream->next)
if (substream->number == (int)subdevice)
break;
if (substream == NULL) {
err = -ENXIO;
goto _error;
}
mutex_lock(&pcm->open_mutex);
err = snd_pcm_info_user(substream, info);
mutex_unlock(&pcm->open_mutex);
_error:
mutex_unlock(&register_mutex);
return err;
if (substream == NULL)
return -ENXIO;
guard(mutex)(&pcm->open_mutex);
return snd_pcm_info_user(substream, info);
}
case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE:
{
@ -225,9 +211,11 @@ static const char * const snd_pcm_format_names[] = {
*/
const char *snd_pcm_format_name(snd_pcm_format_t format)
{
if ((__force unsigned int)format >= ARRAY_SIZE(snd_pcm_format_names))
unsigned int format_num = (__force unsigned int)format;
if (format_num >= ARRAY_SIZE(snd_pcm_format_names) || !snd_pcm_format_names[format_num])
return "Unknown";
return snd_pcm_format_names[(__force unsigned int)format];
return snd_pcm_format_names[format_num];
}
EXPORT_SYMBOL_GPL(snd_pcm_format_name);
@ -340,7 +328,7 @@ static const char *snd_pcm_oss_format_name(int format)
static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
struct snd_info_buffer *buffer)
{
struct snd_pcm_info *info;
struct snd_pcm_info *info __free(kfree) = NULL;
int err;
if (! substream)
@ -353,7 +341,6 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
err = snd_pcm_info(substream, info);
if (err < 0) {
snd_iprintf(buffer, "error %d\n", err);
kfree(info);
return;
}
snd_iprintf(buffer, "card: %d\n", info->card);
@ -367,7 +354,6 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
snd_iprintf(buffer, "subclass: %d\n", info->dev_subclass);
snd_iprintf(buffer, "subdevices_count: %d\n", info->subdevices_count);
snd_iprintf(buffer, "subdevices_avail: %d\n", info->subdevices_avail);
kfree(info);
}
static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry,
@ -389,15 +375,15 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
struct snd_pcm_substream *substream = entry->private_data;
struct snd_pcm_runtime *runtime;
mutex_lock(&substream->pcm->open_mutex);
guard(mutex)(&substream->pcm->open_mutex);
runtime = substream->runtime;
if (!runtime) {
snd_iprintf(buffer, "closed\n");
goto unlock;
return;
}
if (runtime->state == SNDRV_PCM_STATE_OPEN) {
snd_iprintf(buffer, "no setup\n");
goto unlock;
return;
}
snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access));
snd_iprintf(buffer, "format: %s\n", snd_pcm_format_name(runtime->format));
@ -416,8 +402,6 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames);
}
#endif
unlock:
mutex_unlock(&substream->pcm->open_mutex);
}
static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
@ -426,15 +410,15 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
struct snd_pcm_substream *substream = entry->private_data;
struct snd_pcm_runtime *runtime;
mutex_lock(&substream->pcm->open_mutex);
guard(mutex)(&substream->pcm->open_mutex);
runtime = substream->runtime;
if (!runtime) {
snd_iprintf(buffer, "closed\n");
goto unlock;
return;
}
if (runtime->state == SNDRV_PCM_STATE_OPEN) {
snd_iprintf(buffer, "no setup\n");
goto unlock;
return;
}
snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode));
snd_iprintf(buffer, "period_step: %u\n", runtime->period_step);
@ -444,8 +428,6 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold);
snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size);
snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary);
unlock:
mutex_unlock(&substream->pcm->open_mutex);
}
static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
@ -456,17 +438,17 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
struct snd_pcm_status64 status;
int err;
mutex_lock(&substream->pcm->open_mutex);
guard(mutex)(&substream->pcm->open_mutex);
runtime = substream->runtime;
if (!runtime) {
snd_iprintf(buffer, "closed\n");
goto unlock;
return;
}
memset(&status, 0, sizeof(status));
err = snd_pcm_status64(substream, &status);
if (err < 0) {
snd_iprintf(buffer, "error %d\n", err);
goto unlock;
return;
}
snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state));
snd_iprintf(buffer, "owner_pid : %d\n", pid_vnr(substream->pid));
@ -480,8 +462,6 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "-----\n");
snd_iprintf(buffer, "hw_ptr : %ld\n", runtime->status->hw_ptr);
snd_iprintf(buffer, "appl_ptr : %ld\n", runtime->control->appl_ptr);
unlock:
mutex_unlock(&substream->pcm->open_mutex);
}
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
@ -1009,9 +989,8 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
kfree(runtime->hw_constraints.rules);
/* Avoid concurrent access to runtime via PCM timer interface */
if (substream->timer) {
spin_lock_irq(&substream->timer->lock);
substream->runtime = NULL;
spin_unlock_irq(&substream->timer->lock);
scoped_guard(spinlock_irq, &substream->timer->lock)
substream->runtime = NULL;
} else {
substream->runtime = NULL;
}
@ -1068,10 +1047,10 @@ static int snd_pcm_dev_register(struct snd_device *device)
return -ENXIO;
pcm = device->device_data;
mutex_lock(&register_mutex);
guard(mutex)(&register_mutex);
err = snd_pcm_add(pcm);
if (err)
goto unlock;
return err;
for (cidx = 0; cidx < 2; cidx++) {
int devtype = -1;
if (pcm->streams[cidx].substream == NULL)
@ -1090,7 +1069,7 @@ static int snd_pcm_dev_register(struct snd_device *device)
pcm->streams[cidx].dev);
if (err < 0) {
list_del_init(&pcm->list);
goto unlock;
return err;
}
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
@ -1098,9 +1077,6 @@ static int snd_pcm_dev_register(struct snd_device *device)
}
pcm_call_notify(pcm, n_register);
unlock:
mutex_unlock(&register_mutex);
return err;
}
@ -1110,8 +1086,8 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
struct snd_pcm_substream *substream;
int cidx;
mutex_lock(&register_mutex);
mutex_lock(&pcm->open_mutex);
guard(mutex)(&register_mutex);
guard(mutex)(&pcm->open_mutex);
wake_up(&pcm->open_wait);
list_del_init(&pcm->list);
@ -1138,8 +1114,6 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
snd_unregister_device(pcm->streams[cidx].dev);
free_chmap(&pcm->streams[cidx]);
}
mutex_unlock(&pcm->open_mutex);
mutex_unlock(&register_mutex);
return 0;
}
@ -1164,7 +1138,7 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
!notify->n_unregister ||
!notify->n_disconnect))
return -EINVAL;
mutex_lock(&register_mutex);
guard(mutex)(&register_mutex);
if (nfree) {
list_del(&notify->list);
list_for_each_entry(pcm, &snd_pcm_devices, list)
@ -1174,7 +1148,6 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
list_for_each_entry(pcm, &snd_pcm_devices, list)
notify->n_register(pcm);
}
mutex_unlock(&register_mutex);
return 0;
}
EXPORT_SYMBOL(snd_pcm_notify);
@ -1190,7 +1163,7 @@ static void snd_pcm_proc_read(struct snd_info_entry *entry,
{
struct snd_pcm *pcm;
mutex_lock(&register_mutex);
guard(mutex)(&register_mutex);
list_for_each_entry(pcm, &snd_pcm_devices, list) {
snd_iprintf(buffer, "%02i-%02i: %s : %s",
pcm->card->number, pcm->device, pcm->id, pcm->name);
@ -1202,7 +1175,6 @@ static void snd_pcm_proc_read(struct snd_info_entry *entry,
pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count);
snd_iprintf(buffer, "\n");
}
mutex_unlock(&register_mutex);
}
static struct snd_info_entry *snd_pcm_proc_entry;

View File

@ -235,7 +235,7 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
int refine,
struct snd_pcm_hw_params32 __user *data32)
{
struct snd_pcm_hw_params *data;
struct snd_pcm_hw_params *data __free(kfree) = NULL;
struct snd_pcm_runtime *runtime;
int err;
@ -248,34 +248,28 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
return -ENOMEM;
/* only fifo_size (RO from userspace) is different, so just copy all */
if (copy_from_user(data, data32, sizeof(*data32))) {
err = -EFAULT;
goto error;
}
if (copy_from_user(data, data32, sizeof(*data32)))
return -EFAULT;
if (refine) {
err = snd_pcm_hw_refine(substream, data);
if (err < 0)
goto error;
return err;
err = fixup_unreferenced_params(substream, data);
} else {
err = snd_pcm_hw_params(substream, data);
}
if (err < 0)
goto error;
return err;
if (copy_to_user(data32, data, sizeof(*data32)) ||
put_user(data->fifo_size, &data32->fifo_size)) {
err = -EFAULT;
goto error;
}
put_user(data->fifo_size, &data32->fifo_size))
return -EFAULT;
if (! refine) {
unsigned int new_boundary = recalculate_boundary(runtime);
if (new_boundary)
runtime->boundary = new_boundary;
}
error:
kfree(data);
return err;
}
@ -338,7 +332,7 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
compat_caddr_t buf;
compat_caddr_t __user *bufptr;
u32 frames;
void __user **bufs;
void __user **bufs __free(kfree) = NULL;
int err, ch, i;
if (! substream->runtime)
@ -360,10 +354,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
return -ENOMEM;
for (i = 0; i < ch; i++) {
u32 ptr;
if (get_user(ptr, bufptr)) {
kfree(bufs);
if (get_user(ptr, bufptr))
return -EFAULT;
}
bufs[i] = compat_ptr(ptr);
bufptr++;
}
@ -373,9 +365,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
err = snd_pcm_lib_readv(substream, bufs, frames);
if (err >= 0) {
if (put_user(err, &data32->result))
err = -EFAULT;
return -EFAULT;
}
kfree(bufs);
return err;
}
@ -441,22 +432,22 @@ static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream,
boundary = recalculate_boundary(runtime);
if (!boundary)
boundary = 0x7fffffff;
snd_pcm_stream_lock_irq(substream);
/* FIXME: we should consider the boundary for the sync from app */
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
control->appl_ptr = scontrol.appl_ptr;
else
scontrol.appl_ptr = control->appl_ptr % boundary;
if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = scontrol.avail_min;
else
scontrol.avail_min = control->avail_min;
sstatus.state = status->state;
sstatus.hw_ptr = status->hw_ptr % boundary;
sstatus.tstamp = status->tstamp;
sstatus.suspended_state = status->suspended_state;
sstatus.audio_tstamp = status->audio_tstamp;
snd_pcm_stream_unlock_irq(substream);
scoped_guard(pcm_stream_lock_irq, substream) {
/* FIXME: we should consider the boundary for the sync from app */
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
control->appl_ptr = scontrol.appl_ptr;
else
scontrol.appl_ptr = control->appl_ptr % boundary;
if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = scontrol.avail_min;
else
scontrol.avail_min = control->avail_min;
sstatus.state = status->state;
sstatus.hw_ptr = status->hw_ptr % boundary;
sstatus.tstamp = status->tstamp;
sstatus.suspended_state = status->suspended_state;
sstatus.audio_tstamp = status->audio_tstamp;
}
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
if (put_user(sstatus.state, &src->s.status.state) ||
@ -519,26 +510,24 @@ static int snd_pcm_ioctl_sync_ptr_buggy(struct snd_pcm_substream *substream,
if (err < 0)
return err;
}
snd_pcm_stream_lock_irq(substream);
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
err = pcm_lib_apply_appl_ptr(substream, sync_cp->appl_ptr);
if (err < 0) {
snd_pcm_stream_unlock_irq(substream);
return err;
scoped_guard(pcm_stream_lock_irq, substream) {
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
err = pcm_lib_apply_appl_ptr(substream, sync_cp->appl_ptr);
if (err < 0)
return err;
} else {
sync_cp->appl_ptr = control->appl_ptr;
}
} else {
sync_cp->appl_ptr = control->appl_ptr;
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = sync_cp->avail_min;
else
sync_cp->avail_min = control->avail_min;
sync_ptr.s.status.state = status->state;
sync_ptr.s.status.hw_ptr = status->hw_ptr;
sync_ptr.s.status.tstamp = status->tstamp;
sync_ptr.s.status.suspended_state = status->suspended_state;
sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
}
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = sync_cp->avail_min;
else
sync_cp->avail_min = control->avail_min;
sync_ptr.s.status.state = status->state;
sync_ptr.s.status.hw_ptr = status->hw_ptr;
sync_ptr.s.status.tstamp = status->tstamp;
sync_ptr.s.status.suspended_state = status->suspended_state;
sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
snd_pcm_stream_unlock_irq(substream);
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))

View File

@ -1744,8 +1744,8 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
void *arg)
{
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned long flags;
snd_pcm_stream_lock_irqsave(substream, flags);
guard(pcm_stream_lock_irqsave)(substream);
if (snd_pcm_running(substream) &&
snd_pcm_update_hw_ptr(substream) >= 0)
runtime->status->hw_ptr %= runtime->buffer_size;
@ -1753,7 +1753,6 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
runtime->status->hw_ptr = 0;
runtime->hw_ptr_wrap = 0;
}
snd_pcm_stream_unlock_irqrestore(substream, flags);
return 0;
}
@ -1899,14 +1898,11 @@ EXPORT_SYMBOL(snd_pcm_period_elapsed_under_stream_lock);
*/
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);
guard(pcm_stream_lock_irqsave)(substream);
snd_pcm_period_elapsed_under_stream_lock(substream);
snd_pcm_stream_unlock_irqrestore(substream, flags);
}
EXPORT_SYMBOL(snd_pcm_period_elapsed);

View File

@ -38,17 +38,15 @@ static void __update_allocated_size(struct snd_card *card, ssize_t bytes)
static void update_allocated_size(struct snd_card *card, ssize_t bytes)
{
mutex_lock(&card->memory_mutex);
guard(mutex)(&card->memory_mutex);
__update_allocated_size(card, bytes);
mutex_unlock(&card->memory_mutex);
}
static void decrease_allocated_size(struct snd_card *card, size_t bytes)
{
mutex_lock(&card->memory_mutex);
guard(mutex)(&card->memory_mutex);
WARN_ON(card->total_pcm_alloc_bytes < bytes);
__update_allocated_size(card, -(ssize_t)bytes);
mutex_unlock(&card->memory_mutex);
}
static int do_alloc_pages(struct snd_card *card, int type, struct device *dev,
@ -58,14 +56,12 @@ static int do_alloc_pages(struct snd_card *card, int type, struct device *dev,
int err;
/* check and reserve the requested size */
mutex_lock(&card->memory_mutex);
if (max_alloc_per_card &&
card->total_pcm_alloc_bytes + size > max_alloc_per_card) {
mutex_unlock(&card->memory_mutex);
return -ENOMEM;
scoped_guard(mutex, &card->memory_mutex) {
if (max_alloc_per_card &&
card->total_pcm_alloc_bytes + size > max_alloc_per_card)
return -ENOMEM;
__update_allocated_size(card, size);
}
__update_allocated_size(card, size);
mutex_unlock(&card->memory_mutex);
if (str == SNDRV_PCM_STREAM_PLAYBACK)
dir = DMA_TO_DEVICE;
@ -191,20 +187,20 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
size_t size;
struct snd_dma_buffer new_dmab;
mutex_lock(&substream->pcm->open_mutex);
guard(mutex)(&substream->pcm->open_mutex);
if (substream->runtime) {
buffer->error = -EBUSY;
goto unlock;
return;
}
if (!snd_info_get_line(buffer, line, sizeof(line))) {
snd_info_get_str(str, line, sizeof(str));
size = simple_strtoul(str, NULL, 10) * 1024;
if ((size != 0 && size < 8192) || size > substream->dma_max) {
buffer->error = -EINVAL;
goto unlock;
return;
}
if (substream->dma_buffer.bytes == size)
goto unlock;
return;
memset(&new_dmab, 0, sizeof(new_dmab));
new_dmab.dev = substream->dma_buffer.dev;
if (size > 0) {
@ -218,7 +214,7 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
substream->pcm->card->number, substream->pcm->device,
substream->stream ? 'c' : 'p', substream->number,
substream->pcm->name, size);
goto unlock;
return;
}
substream->buffer_bytes_max = size;
} else {
@ -230,8 +226,6 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
} else {
buffer->error = -EINVAL;
}
unlock:
mutex_unlock(&substream->pcm->open_mutex);
}
static inline void preallocate_info_init(struct snd_pcm_substream *substream)

View File

@ -236,7 +236,7 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)
int snd_pcm_info_user(struct snd_pcm_substream *substream,
struct snd_pcm_info __user * _info)
{
struct snd_pcm_info *info;
struct snd_pcm_info *info __free(kfree) = NULL;
int err;
info = kmalloc(sizeof(*info), GFP_KERNEL);
@ -247,7 +247,6 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
if (copy_to_user(_info, info, sizeof(*info)))
err = -EFAULT;
}
kfree(info);
return err;
}
@ -359,7 +358,7 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
struct snd_pcm_hw_constraints *constrs =
&substream->runtime->hw_constraints;
unsigned int k;
unsigned int *rstamps;
unsigned int *rstamps __free(kfree) = NULL;
unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
unsigned int stamp;
struct snd_pcm_hw_rule *r;
@ -435,10 +434,8 @@ retry:
}
changed = r->func(params, r);
if (changed < 0) {
err = changed;
goto out;
}
if (changed < 0)
return changed;
/*
* When the parameter is changed, notify it to the caller
@ -469,8 +466,6 @@ retry:
if (again)
goto retry;
out:
kfree(rstamps);
return err;
}
@ -576,26 +571,24 @@ EXPORT_SYMBOL(snd_pcm_hw_refine);
static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params __user * _params)
{
struct snd_pcm_hw_params *params;
struct snd_pcm_hw_params *params __free(kfree) = NULL;
int err;
params = memdup_user(_params, sizeof(*params));
if (IS_ERR(params))
return PTR_ERR(params);
return PTR_ERR(no_free_ptr(params));
err = snd_pcm_hw_refine(substream, params);
if (err < 0)
goto end;
return err;
err = fixup_unreferenced_params(substream, params);
if (err < 0)
goto end;
return err;
if (copy_to_user(_params, params, sizeof(*params)))
err = -EFAULT;
end:
kfree(params);
return err;
return -EFAULT;
return 0;
}
static int period_to_usecs(struct snd_pcm_runtime *runtime)
@ -616,10 +609,9 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
static void snd_pcm_set_state(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
snd_pcm_stream_lock_irq(substream);
guard(pcm_stream_lock_irq)(substream);
if (substream->runtime->state != SNDRV_PCM_STATE_DISCONNECTED)
__snd_pcm_set_state(substream->runtime, state);
snd_pcm_stream_unlock_irq(substream);
}
static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
@ -745,20 +737,20 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
err = snd_pcm_buffer_access_lock(runtime);
if (err < 0)
return err;
snd_pcm_stream_lock_irq(substream);
switch (runtime->state) {
case SNDRV_PCM_STATE_OPEN:
case SNDRV_PCM_STATE_SETUP:
case SNDRV_PCM_STATE_PREPARED:
if (!is_oss_stream(substream) &&
atomic_read(&substream->mmap_count))
scoped_guard(pcm_stream_lock_irq, substream) {
switch (runtime->state) {
case SNDRV_PCM_STATE_OPEN:
case SNDRV_PCM_STATE_SETUP:
case SNDRV_PCM_STATE_PREPARED:
if (!is_oss_stream(substream) &&
atomic_read(&substream->mmap_count))
err = -EBADFD;
break;
default:
err = -EBADFD;
break;
default:
err = -EBADFD;
break;
break;
}
}
snd_pcm_stream_unlock_irq(substream);
if (err)
goto unlock;
@ -869,21 +861,19 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params __user * _params)
{
struct snd_pcm_hw_params *params;
struct snd_pcm_hw_params *params __free(kfree) = NULL;
int err;
params = memdup_user(_params, sizeof(*params));
if (IS_ERR(params))
return PTR_ERR(params);
return PTR_ERR(no_free_ptr(params));
err = snd_pcm_hw_params(substream, params);
if (err < 0)
goto end;
return err;
if (copy_to_user(_params, params, sizeof(*params)))
err = -EFAULT;
end:
kfree(params);
return -EFAULT;
return err;
}
@ -910,18 +900,18 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
result = snd_pcm_buffer_access_lock(runtime);
if (result < 0)
return result;
snd_pcm_stream_lock_irq(substream);
switch (runtime->state) {
case SNDRV_PCM_STATE_SETUP:
case SNDRV_PCM_STATE_PREPARED:
if (atomic_read(&substream->mmap_count))
scoped_guard(pcm_stream_lock_irq, substream) {
switch (runtime->state) {
case SNDRV_PCM_STATE_SETUP:
case SNDRV_PCM_STATE_PREPARED:
if (atomic_read(&substream->mmap_count))
result = -EBADFD;
break;
default:
result = -EBADFD;
break;
default:
result = -EBADFD;
break;
break;
}
}
snd_pcm_stream_unlock_irq(substream);
if (result)
goto unlock;
result = do_hw_free(substream);
@ -941,12 +931,10 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
runtime = substream->runtime;
snd_pcm_stream_lock_irq(substream);
if (runtime->state == SNDRV_PCM_STATE_OPEN) {
snd_pcm_stream_unlock_irq(substream);
return -EBADFD;
scoped_guard(pcm_stream_lock_irq, substream) {
if (runtime->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
}
snd_pcm_stream_unlock_irq(substream);
if (params->tstamp_mode < 0 ||
params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST)
@ -966,24 +954,24 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
err = 0;
snd_pcm_stream_lock_irq(substream);
runtime->tstamp_mode = params->tstamp_mode;
if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12))
runtime->tstamp_type = params->tstamp_type;
runtime->period_step = params->period_step;
runtime->control->avail_min = params->avail_min;
runtime->start_threshold = params->start_threshold;
runtime->stop_threshold = params->stop_threshold;
runtime->silence_threshold = params->silence_threshold;
runtime->silence_size = params->silence_size;
params->boundary = runtime->boundary;
if (snd_pcm_running(substream)) {
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
snd_pcm_playback_silence(substream, ULONG_MAX);
err = snd_pcm_update_state(substream, runtime);
scoped_guard(pcm_stream_lock_irq, substream) {
runtime->tstamp_mode = params->tstamp_mode;
if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12))
runtime->tstamp_type = params->tstamp_type;
runtime->period_step = params->period_step;
runtime->control->avail_min = params->avail_min;
runtime->start_threshold = params->start_threshold;
runtime->stop_threshold = params->stop_threshold;
runtime->silence_threshold = params->silence_threshold;
runtime->silence_size = params->silence_size;
params->boundary = runtime->boundary;
if (snd_pcm_running(substream)) {
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
snd_pcm_playback_silence(substream, ULONG_MAX);
err = snd_pcm_update_state(substream, runtime);
}
}
snd_pcm_stream_unlock_irq(substream);
return err;
}
@ -1017,7 +1005,7 @@ int snd_pcm_status64(struct snd_pcm_substream *substream,
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_stream_lock_irq(substream);
guard(pcm_stream_lock_irq)(substream);
snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data,
&runtime->audio_tstamp_config);
@ -1038,7 +1026,7 @@ int snd_pcm_status64(struct snd_pcm_substream *substream,
status->state = runtime->state;
status->suspended_state = runtime->suspended_state;
if (status->state == SNDRV_PCM_STATE_OPEN)
goto _end;
return 0;
status->trigger_tstamp_sec = runtime->trigger_tstamp.tv_sec;
status->trigger_tstamp_nsec = runtime->trigger_tstamp.tv_nsec;
if (snd_pcm_running(substream)) {
@ -1083,8 +1071,6 @@ int snd_pcm_status64(struct snd_pcm_substream *substream,
status->overrange = runtime->overrange;
runtime->avail_max = 0;
runtime->overrange = 0;
_end:
snd_pcm_stream_unlock_irq(substream);
return 0;
}
@ -1169,12 +1155,10 @@ static int snd_pcm_channel_info(struct snd_pcm_substream *substream,
channel = info->channel;
runtime = substream->runtime;
snd_pcm_stream_lock_irq(substream);
if (runtime->state == SNDRV_PCM_STATE_OPEN) {
snd_pcm_stream_unlock_irq(substream);
return -EBADFD;
scoped_guard(pcm_stream_lock_irq, substream) {
if (runtime->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
}
snd_pcm_stream_unlock_irq(substream);
if (channel >= runtime->channels)
return -EINVAL;
memset(info, 0, sizeof(*info));
@ -1395,12 +1379,8 @@ static int snd_pcm_action_lock_irq(const struct action_ops *ops,
struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
int res;
snd_pcm_stream_lock_irq(substream);
res = snd_pcm_action(ops, substream, state);
snd_pcm_stream_unlock_irq(substream);
return res;
guard(pcm_stream_lock_irq)(substream);
return snd_pcm_action(ops, substream, state);
}
/*
@ -1412,17 +1392,15 @@ static int snd_pcm_action_nonatomic(const struct action_ops *ops,
int res;
/* Guarantee the group members won't change during non-atomic action */
down_read(&snd_pcm_link_rwsem);
guard(rwsem_read)(&snd_pcm_link_rwsem);
res = snd_pcm_buffer_access_lock(substream->runtime);
if (res < 0)
goto unlock;
return res;
if (snd_pcm_stream_linked(substream))
res = snd_pcm_action_group(ops, substream, state, false);
else
res = snd_pcm_action_single(ops, substream, state);
snd_pcm_buffer_access_unlock(substream->runtime);
unlock:
up_read(&snd_pcm_link_rwsem);
return res;
}
@ -1592,12 +1570,9 @@ int snd_pcm_drain_done(struct snd_pcm_substream *substream)
*/
int snd_pcm_stop_xrun(struct snd_pcm_substream *substream)
{
unsigned long flags;
snd_pcm_stream_lock_irqsave(substream, flags);
guard(pcm_stream_lock_irqsave)(substream);
if (substream->runtime && snd_pcm_running(substream))
__snd_pcm_xrun(substream);
snd_pcm_stream_unlock_irqrestore(substream, flags);
return 0;
}
EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun);
@ -1749,14 +1724,9 @@ static const struct action_ops snd_pcm_action_suspend = {
*/
static int snd_pcm_suspend(struct snd_pcm_substream *substream)
{
int err;
unsigned long flags;
snd_pcm_stream_lock_irqsave(substream, flags);
err = snd_pcm_action(&snd_pcm_action_suspend, substream,
ACTION_ARG_IGNORE);
snd_pcm_stream_unlock_irqrestore(substream, flags);
return err;
guard(pcm_stream_lock_irqsave)(substream);
return snd_pcm_action(&snd_pcm_action_suspend, substream,
ACTION_ARG_IGNORE);
}
/**
@ -1872,22 +1842,17 @@ static int snd_pcm_resume(struct snd_pcm_substream *substream)
static int snd_pcm_xrun(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
int result;
snd_pcm_stream_lock_irq(substream);
guard(pcm_stream_lock_irq)(substream);
switch (runtime->state) {
case SNDRV_PCM_STATE_XRUN:
result = 0; /* already there */
break;
return 0; /* already there */
case SNDRV_PCM_STATE_RUNNING:
__snd_pcm_xrun(substream);
result = 0;
break;
return 0;
default:
result = -EBADFD;
return -EBADFD;
}
snd_pcm_stream_unlock_irq(substream);
return result;
}
/*
@ -1916,13 +1881,12 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream,
int err = snd_pcm_ops_ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL);
if (err < 0)
return err;
snd_pcm_stream_lock_irq(substream);
guard(pcm_stream_lock_irq)(substream);
runtime->hw_ptr_base = 0;
runtime->hw_ptr_interrupt = runtime->status->hw_ptr -
runtime->status->hw_ptr % runtime->period_size;
runtime->silence_start = runtime->status->hw_ptr;
runtime->silence_filled = 0;
snd_pcm_stream_unlock_irq(substream);
return 0;
}
@ -1930,12 +1894,11 @@ static void snd_pcm_post_reset(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_stream_lock_irq(substream);
guard(pcm_stream_lock_irq)(substream);
runtime->control->appl_ptr = runtime->status->hw_ptr;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
snd_pcm_playback_silence(substream, ULONG_MAX);
snd_pcm_stream_unlock_irq(substream);
}
static const struct action_ops snd_pcm_action_reset = {
@ -2011,16 +1974,16 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream,
else
f_flags = substream->f_flags;
snd_pcm_stream_lock_irq(substream);
switch (substream->runtime->state) {
case SNDRV_PCM_STATE_PAUSED:
snd_pcm_pause(substream, false);
fallthrough;
case SNDRV_PCM_STATE_SUSPENDED:
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
break;
scoped_guard(pcm_stream_lock_irq, substream) {
switch (substream->runtime->state) {
case SNDRV_PCM_STATE_PAUSED:
snd_pcm_pause(substream, false);
fallthrough;
case SNDRV_PCM_STATE_SUSPENDED:
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
break;
}
}
snd_pcm_stream_unlock_irq(substream);
return snd_pcm_action_nonatomic(&snd_pcm_action_prepare,
substream,
@ -2237,14 +2200,13 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream)
runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
snd_pcm_stream_lock_irq(substream);
guard(pcm_stream_lock_irq)(substream);
/* resume pause */
if (runtime->state == SNDRV_PCM_STATE_PAUSED)
snd_pcm_pause(substream, false);
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
/* runtime->control->appl_ptr = runtime->status->hw_ptr; */
snd_pcm_stream_unlock_irq(substream);
return result;
}
@ -2273,53 +2235,44 @@ static bool is_pcm_file(struct file *file)
*/
static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
{
int res = 0;
struct snd_pcm_file *pcm_file;
struct snd_pcm_substream *substream1;
struct snd_pcm_group *group, *target_group;
struct snd_pcm_group *group __free(kfree) = NULL;
struct snd_pcm_group *target_group;
bool nonatomic = substream->pcm->nonatomic;
struct fd f = fdget(fd);
CLASS(fd, f)(fd);
if (!f.file)
return -EBADFD;
if (!is_pcm_file(f.file)) {
res = -EBADFD;
goto _badf;
}
if (!is_pcm_file(f.file))
return -EBADFD;
pcm_file = f.file->private_data;
substream1 = pcm_file->substream;
if (substream == substream1) {
res = -EINVAL;
goto _badf;
}
if (substream == substream1)
return -EINVAL;
group = kzalloc(sizeof(*group), GFP_KERNEL);
if (!group) {
res = -ENOMEM;
goto _nolock;
}
if (!group)
return -ENOMEM;
snd_pcm_group_init(group);
down_write(&snd_pcm_link_rwsem);
guard(rwsem_write)(&snd_pcm_link_rwsem);
if (substream->runtime->state == SNDRV_PCM_STATE_OPEN ||
substream->runtime->state != substream1->runtime->state ||
substream->pcm->nonatomic != substream1->pcm->nonatomic) {
res = -EBADFD;
goto _end;
}
if (snd_pcm_stream_linked(substream1)) {
res = -EALREADY;
goto _end;
}
substream->pcm->nonatomic != substream1->pcm->nonatomic)
return -EBADFD;
if (snd_pcm_stream_linked(substream1))
return -EALREADY;
snd_pcm_stream_lock_irq(substream);
if (!snd_pcm_stream_linked(substream)) {
snd_pcm_group_assign(substream, group);
group = NULL; /* assigned, don't free this one below */
scoped_guard(pcm_stream_lock_irq, substream) {
if (!snd_pcm_stream_linked(substream)) {
snd_pcm_group_assign(substream, group);
group = NULL; /* assigned, don't free this one below */
}
target_group = substream->group;
}
target_group = substream->group;
snd_pcm_stream_unlock_irq(substream);
snd_pcm_group_lock_irq(target_group, nonatomic);
snd_pcm_stream_lock_nested(substream1);
@ -2327,13 +2280,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
refcount_inc(&target_group->refs);
snd_pcm_stream_unlock(substream1);
snd_pcm_group_unlock_irq(target_group, nonatomic);
_end:
up_write(&snd_pcm_link_rwsem);
_nolock:
kfree(group);
_badf:
fdput(f);
return res;
return 0;
}
static void relink_to_local(struct snd_pcm_substream *substream)
@ -2348,14 +2295,11 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
struct snd_pcm_group *group;
bool nonatomic = substream->pcm->nonatomic;
bool do_free = false;
int res = 0;
down_write(&snd_pcm_link_rwsem);
guard(rwsem_write)(&snd_pcm_link_rwsem);
if (!snd_pcm_stream_linked(substream)) {
res = -EALREADY;
goto _end;
}
if (!snd_pcm_stream_linked(substream))
return -EALREADY;
group = substream->group;
snd_pcm_group_lock_irq(group, nonatomic);
@ -2374,10 +2318,7 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
snd_pcm_group_unlock_irq(group, nonatomic);
if (do_free)
kfree(group);
_end:
up_write(&snd_pcm_link_rwsem);
return res;
return 0;
}
/*
@ -2950,10 +2891,10 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
/* 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);
mutex_unlock(&pcm->open_mutex);
scoped_guard(mutex, &pcm->open_mutex) {
snd_pcm_release_substream(substream);
kfree(pcm_file);
}
wake_up(&pcm->open_wait);
module_put(pcm->card->module);
snd_card_file_remove(pcm->card, file);
@ -3037,12 +2978,12 @@ static snd_pcm_sframes_t snd_pcm_rewind(struct snd_pcm_substream *substream,
if (frames == 0)
return 0;
snd_pcm_stream_lock_irq(substream);
ret = do_pcm_hwsync(substream);
if (!ret)
ret = rewind_appl_ptr(substream, frames,
snd_pcm_hw_avail(substream));
snd_pcm_stream_unlock_irq(substream);
scoped_guard(pcm_stream_lock_irq, substream) {
ret = do_pcm_hwsync(substream);
if (!ret)
ret = rewind_appl_ptr(substream, frames,
snd_pcm_hw_avail(substream));
}
if (ret >= 0)
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
return ret;
@ -3056,12 +2997,12 @@ static snd_pcm_sframes_t snd_pcm_forward(struct snd_pcm_substream *substream,
if (frames == 0)
return 0;
snd_pcm_stream_lock_irq(substream);
ret = do_pcm_hwsync(substream);
if (!ret)
ret = forward_appl_ptr(substream, frames,
snd_pcm_avail(substream));
snd_pcm_stream_unlock_irq(substream);
scoped_guard(pcm_stream_lock_irq, substream) {
ret = do_pcm_hwsync(substream);
if (!ret)
ret = forward_appl_ptr(substream, frames,
snd_pcm_avail(substream));
}
if (ret >= 0)
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
return ret;
@ -3072,11 +3013,11 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream,
{
int err;
snd_pcm_stream_lock_irq(substream);
err = do_pcm_hwsync(substream);
if (delay && !err)
*delay = snd_pcm_calc_delay(substream);
snd_pcm_stream_unlock_irq(substream);
scoped_guard(pcm_stream_lock_irq, substream) {
err = do_pcm_hwsync(substream);
if (delay && !err)
*delay = snd_pcm_calc_delay(substream);
}
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_CPU);
return err;
@ -3108,27 +3049,25 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
if (err < 0)
return err;
}
snd_pcm_stream_lock_irq(substream);
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
err = pcm_lib_apply_appl_ptr(substream,
sync_ptr.c.control.appl_ptr);
if (err < 0) {
snd_pcm_stream_unlock_irq(substream);
return err;
scoped_guard(pcm_stream_lock_irq, substream) {
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
err = pcm_lib_apply_appl_ptr(substream,
sync_ptr.c.control.appl_ptr);
if (err < 0)
return err;
} else {
sync_ptr.c.control.appl_ptr = control->appl_ptr;
}
} else {
sync_ptr.c.control.appl_ptr = control->appl_ptr;
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = sync_ptr.c.control.avail_min;
else
sync_ptr.c.control.avail_min = control->avail_min;
sync_ptr.s.status.state = status->state;
sync_ptr.s.status.hw_ptr = status->hw_ptr;
sync_ptr.s.status.tstamp = status->tstamp;
sync_ptr.s.status.suspended_state = status->suspended_state;
sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
}
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = sync_ptr.c.control.avail_min;
else
sync_ptr.c.control.avail_min = control->avail_min;
sync_ptr.s.status.state = status->state;
sync_ptr.s.status.hw_ptr = status->hw_ptr;
sync_ptr.s.status.tstamp = status->tstamp;
sync_ptr.s.status.suspended_state = status->suspended_state;
sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
snd_pcm_stream_unlock_irq(substream);
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
@ -3206,27 +3145,25 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
boundary = recalculate_boundary(runtime);
if (! boundary)
boundary = 0x7fffffff;
snd_pcm_stream_lock_irq(substream);
/* FIXME: we should consider the boundary for the sync from app */
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) {
err = pcm_lib_apply_appl_ptr(substream,
scontrol.appl_ptr);
if (err < 0) {
snd_pcm_stream_unlock_irq(substream);
return err;
}
} else
scontrol.appl_ptr = control->appl_ptr % boundary;
if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = scontrol.avail_min;
else
scontrol.avail_min = control->avail_min;
sstatus.state = status->state;
sstatus.hw_ptr = status->hw_ptr % boundary;
sstatus.tstamp = status->tstamp;
sstatus.suspended_state = status->suspended_state;
sstatus.audio_tstamp = status->audio_tstamp;
snd_pcm_stream_unlock_irq(substream);
scoped_guard(pcm_stream_lock_irq, substream) {
/* FIXME: we should consider the boundary for the sync from app */
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) {
err = pcm_lib_apply_appl_ptr(substream,
scontrol.appl_ptr);
if (err < 0)
return err;
} else
scontrol.appl_ptr = control->appl_ptr % boundary;
if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = scontrol.avail_min;
else
scontrol.avail_min = control->avail_min;
sstatus.state = status->state;
sstatus.hw_ptr = status->hw_ptr % boundary;
sstatus.tstamp = status->tstamp;
sstatus.suspended_state = status->suspended_state;
sstatus.audio_tstamp = status->audio_tstamp;
}
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
if (put_user(sstatus.state, &src->s.status.state) ||
@ -3284,7 +3221,7 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream,
{
struct snd_xfern xfern;
struct snd_pcm_runtime *runtime = substream->runtime;
void *bufs;
void *bufs __free(kfree) = NULL;
snd_pcm_sframes_t result;
if (runtime->state == SNDRV_PCM_STATE_OPEN)
@ -3298,12 +3235,11 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream,
bufs = memdup_user(xfern.bufs, sizeof(void *) * runtime->channels);
if (IS_ERR(bufs))
return PTR_ERR(bufs);
return PTR_ERR(no_free_ptr(bufs));
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
result = snd_pcm_lib_writev(substream, bufs, xfern.frames);
else
result = snd_pcm_lib_readv(substream, bufs, xfern.frames);
kfree(bufs);
if (put_user(result, &_xfern->result))
return -EFAULT;
return result < 0 ? result : 0;
@ -3571,7 +3507,7 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)
struct snd_pcm_runtime *runtime;
snd_pcm_sframes_t result;
unsigned long i;
void __user **bufs;
void __user **bufs __free(kfree) = NULL;
snd_pcm_uframes_t frames;
const struct iovec *iov = iter_iov(to);
@ -3600,7 +3536,6 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)
result = snd_pcm_lib_readv(substream, bufs, frames);
if (result > 0)
result = frames_to_bytes(runtime, result);
kfree(bufs);
return result;
}
@ -3611,7 +3546,7 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
struct snd_pcm_runtime *runtime;
snd_pcm_sframes_t result;
unsigned long i;
void __user **bufs;
void __user **bufs __free(kfree) = NULL;
snd_pcm_uframes_t frames;
const struct iovec *iov = iter_iov(from);
@ -3639,7 +3574,6 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
result = snd_pcm_lib_writev(substream, bufs, frames);
if (result > 0)
result = frames_to_bytes(runtime, result);
kfree(bufs);
return result;
}
@ -3668,7 +3602,7 @@ static __poll_t snd_pcm_poll(struct file *file, poll_table *wait)
poll_wait(file, &runtime->sleep, wait);
mask = 0;
snd_pcm_stream_lock_irq(substream);
guard(pcm_stream_lock_irq)(substream);
avail = snd_pcm_avail(substream);
switch (runtime->state) {
case SNDRV_PCM_STATE_RUNNING:
@ -3688,7 +3622,6 @@ static __poll_t snd_pcm_poll(struct file *file, poll_table *wait)
mask = ok | EPOLLERR;
break;
}
snd_pcm_stream_unlock_irq(substream);
return mask;
}
@ -4081,8 +4014,8 @@ static void snd_pcm_hw_convert_to_old_params(struct snd_pcm_hw_params_old *opara
static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params_old __user * _oparams)
{
struct snd_pcm_hw_params *params;
struct snd_pcm_hw_params_old *oparams = NULL;
struct snd_pcm_hw_params *params __free(kfree) = NULL;
struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL;
int err;
params = kmalloc(sizeof(*params), GFP_KERNEL);
@ -4090,34 +4023,28 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
return -ENOMEM;
oparams = memdup_user(_oparams, sizeof(*oparams));
if (IS_ERR(oparams)) {
err = PTR_ERR(oparams);
goto out;
}
if (IS_ERR(oparams))
return PTR_ERR(no_free_ptr(oparams));
snd_pcm_hw_convert_from_old_params(params, oparams);
err = snd_pcm_hw_refine(substream, params);
if (err < 0)
goto out_old;
return err;
err = fixup_unreferenced_params(substream, params);
if (err < 0)
goto out_old;
return err;
snd_pcm_hw_convert_to_old_params(oparams, params);
if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
err = -EFAULT;
out_old:
kfree(oparams);
out:
kfree(params);
return err;
return -EFAULT;
return 0;
}
static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params_old __user * _oparams)
{
struct snd_pcm_hw_params *params;
struct snd_pcm_hw_params_old *oparams = NULL;
struct snd_pcm_hw_params *params __free(kfree) = NULL;
struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL;
int err;
params = kmalloc(sizeof(*params), GFP_KERNEL);
@ -4125,24 +4052,18 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
return -ENOMEM;
oparams = memdup_user(_oparams, sizeof(*oparams));
if (IS_ERR(oparams)) {
err = PTR_ERR(oparams);
goto out;
}
if (IS_ERR(oparams))
return PTR_ERR(no_free_ptr(oparams));
snd_pcm_hw_convert_from_old_params(params, oparams);
err = snd_pcm_hw_params(substream, params);
if (err < 0)
goto out_old;
return err;
snd_pcm_hw_convert_to_old_params(oparams, params);
if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
err = -EFAULT;
out_old:
kfree(oparams);
out:
kfree(params);
return err;
return -EFAULT;
return 0;
}
#endif /* CONFIG_SND_SUPPORT_OLD_API */

View File

@ -105,13 +105,8 @@ static inline bool __snd_rawmidi_ready(struct snd_rawmidi_runtime *runtime)
static bool snd_rawmidi_ready(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
bool ready;
spin_lock_irqsave(&substream->lock, flags);
ready = __snd_rawmidi_ready(substream->runtime);
spin_unlock_irqrestore(&substream->lock, flags);
return ready;
guard(spinlock_irqsave)(&substream->lock);
return __snd_rawmidi_ready(substream->runtime);
}
static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substream,
@ -238,12 +233,9 @@ static void __reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime,
static void reset_runtime_ptrs(struct snd_rawmidi_substream *substream,
bool is_input)
{
unsigned long flags;
spin_lock_irqsave(&substream->lock, flags);
guard(spinlock_irqsave)(&substream->lock);
if (substream->opened && substream->runtime)
__reset_runtime_ptrs(substream->runtime, is_input);
spin_unlock_irqrestore(&substream->lock, flags);
}
int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream)
@ -260,33 +252,29 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
long timeout;
struct snd_rawmidi_runtime *runtime;
spin_lock_irq(&substream->lock);
runtime = substream->runtime;
if (!substream->opened || !runtime || !runtime->buffer) {
err = -EINVAL;
} else {
scoped_guard(spinlock_irq, &substream->lock) {
runtime = substream->runtime;
if (!substream->opened || !runtime || !runtime->buffer)
return -EINVAL;
snd_rawmidi_buffer_ref(runtime);
runtime->drain = 1;
}
spin_unlock_irq(&substream->lock);
if (err < 0)
return err;
timeout = wait_event_interruptible_timeout(runtime->sleep,
(runtime->avail >= runtime->buffer_size),
10*HZ);
spin_lock_irq(&substream->lock);
if (signal_pending(current))
err = -ERESTARTSYS;
if (runtime->avail < runtime->buffer_size && !timeout) {
rmidi_warn(substream->rmidi,
"rawmidi drain error (avail = %li, buffer_size = %li)\n",
(long)runtime->avail, (long)runtime->buffer_size);
err = -EIO;
scoped_guard(spinlock_irq, &substream->lock) {
if (signal_pending(current))
err = -ERESTARTSYS;
if (runtime->avail < runtime->buffer_size && !timeout) {
rmidi_warn(substream->rmidi,
"rawmidi drain error (avail = %li, buffer_size = %li)\n",
(long)runtime->avail, (long)runtime->buffer_size);
err = -EIO;
}
runtime->drain = 0;
}
runtime->drain = 0;
spin_unlock_irq(&substream->lock);
if (err != -ERESTARTSYS) {
/* we need wait a while to make sure that Tx FIFOs are empty */
@ -297,9 +285,8 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
snd_rawmidi_drop_output(substream);
}
spin_lock_irq(&substream->lock);
snd_rawmidi_buffer_unref(runtime);
spin_unlock_irq(&substream->lock);
scoped_guard(spinlock_irq, &substream->lock)
snd_rawmidi_buffer_unref(runtime);
return err;
}
@ -363,14 +350,13 @@ static int open_substream(struct snd_rawmidi *rmidi,
snd_rawmidi_runtime_free(substream);
return err;
}
spin_lock_irq(&substream->lock);
guard(spinlock_irq)(&substream->lock);
substream->opened = 1;
substream->active_sensing = 0;
if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
substream->append = 1;
substream->pid = get_pid(task_pid(current));
rmidi->streams[substream->stream].substream_opened++;
spin_unlock_irq(&substream->lock);
}
substream->use_count++;
return 0;
@ -433,9 +419,8 @@ int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice,
if (!try_module_get(rmidi->card->module))
return -ENXIO;
mutex_lock(&rmidi->open_mutex);
guard(mutex)(&rmidi->open_mutex);
err = rawmidi_open_priv(rmidi, subdevice, mode, rfile);
mutex_unlock(&rmidi->open_mutex);
if (err < 0)
module_put(rmidi->card->module);
return err;
@ -568,10 +553,10 @@ static void close_substream(struct snd_rawmidi *rmidi,
}
snd_rawmidi_buffer_ref_sync(substream);
}
spin_lock_irq(&substream->lock);
substream->opened = 0;
substream->append = 0;
spin_unlock_irq(&substream->lock);
scoped_guard(spinlock_irq, &substream->lock) {
substream->opened = 0;
substream->append = 0;
}
substream->ops->close(substream);
if (substream->runtime->private_free)
substream->runtime->private_free(substream);
@ -586,7 +571,7 @@ static void rawmidi_release_priv(struct snd_rawmidi_file *rfile)
struct snd_rawmidi *rmidi;
rmidi = rfile->rmidi;
mutex_lock(&rmidi->open_mutex);
guard(mutex)(&rmidi->open_mutex);
if (rfile->input) {
close_substream(rmidi, rfile->input, 1);
rfile->input = NULL;
@ -596,7 +581,6 @@ static void rawmidi_release_priv(struct snd_rawmidi_file *rfile)
rfile->output = NULL;
}
rfile->rmidi = NULL;
mutex_unlock(&rmidi->open_mutex);
wake_up(&rmidi->open_wait);
}
@ -695,12 +679,8 @@ static int __snd_rawmidi_info_select(struct snd_card *card,
int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info)
{
int ret;
mutex_lock(&register_mutex);
ret = __snd_rawmidi_info_select(card, info);
mutex_unlock(&register_mutex);
return ret;
guard(mutex)(&register_mutex);
return __snd_rawmidi_info_select(card, info);
}
EXPORT_SYMBOL(snd_rawmidi_info_select);
@ -744,9 +724,8 @@ static int resize_runtime_buffer(struct snd_rawmidi_substream *substream,
newbuf = kvzalloc(params->buffer_size, GFP_KERNEL);
if (!newbuf)
return -ENOMEM;
spin_lock_irq(&substream->lock);
guard(spinlock_irq)(&substream->lock);
if (runtime->buffer_ref) {
spin_unlock_irq(&substream->lock);
kvfree(newbuf);
return -EBUSY;
}
@ -754,7 +733,6 @@ static int resize_runtime_buffer(struct snd_rawmidi_substream *substream,
runtime->buffer = newbuf;
runtime->buffer_size = params->buffer_size;
__reset_runtime_ptrs(runtime, is_input);
spin_unlock_irq(&substream->lock);
kvfree(oldbuf);
}
runtime->avail_min = params->avail_min;
@ -767,15 +745,12 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
int err;
snd_rawmidi_drain_output(substream);
mutex_lock(&substream->rmidi->open_mutex);
guard(mutex)(&substream->rmidi->open_mutex);
if (substream->append && substream->use_count > 1)
err = -EBUSY;
else
err = resize_runtime_buffer(substream, params, false);
return -EBUSY;
err = resize_runtime_buffer(substream, params, false);
if (!err)
substream->active_sensing = !params->no_active_sensing;
mutex_unlock(&substream->rmidi->open_mutex);
return err;
}
EXPORT_SYMBOL(snd_rawmidi_output_params);
@ -788,7 +763,7 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
int err;
snd_rawmidi_drain_input(substream);
mutex_lock(&substream->rmidi->open_mutex);
guard(mutex)(&substream->rmidi->open_mutex);
if (framing == SNDRV_RAWMIDI_MODE_FRAMING_NONE && clock_type != SNDRV_RAWMIDI_MODE_CLOCK_NONE)
err = -EINVAL;
else if (clock_type > SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW)
@ -802,7 +777,6 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
substream->framing = framing;
substream->clock_type = clock_type;
}
mutex_unlock(&substream->rmidi->open_mutex);
return 0;
}
EXPORT_SYMBOL(snd_rawmidi_input_params);
@ -814,9 +788,8 @@ static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream,
memset(status, 0, sizeof(*status));
status->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
spin_lock_irq(&substream->lock);
guard(spinlock_irq)(&substream->lock);
status->avail = runtime->avail;
spin_unlock_irq(&substream->lock);
return 0;
}
@ -827,11 +800,10 @@ static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream,
memset(status, 0, sizeof(*status));
status->stream = SNDRV_RAWMIDI_STREAM_INPUT;
spin_lock_irq(&substream->lock);
guard(spinlock_irq)(&substream->lock);
status->avail = runtime->avail;
status->xruns = runtime->xruns;
runtime->xruns = 0;
spin_unlock_irq(&substream->lock);
return 0;
}
@ -1025,19 +997,19 @@ static int snd_rawmidi_next_device(struct snd_card *card, int __user *argp,
return -EFAULT;
if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */
device = SNDRV_RAWMIDI_DEVICES - 1;
mutex_lock(&register_mutex);
device = device < 0 ? 0 : device + 1;
for (; device < SNDRV_RAWMIDI_DEVICES; device++) {
rmidi = snd_rawmidi_search(card, device);
if (!rmidi)
continue;
is_ump = rawmidi_is_ump(rmidi);
if (find_ump == is_ump)
break;
scoped_guard(mutex, &register_mutex) {
device = device < 0 ? 0 : device + 1;
for (; device < SNDRV_RAWMIDI_DEVICES; device++) {
rmidi = snd_rawmidi_search(card, device);
if (!rmidi)
continue;
is_ump = rawmidi_is_ump(rmidi);
if (find_ump == is_ump)
break;
}
if (device == SNDRV_RAWMIDI_DEVICES)
device = -1;
}
if (device == SNDRV_RAWMIDI_DEVICES)
device = -1;
mutex_unlock(&register_mutex);
if (put_user(device, argp))
return -EFAULT;
return 0;
@ -1050,18 +1022,16 @@ static int snd_rawmidi_call_ump_ioctl(struct snd_card *card, int cmd,
{
struct snd_ump_endpoint_info __user *info = argp;
struct snd_rawmidi *rmidi;
int device, ret;
int device;
if (get_user(device, &info->device))
return -EFAULT;
mutex_lock(&register_mutex);
guard(mutex)(&register_mutex);
rmidi = snd_rawmidi_search(card, device);
if (rmidi && rmidi->ops && rmidi->ops->ioctl)
ret = rmidi->ops->ioctl(rmidi, cmd, argp);
return rmidi->ops->ioctl(rmidi, cmd, argp);
else
ret = -ENXIO;
mutex_unlock(&register_mutex);
return ret;
return -ENXIO;
}
#endif
@ -1168,27 +1138,23 @@ static struct timespec64 get_framing_tstamp(struct snd_rawmidi_substream *substr
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;
spin_lock_irqsave(&substream->lock, flags);
if (!substream->opened) {
result = -EBADFD;
goto unlock;
}
guard(spinlock_irqsave)(&substream->lock);
if (!substream->opened)
return -EBADFD;
runtime = substream->runtime;
if (!runtime || !runtime->buffer) {
rmidi_dbg(substream->rmidi,
"snd_rawmidi_receive: input is not active!!!\n");
result = -EINVAL;
goto unlock;
return -EINVAL;
}
count = get_aligned_size(runtime, count);
if (!count)
goto unlock;
return result;
if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) {
result = receive_with_tstamp_framing(substream, buffer, count, &ts64);
@ -1211,7 +1177,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
count1 = runtime->buffer_size - runtime->avail;
count1 = get_aligned_size(runtime, count1);
if (!count1)
goto unlock;
return result;
memcpy(runtime->buffer + runtime->hw_ptr, buffer, count1);
runtime->hw_ptr += count1;
runtime->hw_ptr %= runtime->buffer_size;
@ -1239,8 +1205,6 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
else if (__snd_rawmidi_ready(runtime))
wake_up(&runtime->sleep);
}
unlock:
spin_unlock_irqrestore(&substream->lock, flags);
return result;
}
EXPORT_SYMBOL(snd_rawmidi_receive);
@ -1362,20 +1326,15 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun
int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
{
struct snd_rawmidi_runtime *runtime;
int result;
unsigned long flags;
spin_lock_irqsave(&substream->lock, flags);
guard(spinlock_irqsave)(&substream->lock);
runtime = substream->runtime;
if (!substream->opened || !runtime || !runtime->buffer) {
rmidi_dbg(substream->rmidi,
"snd_rawmidi_transmit_empty: output is not active!!!\n");
result = 1;
} else {
result = runtime->avail >= runtime->buffer_size;
return 1;
}
spin_unlock_irqrestore(&substream->lock, flags);
return result;
return (runtime->avail >= runtime->buffer_size);
}
EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
@ -1449,16 +1408,10 @@ static int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
unsigned char *buffer, int count)
{
int result;
unsigned long flags;
spin_lock_irqsave(&substream->lock, flags);
guard(spinlock_irqsave)(&substream->lock);
if (!substream->opened || !substream->runtime)
result = -EBADFD;
else
result = __snd_rawmidi_transmit_peek(substream, buffer, count);
spin_unlock_irqrestore(&substream->lock, flags);
return result;
return -EBADFD;
return __snd_rawmidi_transmit_peek(substream, buffer, count);
}
EXPORT_SYMBOL(snd_rawmidi_transmit_peek);
@ -1505,16 +1458,10 @@ static int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream,
*/
int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
{
int result;
unsigned long flags;
spin_lock_irqsave(&substream->lock, flags);
guard(spinlock_irqsave)(&substream->lock);
if (!substream->opened || !substream->runtime)
result = -EBADFD;
else
result = __snd_rawmidi_transmit_ack(substream, count);
spin_unlock_irqrestore(&substream->lock, flags);
return result;
return -EBADFD;
return __snd_rawmidi_transmit_ack(substream, count);
}
EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
@ -1531,21 +1478,13 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
unsigned char *buffer, int count)
{
int result;
unsigned long flags;
spin_lock_irqsave(&substream->lock, flags);
guard(spinlock_irqsave)(&substream->lock);
if (!substream->opened)
result = -EBADFD;
else {
count = __snd_rawmidi_transmit_peek(substream, buffer, count);
if (count <= 0)
result = count;
else
result = __snd_rawmidi_transmit_ack(substream, count);
}
spin_unlock_irqrestore(&substream->lock, flags);
return result;
return -EBADFD;
count = __snd_rawmidi_transmit_peek(substream, buffer, count);
if (count <= 0)
return count;
return __snd_rawmidi_transmit_ack(substream, count);
}
EXPORT_SYMBOL(snd_rawmidi_transmit);
@ -1558,17 +1497,15 @@ EXPORT_SYMBOL(snd_rawmidi_transmit);
int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream)
{
struct snd_rawmidi_runtime *runtime;
unsigned long flags;
int count = 0;
spin_lock_irqsave(&substream->lock, flags);
guard(spinlock_irqsave)(&substream->lock);
runtime = substream->runtime;
if (substream->opened && runtime &&
runtime->avail < runtime->buffer_size) {
count = runtime->buffer_size - runtime->avail;
__snd_rawmidi_transmit_ack(substream, count);
}
spin_unlock_irqrestore(&substream->lock, flags);
return count;
}
EXPORT_SYMBOL(snd_rawmidi_proceed);
@ -1772,7 +1709,7 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
rawmidi_is_ump(rmidi) ? "UMP" : "Legacy");
if (rmidi->ops && rmidi->ops->proc_read)
rmidi->ops->proc_read(entry, buffer);
mutex_lock(&rmidi->open_mutex);
guard(mutex)(&rmidi->open_mutex);
if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) {
list_for_each_entry(substream,
&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams,
@ -1787,10 +1724,10 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
" Owner PID : %d\n",
pid_vnr(substream->pid));
runtime = substream->runtime;
spin_lock_irq(&substream->lock);
buffer_size = runtime->buffer_size;
avail = runtime->avail;
spin_unlock_irq(&substream->lock);
scoped_guard(spinlock_irq, &substream->lock) {
buffer_size = runtime->buffer_size;
avail = runtime->avail;
}
snd_iprintf(buffer,
" Mode : %s\n"
" Buffer size : %lu\n"
@ -1814,11 +1751,11 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
" Owner PID : %d\n",
pid_vnr(substream->pid));
runtime = substream->runtime;
spin_lock_irq(&substream->lock);
buffer_size = runtime->buffer_size;
avail = runtime->avail;
xruns = runtime->xruns;
spin_unlock_irq(&substream->lock);
scoped_guard(spinlock_irq, &substream->lock) {
buffer_size = runtime->buffer_size;
avail = runtime->avail;
xruns = runtime->xruns;
}
snd_iprintf(buffer,
" Buffer size : %lu\n"
" Avail : %lu\n"
@ -1835,7 +1772,6 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
}
}
}
mutex_unlock(&rmidi->open_mutex);
}
/*
@ -2024,12 +1960,12 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
if (rmidi->device >= SNDRV_RAWMIDI_DEVICES)
return -ENOMEM;
err = 0;
mutex_lock(&register_mutex);
if (snd_rawmidi_search(rmidi->card, rmidi->device))
err = -EBUSY;
else
list_add_tail(&rmidi->list, &snd_rawmidi_devices);
mutex_unlock(&register_mutex);
scoped_guard(mutex, &register_mutex) {
if (snd_rawmidi_search(rmidi->card, rmidi->device))
err = -EBUSY;
else
list_add_tail(&rmidi->list, &snd_rawmidi_devices);
}
if (err < 0)
return err;
@ -2102,9 +2038,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
error_unregister:
snd_unregister_device(rmidi->dev);
error:
mutex_lock(&register_mutex);
list_del(&rmidi->list);
mutex_unlock(&register_mutex);
scoped_guard(mutex, &register_mutex)
list_del(&rmidi->list);
return err;
}
@ -2113,8 +2048,8 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
struct snd_rawmidi *rmidi = device->device_data;
int dir;
mutex_lock(&register_mutex);
mutex_lock(&rmidi->open_mutex);
guard(mutex)(&register_mutex);
guard(mutex)(&rmidi->open_mutex);
wake_up(&rmidi->open_wait);
list_del_init(&rmidi->list);
for (dir = 0; dir < 2; dir++) {
@ -2140,8 +2075,6 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
}
#endif /* CONFIG_SND_OSSEMUL */
snd_unregister_device(rmidi->dev);
mutex_unlock(&rmidi->open_mutex);
mutex_unlock(&register_mutex);
return 0;
}

View File

@ -71,7 +71,6 @@ config SND_SEQ_UMP
among legacy and UMP clients.
config SND_SEQ_UMP_CLIENT
tristate
def_tristate SND_UMP
endif # SND_SEQUENCER

View File

@ -163,6 +163,6 @@ snd_seq_oss_fill_addr(struct seq_oss_devinfo *dp, struct snd_seq_event *ev,
/* misc. functions for proc interface */
char *enabled_str(int bool);
char *enabled_str(bool b);
#endif /* __SEQ_OSS_DEVICE_H */

View File

@ -63,20 +63,18 @@ int __init
snd_seq_oss_create_client(void)
{
int rc;
struct snd_seq_port_info *port;
struct snd_seq_port_info *port __free(kfree) = NULL;
struct snd_seq_port_callback port_callback;
port = kzalloc(sizeof(*port), GFP_KERNEL);
if (!port) {
rc = -ENOMEM;
goto __error;
}
if (!port)
return -ENOMEM;
/* create ALSA client */
rc = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_OSS,
"OSS sequencer");
if (rc < 0)
goto __error;
return rc;
system_client = rc;
@ -104,14 +102,11 @@ snd_seq_oss_create_client(void)
subs.dest.port = system_port;
call_ctl(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs);
}
rc = 0;
/* look up midi devices */
schedule_work(&async_lookup_work);
__error:
kfree(port);
return rc;
return 0;
}
@ -455,9 +450,9 @@ snd_seq_oss_reset(struct seq_oss_devinfo *dp)
* misc. functions for proc interface
*/
char *
enabled_str(int bool)
enabled_str(bool b)
{
return bool ? "enabled" : "disabled";
return b ? "enabled" : "disabled";
}
static const char *

View File

@ -64,16 +64,13 @@ static int send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev,
int
snd_seq_oss_midi_lookup_ports(int client)
{
struct snd_seq_client_info *clinfo;
struct snd_seq_port_info *pinfo;
struct snd_seq_client_info *clinfo __free(kfree) = NULL;
struct snd_seq_port_info *pinfo __free(kfree) = NULL;
clinfo = kzalloc(sizeof(*clinfo), GFP_KERNEL);
pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
if (! clinfo || ! pinfo) {
kfree(clinfo);
kfree(pinfo);
if (!clinfo || !pinfo)
return -ENOMEM;
}
clinfo->client = -1;
while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, clinfo) == 0) {
if (clinfo->client == client)
@ -83,8 +80,6 @@ snd_seq_oss_midi_lookup_ports(int client)
while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, pinfo) == 0)
snd_seq_oss_midi_check_new_port(pinfo);
}
kfree(clinfo);
kfree(pinfo);
return 0;
}

View File

@ -31,8 +31,8 @@ struct snd_seq_port_info32 {
static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned int cmd,
struct snd_seq_port_info32 __user *data32)
{
int err = -EFAULT;
struct snd_seq_port_info *data;
struct snd_seq_port_info *data __free(kfree) = NULL;
int err;
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data)
@ -41,20 +41,18 @@ static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned
if (copy_from_user(data, data32, sizeof(*data32)) ||
get_user(data->flags, &data32->flags) ||
get_user(data->time_queue, &data32->time_queue))
goto error;
return -EFAULT;
data->kernel = NULL;
err = snd_seq_kernel_client_ctl(client->number, cmd, data);
if (err < 0)
goto error;
return err;
if (copy_to_user(data32, data, sizeof(*data32)) ||
put_user(data->flags, &data32->flags) ||
put_user(data->time_queue, &data32->time_queue))
err = -EFAULT;
return -EFAULT;
error:
kfree(data);
return err;
}

View File

@ -88,12 +88,11 @@ void snd_seq_fifo_clear(struct snd_seq_fifo *f)
atomic_set(&f->overflow, 0);
snd_use_lock_sync(&f->use_lock);
spin_lock_irq(&f->lock);
guard(spinlock_irq)(&f->lock);
/* drain the fifo */
while ((cell = fifo_cell_out(f)) != NULL) {
snd_seq_cell_free(cell);
}
spin_unlock_irq(&f->lock);
}
@ -102,7 +101,6 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
struct snd_seq_event *event)
{
struct snd_seq_event_cell *cell;
unsigned long flags;
int err;
if (snd_BUG_ON(!f))
@ -118,15 +116,15 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
}
/* append new cells to fifo */
spin_lock_irqsave(&f->lock, flags);
if (f->tail != NULL)
f->tail->next = cell;
f->tail = cell;
if (f->head == NULL)
f->head = cell;
cell->next = NULL;
f->cells++;
spin_unlock_irqrestore(&f->lock, flags);
scoped_guard(spinlock_irqsave, &f->lock) {
if (f->tail != NULL)
f->tail->next = cell;
f->tail = cell;
if (f->head == NULL)
f->head = cell;
cell->next = NULL;
f->cells++;
}
/* wakeup client */
if (waitqueue_active(&f->input_sleep))
@ -199,16 +197,13 @@ int snd_seq_fifo_cell_out(struct snd_seq_fifo *f,
void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f,
struct snd_seq_event_cell *cell)
{
unsigned long flags;
if (cell) {
spin_lock_irqsave(&f->lock, flags);
guard(spinlock_irqsave)(&f->lock);
cell->next = f->head;
f->head = cell;
if (!f->tail)
f->tail = cell;
f->cells++;
spin_unlock_irqrestore(&f->lock, flags);
}
}
@ -239,17 +234,17 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
return -ENOMEM;
}
spin_lock_irq(&f->lock);
/* remember old pool */
oldpool = f->pool;
oldhead = f->head;
/* exchange pools */
f->pool = newpool;
f->head = NULL;
f->tail = NULL;
f->cells = 0;
/* NOTE: overflow flag is not cleared */
spin_unlock_irq(&f->lock);
scoped_guard(spinlock_irq, &f->lock) {
/* remember old pool */
oldpool = f->pool;
oldhead = f->head;
/* exchange pools */
f->pool = newpool;
f->head = NULL;
f->tail = NULL;
f->cells = 0;
/* NOTE: overflow flag is not cleared */
}
/* close the old pool and wait until all users are gone */
snd_seq_pool_mark_closing(oldpool);
@ -268,16 +263,14 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
/* get the number of unused cells safely */
int snd_seq_fifo_unused_cells(struct snd_seq_fifo *f)
{
unsigned long flags;
int cells;
if (!f)
return 0;
snd_use_lock_use(&f->use_lock);
spin_lock_irqsave(&f->lock, flags);
cells = snd_seq_unused_cells(f->pool);
spin_unlock_irqrestore(&f->lock, flags);
scoped_guard(spinlock_irqsave, &f->lock)
cells = snd_seq_unused_cells(f->pool);
snd_use_lock_free(&f->use_lock);
return cells;
}

View File

@ -232,7 +232,6 @@ static inline void free_cell(struct snd_seq_pool *pool,
void snd_seq_cell_free(struct snd_seq_event_cell * cell)
{
unsigned long flags;
struct snd_seq_pool *pool;
if (snd_BUG_ON(!cell))
@ -241,7 +240,7 @@ void snd_seq_cell_free(struct snd_seq_event_cell * cell)
if (snd_BUG_ON(!pool))
return;
spin_lock_irqsave(&pool->lock, flags);
guard(spinlock_irqsave)(&pool->lock);
free_cell(pool, cell);
if (snd_seq_ev_is_variable(&cell->event)) {
if (cell->event.data.ext.len & SNDRV_SEQ_EXT_CHAINED) {
@ -259,7 +258,6 @@ void snd_seq_cell_free(struct snd_seq_event_cell * cell)
if (snd_seq_output_ok(pool))
wake_up(&pool->output_sleep);
}
spin_unlock_irqrestore(&pool->lock, flags);
}
@ -449,9 +447,8 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
return -ENOMEM;
/* add new cells to the free cell list */
spin_lock_irq(&pool->lock);
guard(spinlock_irq)(&pool->lock);
if (pool->ptr) {
spin_unlock_irq(&pool->lock);
kvfree(cellptr);
return 0;
}
@ -470,20 +467,16 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
/* init statistics */
pool->max_used = 0;
pool->total_elements = pool->size;
spin_unlock_irq(&pool->lock);
return 0;
}
/* refuse the further insertion to the pool */
void snd_seq_pool_mark_closing(struct snd_seq_pool *pool)
{
unsigned long flags;
if (snd_BUG_ON(!pool))
return;
spin_lock_irqsave(&pool->lock, flags);
guard(spinlock_irqsave)(&pool->lock);
pool->closing = 1;
spin_unlock_irqrestore(&pool->lock, flags);
}
/* remove events */
@ -502,18 +495,17 @@ int snd_seq_pool_done(struct snd_seq_pool *pool)
schedule_timeout_uninterruptible(1);
/* release all resources */
spin_lock_irq(&pool->lock);
ptr = pool->ptr;
pool->ptr = NULL;
pool->free = NULL;
pool->total_elements = 0;
spin_unlock_irq(&pool->lock);
scoped_guard(spinlock_irq, &pool->lock) {
ptr = pool->ptr;
pool->ptr = NULL;
pool->free = NULL;
pool->total_elements = 0;
}
kvfree(ptr);
spin_lock_irq(&pool->lock);
guard(spinlock_irq)(&pool->lock);
pool->closing = 0;
spin_unlock_irq(&pool->lock);
return 0;
}

View File

@ -113,6 +113,12 @@ static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, i
return 0;
}
/* callback for snd_seq_dump_var_event(), bridging to dump_midi() */
static int __dump_midi(void *ptr, void *buf, int count)
{
return dump_midi(ptr, buf, count);
}
static int event_process_midi(struct snd_seq_event *ev, int direct,
void *private_data, int atomic, int hop)
{
@ -132,7 +138,7 @@ static int event_process_midi(struct snd_seq_event *ev, int direct,
pr_debug("ALSA: seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
return 0;
}
snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream);
snd_seq_dump_var_event(ev, __dump_midi, substream);
snd_midi_event_reset_decode(msynth->parser);
} else {
if (msynth->parser == NULL)
@ -264,8 +270,8 @@ snd_seq_midisynth_probe(struct device *_dev)
struct snd_seq_device *dev = to_seq_dev(_dev);
struct seq_midisynth_client *client;
struct seq_midisynth *msynth, *ms;
struct snd_seq_port_info *port;
struct snd_rawmidi_info *info;
struct snd_seq_port_info *port __free(kfree) = NULL;
struct snd_rawmidi_info *info __free(kfree) = NULL;
struct snd_rawmidi *rmidi = dev->private_data;
int newclient = 0;
unsigned int p, ports;
@ -291,31 +297,24 @@ snd_seq_midisynth_probe(struct device *_dev)
ports = output_count;
if (ports < input_count)
ports = input_count;
if (ports == 0) {
kfree(info);
if (ports == 0)
return -ENODEV;
}
if (ports > (256 / SNDRV_RAWMIDI_DEVICES))
ports = 256 / SNDRV_RAWMIDI_DEVICES;
mutex_lock(&register_mutex);
guard(mutex)(&register_mutex);
client = synths[card->number];
if (client == NULL) {
newclient = 1;
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (client == NULL) {
mutex_unlock(&register_mutex);
kfree(info);
if (client == NULL)
return -ENOMEM;
}
client->seq_client =
snd_seq_create_kernel_client(
card, 0, "%s", card->shortname[0] ?
(const char *)card->shortname : "External MIDI");
if (client->seq_client < 0) {
kfree(client);
mutex_unlock(&register_mutex);
kfree(info);
return -ENOMEM;
}
}
@ -396,9 +395,6 @@ snd_seq_midisynth_probe(struct device *_dev)
client->num_ports++;
if (newclient)
synths[card->number] = client;
mutex_unlock(&register_mutex);
kfree(info);
kfree(port);
return 0; /* success */
__nomem:
@ -411,9 +407,6 @@ snd_seq_midisynth_probe(struct device *_dev)
snd_seq_delete_kernel_client(client->seq_client);
kfree(client);
}
kfree(info);
kfree(port);
mutex_unlock(&register_mutex);
return -ENOMEM;
}
@ -427,12 +420,10 @@ snd_seq_midisynth_remove(struct device *_dev)
struct snd_card *card = dev->card;
int device = dev->device, p, ports;
mutex_lock(&register_mutex);
guard(mutex)(&register_mutex);
client = synths[card->number];
if (client == NULL || client->ports[device] == NULL) {
mutex_unlock(&register_mutex);
if (client == NULL || client->ports[device] == NULL)
return -ENODEV;
}
ports = client->ports_per_device[device];
client->ports_per_device[device] = 0;
msynth = client->ports[device];
@ -446,7 +437,6 @@ snd_seq_midisynth_remove(struct device *_dev)
synths[card->number] = NULL;
kfree(client);
}
mutex_unlock(&register_mutex);
return 0;
}

View File

@ -144,21 +144,15 @@ static inline void reset_encode(struct snd_midi_event *dev)
void snd_midi_event_reset_encode(struct snd_midi_event *dev)
{
unsigned long flags;
spin_lock_irqsave(&dev->lock, flags);
guard(spinlock_irqsave)(&dev->lock);
reset_encode(dev);
spin_unlock_irqrestore(&dev->lock, flags);
}
EXPORT_SYMBOL(snd_midi_event_reset_encode);
void snd_midi_event_reset_decode(struct snd_midi_event *dev)
{
unsigned long flags;
spin_lock_irqsave(&dev->lock, flags);
guard(spinlock_irqsave)(&dev->lock);
dev->lastcmd = 0xff;
spin_unlock_irqrestore(&dev->lock, flags);
}
EXPORT_SYMBOL(snd_midi_event_reset_decode);
@ -177,7 +171,6 @@ bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c,
struct snd_seq_event *ev)
{
bool rc = false;
unsigned long flags;
if (c >= MIDI_CMD_COMMON_CLOCK) {
/* real-time event */
@ -187,7 +180,7 @@ bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c,
return ev->type != SNDRV_SEQ_EVENT_NONE;
}
spin_lock_irqsave(&dev->lock, flags);
guard(spinlock_irqsave)(&dev->lock);
if ((c & 0x80) &&
(c != MIDI_CMD_COMMON_SYSEX_END || dev->type != ST_SYSEX)) {
/* new command */
@ -236,7 +229,6 @@ bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c,
}
}
spin_unlock_irqrestore(&dev->lock, flags);
return rc;
}
EXPORT_SYMBOL(snd_midi_event_encode_byte);

View File

@ -48,17 +48,15 @@ struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client,
if (client == NULL)
return NULL;
read_lock(&client->ports_lock);
guard(read_lock)(&client->ports_lock);
list_for_each_entry(port, &client->ports_list_head, list) {
if (port->addr.port == num) {
if (port->closing)
break; /* deleting now */
snd_use_lock_use(&port->use_lock);
read_unlock(&client->ports_lock);
return port;
}
}
read_unlock(&client->ports_lock);
return NULL; /* not found */
}
@ -73,7 +71,7 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
num = pinfo->addr.port;
found = NULL;
read_lock(&client->ports_lock);
guard(read_lock)(&client->ports_lock);
list_for_each_entry(port, &client->ports_list_head, list) {
if ((port->capability & SNDRV_SEQ_PORT_CAP_INACTIVE) &&
!check_inactive)
@ -93,7 +91,6 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
else
snd_use_lock_use(&found->use_lock);
}
read_unlock(&client->ports_lock);
return found;
}
@ -145,13 +142,12 @@ int snd_seq_create_port(struct snd_seq_client *client, int port,
snd_use_lock_use(&new_port->use_lock);
num = max(port, 0);
mutex_lock(&client->ports_mutex);
write_lock_irq(&client->ports_lock);
guard(mutex)(&client->ports_mutex);
guard(write_lock_irq)(&client->ports_lock);
list_for_each_entry(p, &client->ports_list_head, list) {
if (p->addr.port == port) {
kfree(new_port);
num = -EBUSY;
goto unlock;
return -EBUSY;
}
if (p->addr.port > num)
break;
@ -164,9 +160,6 @@ int snd_seq_create_port(struct snd_seq_client *client, int port,
new_port->addr.port = num; /* store the port number in the port */
sprintf(new_port->name, "port-%d", num);
*port_ret = new_port;
unlock:
write_unlock_irq(&client->ports_lock);
mutex_unlock(&client->ports_mutex);
return num;
}
@ -281,19 +274,18 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port)
{
struct snd_seq_client_port *found = NULL, *p;
mutex_lock(&client->ports_mutex);
write_lock_irq(&client->ports_lock);
list_for_each_entry(p, &client->ports_list_head, list) {
if (p->addr.port == port) {
/* ok found. delete from the list at first */
list_del(&p->list);
client->num_ports--;
found = p;
break;
scoped_guard(mutex, &client->ports_mutex) {
guard(write_lock_irq)(&client->ports_lock);
list_for_each_entry(p, &client->ports_list_head, list) {
if (p->addr.port == port) {
/* ok found. delete from the list at first */
list_del(&p->list);
client->num_ports--;
found = p;
break;
}
}
}
write_unlock_irq(&client->ports_lock);
mutex_unlock(&client->ports_mutex);
if (found)
return port_delete(client, found);
else
@ -309,16 +301,16 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
/* move the port list to deleted_list, and
* clear the port list in the client data.
*/
mutex_lock(&client->ports_mutex);
write_lock_irq(&client->ports_lock);
if (! list_empty(&client->ports_list_head)) {
list_add(&deleted_list, &client->ports_list_head);
list_del_init(&client->ports_list_head);
} else {
INIT_LIST_HEAD(&deleted_list);
guard(mutex)(&client->ports_mutex);
scoped_guard(write_lock_irq, &client->ports_lock) {
if (!list_empty(&client->ports_list_head)) {
list_add(&deleted_list, &client->ports_list_head);
list_del_init(&client->ports_list_head);
} else {
INIT_LIST_HEAD(&deleted_list);
}
client->num_ports = 0;
}
client->num_ports = 0;
write_unlock_irq(&client->ports_lock);
/* remove each port in deleted_list */
list_for_each_entry_safe(port, tmp, &deleted_list, list) {
@ -326,7 +318,6 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port);
port_delete(client, port);
}
mutex_unlock(&client->ports_mutex);
return 0;
}
@ -506,42 +497,37 @@ static int check_and_subscribe_port(struct snd_seq_client *client,
int err;
grp = is_src ? &port->c_src : &port->c_dest;
err = -EBUSY;
down_write(&grp->list_mutex);
guard(rwsem_write)(&grp->list_mutex);
if (exclusive) {
if (!list_empty(&grp->list_head))
goto __error;
return -EBUSY;
} else {
if (grp->exclusive)
goto __error;
return -EBUSY;
/* check whether already exists */
list_for_each(p, &grp->list_head) {
s = get_subscriber(p, is_src);
if (match_subs_info(&subs->info, &s->info))
goto __error;
return -EBUSY;
}
}
err = subscribe_port(client, port, grp, &subs->info, ack);
if (err < 0) {
grp->exclusive = 0;
goto __error;
return err;
}
/* add to list */
write_lock_irq(&grp->list_lock);
guard(write_lock_irq)(&grp->list_lock);
if (is_src)
list_add_tail(&subs->src_list, &grp->list_head);
else
list_add_tail(&subs->dest_list, &grp->list_head);
grp->exclusive = exclusive;
atomic_inc(&subs->ref_count);
write_unlock_irq(&grp->list_lock);
err = 0;
__error:
up_write(&grp->list_mutex);
return err;
return 0;
}
/* called with grp->list_mutex held */
@ -556,12 +542,12 @@ static void __delete_and_unsubscribe_port(struct snd_seq_client *client,
grp = is_src ? &port->c_src : &port->c_dest;
list = is_src ? &subs->src_list : &subs->dest_list;
write_lock_irq(&grp->list_lock);
empty = list_empty(list);
if (!empty)
list_del_init(list);
grp->exclusive = 0;
write_unlock_irq(&grp->list_lock);
scoped_guard(write_lock_irq, &grp->list_lock) {
empty = list_empty(list);
if (!empty)
list_del_init(list);
grp->exclusive = 0;
}
if (!empty)
unsubscribe_port(client, port, grp, &subs->info, ack);
@ -575,9 +561,8 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client,
struct snd_seq_port_subs_info *grp;
grp = is_src ? &port->c_src : &port->c_dest;
down_write(&grp->list_mutex);
guard(rwsem_write)(&grp->list_mutex);
__delete_and_unsubscribe_port(client, port, subs, is_src, ack);
up_write(&grp->list_mutex);
}
/* connect two ports */
@ -639,18 +624,18 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
/* always start from deleting the dest port for avoiding concurrent
* deletions
*/
down_write(&dest->list_mutex);
/* look for the connection */
list_for_each_entry(subs, &dest->list_head, dest_list) {
if (match_subs_info(info, &subs->info)) {
__delete_and_unsubscribe_port(dest_client, dest_port,
subs, false,
connector->number != dest_client->number);
err = 0;
break;
scoped_guard(rwsem_write, &dest->list_mutex) {
/* look for the connection */
list_for_each_entry(subs, &dest->list_head, dest_list) {
if (match_subs_info(info, &subs->info)) {
__delete_and_unsubscribe_port(dest_client, dest_port,
subs, false,
connector->number != dest_client->number);
err = 0;
break;
}
}
}
up_write(&dest->list_mutex);
if (err < 0)
return err;
@ -669,7 +654,7 @@ int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
struct snd_seq_subscribers *s;
int err = -ENOENT;
down_read(&src_grp->list_mutex);
guard(rwsem_read)(&src_grp->list_mutex);
list_for_each_entry(s, &src_grp->list_head, src_list) {
if (addr_match(dest_addr, &s->info.dest)) {
*subs = s->info;
@ -677,7 +662,6 @@ int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
break;
}
}
up_read(&src_grp->list_mutex);
return err;
}

View File

@ -132,7 +132,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
struct snd_seq_event_cell * cell)
{
struct snd_seq_event_cell *cur, *prev;
unsigned long flags;
int count;
int prior;
@ -142,7 +141,7 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
/* check flags */
prior = (cell->event.flags & SNDRV_SEQ_PRIORITY_MASK);
spin_lock_irqsave(&f->lock, flags);
guard(spinlock_irqsave)(&f->lock);
/* check if this element needs to inserted at the end (ie. ordered
data is inserted) This will be very likeley if a sequencer
@ -154,7 +153,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
f->tail = cell;
cell->next = NULL;
f->cells++;
spin_unlock_irqrestore(&f->lock, flags);
return 0;
}
}
@ -179,7 +177,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
prev = cur;
cur = cur->next;
if (! --count) {
spin_unlock_irqrestore(&f->lock, flags);
pr_err("ALSA: seq: cannot find a pointer.. infinite loop?\n");
return -EINVAL;
}
@ -195,7 +192,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
if (cur == NULL) /* reached end of the list */
f->tail = cell;
f->cells++;
spin_unlock_irqrestore(&f->lock, flags);
return 0;
}
@ -213,14 +209,13 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f,
void *current_time)
{
struct snd_seq_event_cell *cell;
unsigned long flags;
if (f == NULL) {
pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
return NULL;
}
spin_lock_irqsave(&f->lock, flags);
guard(spinlock_irqsave)(&f->lock);
cell = f->head;
if (cell && current_time && !event_is_ready(&cell->event, current_time))
cell = NULL;
@ -235,7 +230,6 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f,
f->cells--;
}
spin_unlock_irqrestore(&f->lock, flags);
return cell;
}
@ -249,73 +243,43 @@ int snd_seq_prioq_avail(struct snd_seq_prioq * f)
return f->cells;
}
static inline int prioq_match(struct snd_seq_event_cell *cell,
int client, int timestamp)
{
if (cell->event.source.client == client ||
cell->event.dest.client == client)
return 1;
if (!timestamp)
return 0;
switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) {
case SNDRV_SEQ_TIME_STAMP_TICK:
if (cell->event.time.tick)
return 1;
break;
case SNDRV_SEQ_TIME_STAMP_REAL:
if (cell->event.time.time.tv_sec ||
cell->event.time.time.tv_nsec)
return 1;
break;
}
return 0;
}
/* remove cells for left client */
void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
/* remove cells matching with the condition */
static void prioq_remove_cells(struct snd_seq_prioq *f,
bool (*match)(struct snd_seq_event_cell *cell,
void *arg),
void *arg)
{
register struct snd_seq_event_cell *cell, *next;
unsigned long flags;
struct snd_seq_event_cell *prev = NULL;
struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext;
/* collect all removed cells */
spin_lock_irqsave(&f->lock, flags);
cell = f->head;
while (cell) {
next = cell->next;
if (prioq_match(cell, client, timestamp)) {
/* remove cell from prioq */
if (cell == f->head) {
f->head = cell->next;
} else {
prev->next = cell->next;
scoped_guard(spinlock_irqsave, &f->lock) {
for (cell = f->head; cell; cell = next) {
next = cell->next;
if (!match(cell, arg)) {
prev = cell;
continue;
}
/* remove cell from prioq */
if (cell == f->head)
f->head = cell->next;
else
prev->next = cell->next;
if (cell == f->tail)
f->tail = cell->next;
f->cells--;
/* add cell to free list */
cell->next = NULL;
if (freefirst == NULL) {
if (freefirst == NULL)
freefirst = cell;
} else {
else
freeprev->next = cell;
}
freeprev = cell;
} else {
#if 0
pr_debug("ALSA: seq: type = %i, source = %i, dest = %i, "
"client = %i\n",
cell->event.type,
cell->event.source.client,
cell->event.dest.client,
client);
#endif
prev = cell;
}
cell = next;
}
spin_unlock_irqrestore(&f->lock, flags);
/* remove selected cells */
while (freefirst) {
@ -325,22 +289,68 @@ void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
}
}
static int prioq_remove_match(struct snd_seq_remove_events *info,
struct snd_seq_event *ev)
struct prioq_match_arg {
int client;
int timestamp;
};
static inline bool prioq_match(struct snd_seq_event_cell *cell, void *arg)
{
struct prioq_match_arg *v = arg;
if (cell->event.source.client == v->client ||
cell->event.dest.client == v->client)
return true;
if (!v->timestamp)
return false;
switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) {
case SNDRV_SEQ_TIME_STAMP_TICK:
if (cell->event.time.tick)
return true;
break;
case SNDRV_SEQ_TIME_STAMP_REAL:
if (cell->event.time.time.tv_sec ||
cell->event.time.time.tv_nsec)
return true;
break;
}
return false;
}
/* remove cells for left client */
void snd_seq_prioq_leave(struct snd_seq_prioq *f, int client, int timestamp)
{
struct prioq_match_arg arg = { client, timestamp };
return prioq_remove_cells(f, prioq_match, &arg);
}
struct prioq_remove_match_arg {
int client;
struct snd_seq_remove_events *info;
};
static bool prioq_remove_match(struct snd_seq_event_cell *cell, void *arg)
{
struct prioq_remove_match_arg *v = arg;
struct snd_seq_event *ev = &cell->event;
struct snd_seq_remove_events *info = v->info;
int res;
if (ev->source.client != v->client)
return false;
if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) {
if (ev->dest.client != info->dest.client ||
ev->dest.port != info->dest.port)
return 0;
return false;
}
if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST_CHANNEL) {
if (! snd_seq_ev_is_channel_type(ev))
return 0;
return false;
/* data.note.channel and data.control.channel are identical */
if (ev->data.note.channel != info->channel)
return 0;
return false;
}
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_AFTER) {
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK)
@ -348,7 +358,7 @@ static int prioq_remove_match(struct snd_seq_remove_events *info,
else
res = snd_seq_compare_real_time(&ev->time.time, &info->time.time);
if (!res)
return 0;
return false;
}
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_BEFORE) {
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK)
@ -356,81 +366,35 @@ static int prioq_remove_match(struct snd_seq_remove_events *info,
else
res = snd_seq_compare_real_time(&ev->time.time, &info->time.time);
if (res)
return 0;
return false;
}
if (info->remove_mode & SNDRV_SEQ_REMOVE_EVENT_TYPE) {
if (ev->type != info->type)
return 0;
return false;
}
if (info->remove_mode & SNDRV_SEQ_REMOVE_IGNORE_OFF) {
/* Do not remove off events */
switch (ev->type) {
case SNDRV_SEQ_EVENT_NOTEOFF:
/* case SNDRV_SEQ_EVENT_SAMPLE_STOP: */
return 0;
return false;
default:
break;
}
}
if (info->remove_mode & SNDRV_SEQ_REMOVE_TAG_MATCH) {
if (info->tag != ev->tag)
return 0;
return false;
}
return 1;
return true;
}
/* remove cells matching remove criteria */
void snd_seq_prioq_remove_events(struct snd_seq_prioq * f, int client,
struct snd_seq_remove_events *info)
{
struct snd_seq_event_cell *cell, *next;
unsigned long flags;
struct snd_seq_event_cell *prev = NULL;
struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext;
struct prioq_remove_match_arg arg = { client, info };
/* collect all removed cells */
spin_lock_irqsave(&f->lock, flags);
cell = f->head;
while (cell) {
next = cell->next;
if (cell->event.source.client == client &&
prioq_remove_match(info, &cell->event)) {
/* remove cell from prioq */
if (cell == f->head) {
f->head = cell->next;
} else {
prev->next = cell->next;
}
if (cell == f->tail)
f->tail = cell->next;
f->cells--;
/* add cell to free list */
cell->next = NULL;
if (freefirst == NULL) {
freefirst = cell;
} else {
freeprev->next = cell;
}
freeprev = cell;
} else {
prev = cell;
}
cell = next;
}
spin_unlock_irqrestore(&f->lock, flags);
/* remove selected cells */
while (freefirst) {
freenext = freefirst->next;
snd_seq_cell_free(freefirst);
freefirst = freenext;
}
return prioq_remove_cells(f, prioq_remove_match, &arg);
}

View File

@ -50,43 +50,35 @@ int snd_seq_queue_get_cur_queues(void)
static int queue_list_add(struct snd_seq_queue *q)
{
int i;
unsigned long flags;
spin_lock_irqsave(&queue_list_lock, flags);
guard(spinlock_irqsave)(&queue_list_lock);
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if (! queue_list[i]) {
queue_list[i] = q;
q->queue = i;
num_queues++;
spin_unlock_irqrestore(&queue_list_lock, flags);
return i;
}
}
spin_unlock_irqrestore(&queue_list_lock, flags);
return -1;
}
static struct snd_seq_queue *queue_list_remove(int id, int client)
{
struct snd_seq_queue *q;
unsigned long flags;
spin_lock_irqsave(&queue_list_lock, flags);
guard(spinlock_irqsave)(&queue_list_lock);
q = queue_list[id];
if (q) {
spin_lock(&q->owner_lock);
guard(spinlock)(&q->owner_lock);
if (q->owner == client) {
/* found */
q->klocked = 1;
spin_unlock(&q->owner_lock);
queue_list[id] = NULL;
num_queues--;
spin_unlock_irqrestore(&queue_list_lock, flags);
return q;
}
spin_unlock(&q->owner_lock);
}
spin_unlock_irqrestore(&queue_list_lock, flags);
return NULL;
}
@ -203,15 +195,13 @@ int snd_seq_queue_delete(int client, int queueid)
struct snd_seq_queue *queueptr(int queueid)
{
struct snd_seq_queue *q;
unsigned long flags;
if (queueid < 0 || queueid >= SNDRV_SEQ_MAX_QUEUES)
return NULL;
spin_lock_irqsave(&queue_list_lock, flags);
guard(spinlock_irqsave)(&queue_list_lock);
q = queue_list[queueid];
if (q)
snd_use_lock_use(&q->use_lock);
spin_unlock_irqrestore(&queue_list_lock, flags);
return q;
}
@ -239,7 +229,6 @@ struct snd_seq_queue *snd_seq_queue_find_name(char *name)
void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
{
unsigned long flags;
struct snd_seq_event_cell *cell;
snd_seq_tick_time_t cur_tick;
snd_seq_real_time_t cur_time;
@ -249,14 +238,13 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
return;
/* make this function non-reentrant */
spin_lock_irqsave(&q->check_lock, flags);
if (q->check_blocked) {
q->check_again = 1;
spin_unlock_irqrestore(&q->check_lock, flags);
return; /* other thread is already checking queues */
scoped_guard(spinlock_irqsave, &q->check_lock) {
if (q->check_blocked) {
q->check_again = 1;
return; /* other thread is already checking queues */
}
q->check_blocked = 1;
}
q->check_blocked = 1;
spin_unlock_irqrestore(&q->check_lock, flags);
__again:
/* Process tick queue... */
@ -283,16 +271,14 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
out:
/* free lock */
spin_lock_irqsave(&q->check_lock, flags);
if (q->check_again) {
q->check_again = 0;
if (processed < MAX_CELL_PROCESSES_IN_QUEUE) {
spin_unlock_irqrestore(&q->check_lock, flags);
goto __again;
scoped_guard(spinlock_irqsave, &q->check_lock) {
if (q->check_again) {
q->check_again = 0;
if (processed < MAX_CELL_PROCESSES_IN_QUEUE)
goto __again;
}
q->check_blocked = 0;
}
q->check_blocked = 0;
spin_unlock_irqrestore(&q->check_lock, flags);
}
@ -361,25 +347,20 @@ static inline int check_access(struct snd_seq_queue *q, int client)
*/
static int queue_access_lock(struct snd_seq_queue *q, int client)
{
unsigned long flags;
int access_ok;
spin_lock_irqsave(&q->owner_lock, flags);
guard(spinlock_irqsave)(&q->owner_lock);
access_ok = check_access(q, client);
if (access_ok)
q->klocked = 1;
spin_unlock_irqrestore(&q->owner_lock, flags);
return access_ok;
}
/* unlock the queue */
static inline void queue_access_unlock(struct snd_seq_queue *q)
{
unsigned long flags;
spin_lock_irqsave(&q->owner_lock, flags);
guard(spinlock_irqsave)(&q->owner_lock);
q->klocked = 0;
spin_unlock_irqrestore(&q->owner_lock, flags);
}
/* exported - only checking permission */
@ -387,13 +368,11 @@ int snd_seq_queue_check_access(int queueid, int client)
{
struct snd_seq_queue *q = queueptr(queueid);
int access_ok;
unsigned long flags;
if (! q)
return 0;
spin_lock_irqsave(&q->owner_lock, flags);
access_ok = check_access(q, client);
spin_unlock_irqrestore(&q->owner_lock, flags);
scoped_guard(spinlock_irqsave, &q->owner_lock)
access_ok = check_access(q, client);
queuefree(q);
return access_ok;
}
@ -406,7 +385,6 @@ int snd_seq_queue_check_access(int queueid, int client)
int snd_seq_queue_set_owner(int queueid, int client, int locked)
{
struct snd_seq_queue *q = queueptr(queueid);
unsigned long flags;
if (q == NULL)
return -EINVAL;
@ -416,10 +394,10 @@ int snd_seq_queue_set_owner(int queueid, int client, int locked)
return -EPERM;
}
spin_lock_irqsave(&q->owner_lock, flags);
q->locked = locked ? 1 : 0;
q->owner = client;
spin_unlock_irqrestore(&q->owner_lock, flags);
scoped_guard(spinlock_irqsave, &q->owner_lock) {
q->locked = locked ? 1 : 0;
q->owner = client;
}
queue_access_unlock(q);
queuefree(q);
@ -750,10 +728,10 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry,
else
bpm = 0;
spin_lock_irq(&q->owner_lock);
locked = q->locked;
owner = q->owner;
spin_unlock_irq(&q->owner_lock);
scoped_guard(spinlock_irq, &q->owner_lock) {
locked = q->locked;
owner = q->owner;
}
snd_iprintf(buffer, "queue %d: [%s]\n", q->queue, q->name);
snd_iprintf(buffer, "owned by client : %d\n", owner);

View File

@ -75,9 +75,7 @@ void snd_seq_timer_delete(struct snd_seq_timer **tmr)
void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
{
unsigned long flags;
spin_lock_irqsave(&tmr->lock, flags);
guard(spinlock_irqsave)(&tmr->lock);
/* setup defaults */
tmr->ppq = 96; /* 96 PPQ */
tmr->tempo = 500000; /* 120 BPM */
@ -93,7 +91,6 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
tmr->preferred_resolution = seq_default_timer_resolution;
tmr->skew = tmr->skew_base = SKEW_BASE;
spin_unlock_irqrestore(&tmr->lock, flags);
}
static void seq_timer_reset(struct snd_seq_timer *tmr)
@ -108,11 +105,8 @@ static void seq_timer_reset(struct snd_seq_timer *tmr)
void snd_seq_timer_reset(struct snd_seq_timer *tmr)
{
unsigned long flags;
spin_lock_irqsave(&tmr->lock, flags);
guard(spinlock_irqsave)(&tmr->lock);
seq_timer_reset(tmr);
spin_unlock_irqrestore(&tmr->lock, flags);
}
@ -121,7 +115,6 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
unsigned long resolution,
unsigned long ticks)
{
unsigned long flags;
struct snd_seq_queue *q = timeri->callback_data;
struct snd_seq_timer *tmr;
@ -130,30 +123,28 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
tmr = q->timer;
if (tmr == NULL)
return;
spin_lock_irqsave(&tmr->lock, flags);
if (!tmr->running) {
spin_unlock_irqrestore(&tmr->lock, flags);
return;
scoped_guard(spinlock_irqsave, &tmr->lock) {
if (!tmr->running)
return;
resolution *= ticks;
if (tmr->skew != tmr->skew_base) {
/* FIXME: assuming skew_base = 0x10000 */
resolution = (resolution >> 16) * tmr->skew +
(((resolution & 0xffff) * tmr->skew) >> 16);
}
/* update timer */
snd_seq_inc_time_nsec(&tmr->cur_time, resolution);
/* calculate current tick */
snd_seq_timer_update_tick(&tmr->tick, resolution);
/* register actual time of this timer update */
ktime_get_ts64(&tmr->last_update);
}
resolution *= ticks;
if (tmr->skew != tmr->skew_base) {
/* FIXME: assuming skew_base = 0x10000 */
resolution = (resolution >> 16) * tmr->skew +
(((resolution & 0xffff) * tmr->skew) >> 16);
}
/* update timer */
snd_seq_inc_time_nsec(&tmr->cur_time, resolution);
/* calculate current tick */
snd_seq_timer_update_tick(&tmr->tick, resolution);
/* register actual time of this timer update */
ktime_get_ts64(&tmr->last_update);
spin_unlock_irqrestore(&tmr->lock, flags);
/* check queues and dispatch events */
snd_seq_check_queue(q, 1, 0);
}
@ -161,18 +152,15 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
/* set current tempo */
int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo)
{
unsigned long flags;
if (snd_BUG_ON(!tmr))
return -EINVAL;
if (tempo <= 0)
return -EINVAL;
spin_lock_irqsave(&tmr->lock, flags);
guard(spinlock_irqsave)(&tmr->lock);
if ((unsigned int)tempo != tmr->tempo) {
tmr->tempo = tempo;
snd_seq_timer_set_tick_resolution(tmr);
}
spin_unlock_irqrestore(&tmr->lock, flags);
return 0;
}
@ -180,17 +168,15 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo)
int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq)
{
int changed;
unsigned long flags;
if (snd_BUG_ON(!tmr))
return -EINVAL;
if (tempo <= 0 || ppq <= 0)
return -EINVAL;
spin_lock_irqsave(&tmr->lock, flags);
guard(spinlock_irqsave)(&tmr->lock);
if (tmr->running && (ppq != tmr->ppq)) {
/* refuse to change ppq on running timers */
/* because it will upset the song position (ticks) */
spin_unlock_irqrestore(&tmr->lock, flags);
pr_debug("ALSA: seq: cannot change ppq of a running timer\n");
return -EBUSY;
}
@ -199,7 +185,6 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq)
tmr->ppq = ppq;
if (changed)
snd_seq_timer_set_tick_resolution(tmr);
spin_unlock_irqrestore(&tmr->lock, flags);
return 0;
}
@ -207,15 +192,12 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq)
int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr,
snd_seq_tick_time_t position)
{
unsigned long flags;
if (snd_BUG_ON(!tmr))
return -EINVAL;
spin_lock_irqsave(&tmr->lock, flags);
guard(spinlock_irqsave)(&tmr->lock);
tmr->tick.cur_tick = position;
tmr->tick.fraction = 0;
spin_unlock_irqrestore(&tmr->lock, flags);
return 0;
}
@ -223,15 +205,12 @@ int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr,
int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr,
snd_seq_real_time_t position)
{
unsigned long flags;
if (snd_BUG_ON(!tmr))
return -EINVAL;
snd_seq_sanity_real_time(&position);
spin_lock_irqsave(&tmr->lock, flags);
guard(spinlock_irqsave)(&tmr->lock);
tmr->cur_time = position;
spin_unlock_irqrestore(&tmr->lock, flags);
return 0;
}
@ -239,8 +218,6 @@ int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr,
int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew,
unsigned int base)
{
unsigned long flags;
if (snd_BUG_ON(!tmr))
return -EINVAL;
@ -249,9 +226,8 @@ int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew,
pr_debug("ALSA: seq: invalid skew base 0x%x\n", base);
return -EINVAL;
}
spin_lock_irqsave(&tmr->lock, flags);
guard(spinlock_irqsave)(&tmr->lock);
tmr->skew = skew;
spin_unlock_irqrestore(&tmr->lock, flags);
return 0;
}
@ -296,12 +272,12 @@ int snd_seq_timer_open(struct snd_seq_queue *q)
snd_timer_instance_free(t);
return err;
}
spin_lock_irq(&tmr->lock);
if (tmr->timeri)
err = -EBUSY;
else
tmr->timeri = t;
spin_unlock_irq(&tmr->lock);
scoped_guard(spinlock_irq, &tmr->lock) {
if (tmr->timeri)
err = -EBUSY;
else
tmr->timeri = t;
}
if (err < 0) {
snd_timer_close(t);
snd_timer_instance_free(t);
@ -318,10 +294,10 @@ int snd_seq_timer_close(struct snd_seq_queue *q)
tmr = q->timer;
if (snd_BUG_ON(!tmr))
return -EINVAL;
spin_lock_irq(&tmr->lock);
t = tmr->timeri;
tmr->timeri = NULL;
spin_unlock_irq(&tmr->lock);
scoped_guard(spinlock_irq, &tmr->lock) {
t = tmr->timeri;
tmr->timeri = NULL;
}
if (t) {
snd_timer_close(t);
snd_timer_instance_free(t);
@ -342,13 +318,8 @@ static int seq_timer_stop(struct snd_seq_timer *tmr)
int snd_seq_timer_stop(struct snd_seq_timer *tmr)
{
unsigned long flags;
int err;
spin_lock_irqsave(&tmr->lock, flags);
err = seq_timer_stop(tmr);
spin_unlock_irqrestore(&tmr->lock, flags);
return err;
guard(spinlock_irqsave)(&tmr->lock);
return seq_timer_stop(tmr);
}
static int initialize_timer(struct snd_seq_timer *tmr)
@ -398,13 +369,8 @@ static int seq_timer_start(struct snd_seq_timer *tmr)
int snd_seq_timer_start(struct snd_seq_timer *tmr)
{
unsigned long flags;
int err;
spin_lock_irqsave(&tmr->lock, flags);
err = seq_timer_start(tmr);
spin_unlock_irqrestore(&tmr->lock, flags);
return err;
guard(spinlock_irqsave)(&tmr->lock);
return seq_timer_start(tmr);
}
static int seq_timer_continue(struct snd_seq_timer *tmr)
@ -426,13 +392,8 @@ static int seq_timer_continue(struct snd_seq_timer *tmr)
int snd_seq_timer_continue(struct snd_seq_timer *tmr)
{
unsigned long flags;
int err;
spin_lock_irqsave(&tmr->lock, flags);
err = seq_timer_continue(tmr);
spin_unlock_irqrestore(&tmr->lock, flags);
return err;
guard(spinlock_irqsave)(&tmr->lock);
return seq_timer_continue(tmr);
}
/* return current 'real' time. use timeofday() to get better granularity. */
@ -440,9 +401,8 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr,
bool adjust_ktime)
{
snd_seq_real_time_t cur_time;
unsigned long flags;
spin_lock_irqsave(&tmr->lock, flags);
guard(spinlock_irqsave)(&tmr->lock);
cur_time = tmr->cur_time;
if (adjust_ktime && tmr->running) {
struct timespec64 tm;
@ -453,7 +413,6 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr,
cur_time.tv_sec += tm.tv_sec;
snd_seq_sanity_real_time(&cur_time);
}
spin_unlock_irqrestore(&tmr->lock, flags);
return cur_time;
}
@ -461,13 +420,8 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr,
high PPQ values) */
snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr)
{
snd_seq_tick_time_t cur_tick;
unsigned long flags;
spin_lock_irqsave(&tmr->lock, flags);
cur_tick = tmr->tick.cur_tick;
spin_unlock_irqrestore(&tmr->lock, flags);
return cur_tick;
guard(spinlock_irqsave)(&tmr->lock);
return tmr->tick.cur_tick;
}
@ -486,19 +440,18 @@ void snd_seq_info_timer_read(struct snd_info_entry *entry,
q = queueptr(idx);
if (q == NULL)
continue;
mutex_lock(&q->timer_mutex);
tmr = q->timer;
if (!tmr)
goto unlock;
ti = tmr->timeri;
if (!ti)
goto unlock;
snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name);
resolution = snd_timer_resolution(ti) * tmr->ticks;
snd_iprintf(buffer, " Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000);
snd_iprintf(buffer, " Skew : %u / %u\n", tmr->skew, tmr->skew_base);
unlock:
mutex_unlock(&q->timer_mutex);
scoped_guard(mutex, &q->timer_mutex) {
tmr = q->timer;
if (!tmr)
break;
ti = tmr->timeri;
if (!ti)
break;
snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name);
resolution = snd_timer_resolution(ti) * tmr->ticks;
snd_iprintf(buffer, " Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000);
snd_iprintf(buffer, " Skew : %u / %u\n", tmr->skew, tmr->skew_base);
}
queuefree(q);
}
}

View File

@ -115,21 +115,19 @@ static int seq_ump_process_event(struct snd_seq_event *ev, int direct,
static int seq_ump_client_open(struct seq_ump_client *client, int dir)
{
struct snd_ump_endpoint *ump = client->ump;
int err = 0;
int err;
mutex_lock(&ump->open_mutex);
guard(mutex)(&ump->open_mutex);
if (dir == STR_OUT && !client->opened[dir]) {
err = snd_rawmidi_kernel_open(&ump->core, 0,
SNDRV_RAWMIDI_LFLG_OUTPUT |
SNDRV_RAWMIDI_LFLG_APPEND,
&client->out_rfile);
if (err < 0)
goto unlock;
return err;
}
client->opened[dir]++;
unlock:
mutex_unlock(&ump->open_mutex);
return err;
return 0;
}
/* close the rawmidi */
@ -137,11 +135,10 @@ static int seq_ump_client_close(struct seq_ump_client *client, int dir)
{
struct snd_ump_endpoint *ump = client->ump;
mutex_lock(&ump->open_mutex);
guard(mutex)(&ump->open_mutex);
if (!--client->opened[dir])
if (dir == STR_OUT)
snd_rawmidi_kernel_release(&client->out_rfile);
mutex_unlock(&ump->open_mutex);
return 0;
}
@ -217,15 +214,12 @@ static void fill_port_info(struct snd_seq_port_info *port,
static int seq_ump_group_init(struct seq_ump_client *client, int group_index)
{
struct seq_ump_group *group = &client->groups[group_index];
struct snd_seq_port_info *port;
struct snd_seq_port_info *port __free(kfree) = NULL;
struct snd_seq_port_callback pcallbacks;
int err;
port = kzalloc(sizeof(*port), GFP_KERNEL);
if (!port) {
err = -ENOMEM;
goto error;
}
if (!port)
return -ENOMEM;
fill_port_info(port, client, group);
port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
@ -238,24 +232,22 @@ static int seq_ump_group_init(struct seq_ump_client *client, int group_index)
pcallbacks.unuse = seq_ump_unuse;
pcallbacks.event_input = seq_ump_process_event;
port->kernel = &pcallbacks;
err = snd_seq_kernel_client_ctl(client->seq_client,
SNDRV_SEQ_IOCTL_CREATE_PORT,
port);
error:
kfree(port);
return err;
return snd_seq_kernel_client_ctl(client->seq_client,
SNDRV_SEQ_IOCTL_CREATE_PORT,
port);
}
/* update the sequencer ports; called from notify_fb_change callback */
static void update_port_infos(struct seq_ump_client *client)
{
struct snd_seq_port_info *old, *new;
struct snd_seq_port_info *old __free(kfree) = NULL;
struct snd_seq_port_info *new __free(kfree) = NULL;
int i, err;
old = kzalloc(sizeof(*old), GFP_KERNEL);
new = kzalloc(sizeof(*new), GFP_KERNEL);
if (!old || !new)
goto error;
return;
for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) {
old->addr.client = client->seq_client;
@ -264,7 +256,7 @@ static void update_port_infos(struct seq_ump_client *client)
SNDRV_SEQ_IOCTL_GET_PORT_INFO,
old);
if (err < 0)
goto error;
return;
fill_port_info(new, client, &client->groups[i]);
if (old->capability == new->capability &&
!strcmp(old->name, new->name))
@ -273,13 +265,10 @@ static void update_port_infos(struct seq_ump_client *client)
SNDRV_SEQ_IOCTL_SET_PORT_INFO,
new);
if (err < 0)
goto error;
return;
/* notify to system port */
snd_seq_system_client_ev_port_change(client->seq_client, i);
}
error:
kfree(new);
kfree(old);
}
/* update dir_bits and active flag for all groups in the client */
@ -334,7 +323,7 @@ static void update_group_attrs(struct seq_ump_client *client)
/* create a UMP Endpoint port */
static int create_ump_endpoint_port(struct seq_ump_client *client)
{
struct snd_seq_port_info *port;
struct snd_seq_port_info *port __free(kfree) = NULL;
struct snd_seq_port_callback pcallbacks;
unsigned int rawmidi_info = client->ump->core.info_flags;
int err;
@ -383,7 +372,6 @@ static int create_ump_endpoint_port(struct seq_ump_client *client)
err = snd_seq_kernel_client_ctl(client->seq_client,
SNDRV_SEQ_IOCTL_CREATE_PORT,
port);
kfree(port);
return err;
}

View File

@ -62,6 +62,13 @@ static void snd_virmidi_init_event(struct snd_virmidi *vmidi,
/*
* decode input event and put to read buffer of each opened file
*/
/* callback for snd_seq_dump_var_event(), bridging to snd_rawmidi_receive() */
static int dump_to_rawmidi(void *ptr, void *buf, int count)
{
return snd_rawmidi_receive(ptr, buf, count);
}
static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
struct snd_seq_event *ev,
bool atomic)
@ -80,7 +87,7 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
continue;
snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)snd_rawmidi_receive, vmidi->substream);
snd_seq_dump_var_event(ev, dump_to_rawmidi, vmidi->substream);
snd_midi_event_reset_decode(vmidi->parser);
} else {
len = snd_midi_event_decode(vmidi->parser, msg, sizeof(msg), ev);
@ -192,11 +199,10 @@ static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream)
vmidi->client = rdev->client;
vmidi->port = rdev->port;
runtime->private_data = vmidi;
down_write(&rdev->filelist_sem);
write_lock_irq(&rdev->filelist_lock);
list_add_tail(&vmidi->list, &rdev->filelist);
write_unlock_irq(&rdev->filelist_lock);
up_write(&rdev->filelist_sem);
scoped_guard(rwsem_write, &rdev->filelist_sem) {
guard(write_lock_irq)(&rdev->filelist_lock);
list_add_tail(&vmidi->list, &rdev->filelist);
}
vmidi->rdev = rdev;
return 0;
}
@ -236,11 +242,10 @@ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream)
struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
struct snd_virmidi *vmidi = substream->runtime->private_data;
down_write(&rdev->filelist_sem);
write_lock_irq(&rdev->filelist_lock);
list_del(&vmidi->list);
write_unlock_irq(&rdev->filelist_lock);
up_write(&rdev->filelist_sem);
scoped_guard(rwsem_write, &rdev->filelist_sem) {
guard(write_lock_irq)(&rdev->filelist_lock);
list_del(&vmidi->list);
}
snd_midi_event_free(vmidi->parser);
substream->runtime->private_data = NULL;
kfree(vmidi);
@ -356,26 +361,22 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev)
{
int client;
struct snd_seq_port_callback pcallbacks;
struct snd_seq_port_info *pinfo;
struct snd_seq_port_info *pinfo __free(kfree) = NULL;
int err;
if (rdev->client >= 0)
return 0;
pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
if (!pinfo) {
err = -ENOMEM;
goto __error;
}
if (!pinfo)
return -ENOMEM;
client = snd_seq_create_kernel_client(rdev->card, rdev->device,
"%s %d-%d", rdev->rmidi->name,
rdev->card->number,
rdev->device);
if (client < 0) {
err = client;
goto __error;
}
if (client < 0)
return client;
rdev->client = client;
/* create a port */
@ -403,15 +404,11 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev)
if (err < 0) {
snd_seq_delete_kernel_client(client);
rdev->client = -1;
goto __error;
return err;
}
rdev->port = pinfo->addr.port;
err = 0; /* success */
__error:
kfree(pinfo);
return err;
return 0; /* success */
}

View File

@ -49,7 +49,7 @@ static int snd_seq_bus_match(struct device *dev, struct device_driver *drv)
sdrv->argsize == sdev->argsize;
}
static struct bus_type snd_seq_bus_type = {
static const struct bus_type snd_seq_bus_type = {
.name = "snd_seq",
.match = snd_seq_bus_match,
};

View File

@ -103,7 +103,7 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
if (minor >= ARRAY_SIZE(snd_minors))
return NULL;
mutex_lock(&sound_mutex);
guard(mutex)(&sound_mutex);
mreg = snd_minors[minor];
if (mreg && mreg->type == type) {
private_data = mreg->private_data;
@ -111,7 +111,6 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
get_device(&mreg->card_ptr->card_dev);
} else
private_data = NULL;
mutex_unlock(&sound_mutex);
return private_data;
}
EXPORT_SYMBOL(snd_lookup_minor_data);
@ -150,17 +149,15 @@ static int snd_open(struct inode *inode, struct file *file)
if (minor >= ARRAY_SIZE(snd_minors))
return -ENODEV;
mutex_lock(&sound_mutex);
mptr = snd_minors[minor];
if (mptr == NULL) {
mptr = autoload_device(minor);
if (!mptr) {
mutex_unlock(&sound_mutex);
return -ENODEV;
scoped_guard(mutex, &sound_mutex) {
mptr = snd_minors[minor];
if (mptr == NULL) {
mptr = autoload_device(minor);
if (!mptr)
return -ENODEV;
}
new_fops = fops_get(mptr->f_ops);
}
new_fops = fops_get(mptr->f_ops);
mutex_unlock(&sound_mutex);
if (!new_fops)
return -ENODEV;
replace_fops(file, new_fops);
@ -269,7 +266,7 @@ int snd_register_device(int type, struct snd_card *card, int dev,
preg->f_ops = f_ops;
preg->private_data = private_data;
preg->card_ptr = card;
mutex_lock(&sound_mutex);
guard(mutex)(&sound_mutex);
minor = snd_find_free_minor(type, card, dev);
if (minor < 0) {
err = minor;
@ -284,7 +281,6 @@ int snd_register_device(int type, struct snd_card *card, int dev,
snd_minors[minor] = preg;
error:
mutex_unlock(&sound_mutex);
if (err < 0)
kfree(preg);
return err;
@ -305,7 +301,7 @@ int snd_unregister_device(struct device *dev)
int minor;
struct snd_minor *preg;
mutex_lock(&sound_mutex);
guard(mutex)(&sound_mutex);
for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
preg = snd_minors[minor];
if (preg && preg->dev == dev) {
@ -315,7 +311,6 @@ int snd_unregister_device(struct device *dev)
break;
}
}
mutex_unlock(&sound_mutex);
if (minor >= ARRAY_SIZE(snd_minors))
return -ENOENT;
return 0;
@ -355,7 +350,7 @@ static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_bu
int minor;
struct snd_minor *mptr;
mutex_lock(&sound_mutex);
guard(mutex)(&sound_mutex);
for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) {
mptr = snd_minors[minor];
if (!mptr)
@ -373,7 +368,6 @@ static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_bu
snd_iprintf(buffer, "%3i: : %s\n", minor,
snd_device_type_name(mptr->type));
}
mutex_unlock(&sound_mutex);
}
int __init snd_minor_info_init(void)

312
sound/core/sound_kunit.c Normal file
View File

@ -0,0 +1,312 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Sound core KUnit test
* Author: Ivan Orlov <ivan.orlov0322@gmail.com>
*/
#include <kunit/test.h>
#include <sound/core.h>
#include <sound/pcm.h>
#define SILENCE_BUFFER_MAX_FRAMES 260
#define SILENCE_BUFFER_SIZE (sizeof(u64) * SILENCE_BUFFER_MAX_FRAMES)
#define SILENCE(...) { __VA_ARGS__ }
#define DEFINE_FORMAT(fmt, pbits, wd, endianness, signd, silence_arr) { \
.format = SNDRV_PCM_FORMAT_##fmt, .physical_bits = pbits, \
.width = wd, .le = endianness, .sd = signd, .silence = silence_arr, \
.name = #fmt, \
}
#define WRONG_FORMAT_1 (__force snd_pcm_format_t)((__force int)SNDRV_PCM_FORMAT_LAST + 1)
#define WRONG_FORMAT_2 (__force snd_pcm_format_t)-1
#define VALID_NAME "ValidName"
#define NAME_W_SPEC_CHARS "In%v@1id name"
#define NAME_W_SPACE "Test name"
#define NAME_W_SPACE_REMOVED "Testname"
#define TEST_FIRST_COMPONENT "Component1"
#define TEST_SECOND_COMPONENT "Component2"
struct snd_format_test_data {
snd_pcm_format_t format;
int physical_bits;
int width;
int le;
int sd;
unsigned char silence[8];
unsigned char *name;
};
struct avail_test_data {
snd_pcm_uframes_t buffer_size;
snd_pcm_uframes_t hw_ptr;
snd_pcm_uframes_t appl_ptr;
snd_pcm_uframes_t expected_avail;
};
static struct snd_format_test_data valid_fmt[] = {
DEFINE_FORMAT(S8, 8, 8, -1, 1, SILENCE()),
DEFINE_FORMAT(U8, 8, 8, -1, 0, SILENCE(0x80)),
DEFINE_FORMAT(S16_LE, 16, 16, 1, 1, SILENCE()),
DEFINE_FORMAT(S16_BE, 16, 16, 0, 1, SILENCE()),
DEFINE_FORMAT(U16_LE, 16, 16, 1, 0, SILENCE(0x00, 0x80)),
DEFINE_FORMAT(U16_BE, 16, 16, 0, 0, SILENCE(0x80, 0x00)),
DEFINE_FORMAT(S24_LE, 32, 24, 1, 1, SILENCE()),
DEFINE_FORMAT(S24_BE, 32, 24, 0, 1, SILENCE()),
DEFINE_FORMAT(U24_LE, 32, 24, 1, 0, SILENCE(0x00, 0x00, 0x80)),
DEFINE_FORMAT(U24_BE, 32, 24, 0, 0, SILENCE(0x00, 0x80, 0x00, 0x00)),
DEFINE_FORMAT(S32_LE, 32, 32, 1, 1, SILENCE()),
DEFINE_FORMAT(S32_BE, 32, 32, 0, 1, SILENCE()),
DEFINE_FORMAT(U32_LE, 32, 32, 1, 0, SILENCE(0x00, 0x00, 0x00, 0x80)),
DEFINE_FORMAT(U32_BE, 32, 32, 0, 0, SILENCE(0x80, 0x00, 0x00, 0x00)),
DEFINE_FORMAT(FLOAT_LE, 32, 32, 1, -1, SILENCE()),
DEFINE_FORMAT(FLOAT_BE, 32, 32, 0, -1, SILENCE()),
DEFINE_FORMAT(FLOAT64_LE, 64, 64, 1, -1, SILENCE()),
DEFINE_FORMAT(FLOAT64_BE, 64, 64, 0, -1, SILENCE()),
DEFINE_FORMAT(IEC958_SUBFRAME_LE, 32, 32, 1, -1, SILENCE()),
DEFINE_FORMAT(IEC958_SUBFRAME_BE, 32, 32, 0, -1, SILENCE()),
DEFINE_FORMAT(MU_LAW, 8, 8, -1, -1, SILENCE(0x7f)),
DEFINE_FORMAT(A_LAW, 8, 8, -1, -1, SILENCE(0x55)),
DEFINE_FORMAT(IMA_ADPCM, 4, 4, -1, -1, SILENCE()),
DEFINE_FORMAT(G723_24, 3, 3, -1, -1, SILENCE()),
DEFINE_FORMAT(G723_40, 5, 5, -1, -1, SILENCE()),
DEFINE_FORMAT(DSD_U8, 8, 8, 1, 0, SILENCE(0x69)),
DEFINE_FORMAT(DSD_U16_LE, 16, 16, 1, 0, SILENCE(0x69, 0x69)),
DEFINE_FORMAT(DSD_U32_LE, 32, 32, 1, 0, SILENCE(0x69, 0x69, 0x69, 0x69)),
DEFINE_FORMAT(DSD_U16_BE, 16, 16, 0, 0, SILENCE(0x69, 0x69)),
DEFINE_FORMAT(DSD_U32_BE, 32, 32, 0, 0, SILENCE(0x69, 0x69, 0x69, 0x69)),
DEFINE_FORMAT(S20_LE, 32, 20, 1, 1, SILENCE()),
DEFINE_FORMAT(S20_BE, 32, 20, 0, 1, SILENCE()),
DEFINE_FORMAT(U20_LE, 32, 20, 1, 0, SILENCE(0x00, 0x00, 0x08, 0x00)),
DEFINE_FORMAT(U20_BE, 32, 20, 0, 0, SILENCE(0x00, 0x08, 0x00, 0x00)),
DEFINE_FORMAT(S24_3LE, 24, 24, 1, 1, SILENCE()),
DEFINE_FORMAT(S24_3BE, 24, 24, 0, 1, SILENCE()),
DEFINE_FORMAT(U24_3LE, 24, 24, 1, 0, SILENCE(0x00, 0x00, 0x80)),
DEFINE_FORMAT(U24_3BE, 24, 24, 0, 0, SILENCE(0x80, 0x00, 0x00)),
DEFINE_FORMAT(S20_3LE, 24, 20, 1, 1, SILENCE()),
DEFINE_FORMAT(S20_3BE, 24, 20, 0, 1, SILENCE()),
DEFINE_FORMAT(U20_3LE, 24, 20, 1, 0, SILENCE(0x00, 0x00, 0x08)),
DEFINE_FORMAT(U20_3BE, 24, 20, 0, 0, SILENCE(0x08, 0x00, 0x00)),
DEFINE_FORMAT(S18_3LE, 24, 18, 1, 1, SILENCE()),
DEFINE_FORMAT(S18_3BE, 24, 18, 0, 1, SILENCE()),
DEFINE_FORMAT(U18_3LE, 24, 18, 1, 0, SILENCE(0x00, 0x00, 0x02)),
DEFINE_FORMAT(U18_3BE, 24, 18, 0, 0, SILENCE(0x02, 0x00, 0x00)),
DEFINE_FORMAT(G723_24_1B, 8, 3, -1, -1, SILENCE()),
DEFINE_FORMAT(G723_40_1B, 8, 5, -1, -1, SILENCE()),
};
static void test_phys_format_size(struct kunit *test)
{
u32 i;
for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(valid_fmt[i].format),
valid_fmt[i].physical_bits);
}
KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(WRONG_FORMAT_1), -EINVAL);
KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(WRONG_FORMAT_2), -EINVAL);
}
static void test_format_width(struct kunit *test)
{
u32 i;
for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
KUNIT_EXPECT_EQ(test, snd_pcm_format_width(valid_fmt[i].format),
valid_fmt[i].width);
}
KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_1), -EINVAL);
KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_2), -EINVAL);
}
static void test_format_signed(struct kunit *test)
{
u32 i;
for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
KUNIT_EXPECT_EQ(test, snd_pcm_format_signed(valid_fmt[i].format),
valid_fmt[i].sd < 0 ? -EINVAL : valid_fmt[i].sd);
KUNIT_EXPECT_EQ(test, snd_pcm_format_unsigned(valid_fmt[i].format),
valid_fmt[i].sd < 0 ? -EINVAL : 1 - valid_fmt[i].sd);
}
KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_1), -EINVAL);
KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_2), -EINVAL);
}
static void test_format_endianness(struct kunit *test)
{
u32 i;
for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(valid_fmt[i].format),
valid_fmt[i].le < 0 ? -EINVAL : valid_fmt[i].le);
KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(valid_fmt[i].format),
valid_fmt[i].le < 0 ? -EINVAL : 1 - valid_fmt[i].le);
}
KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(WRONG_FORMAT_1), -EINVAL);
KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(WRONG_FORMAT_2), -EINVAL);
KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(WRONG_FORMAT_1), -EINVAL);
KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(WRONG_FORMAT_2), -EINVAL);
}
static void _test_fill_silence(struct kunit *test, struct snd_format_test_data *data,
u8 *buffer, size_t samples_count)
{
size_t sample_bytes = data->physical_bits >> 3;
u32 i;
KUNIT_ASSERT_EQ(test, snd_pcm_format_set_silence(data->format, buffer, samples_count), 0);
for (i = 0; i < samples_count * sample_bytes; i++)
KUNIT_EXPECT_EQ(test, buffer[i], data->silence[i % sample_bytes]);
}
static void test_format_fill_silence(struct kunit *test)
{
u32 buf_samples[] = { 10, 20, 32, 64, 129, SILENCE_BUFFER_MAX_FRAMES };
u8 *buffer;
u32 i, j;
buffer = kunit_kzalloc(test, SILENCE_BUFFER_SIZE, GFP_KERNEL);
for (i = 0; i < ARRAY_SIZE(buf_samples); i++) {
for (j = 0; j < ARRAY_SIZE(valid_fmt); j++)
_test_fill_silence(test, &valid_fmt[j], buffer, buf_samples[i]);
}
KUNIT_EXPECT_EQ(test, snd_pcm_format_set_silence(WRONG_FORMAT_1, buffer, 20), -EINVAL);
KUNIT_EXPECT_EQ(test, snd_pcm_format_set_silence(SNDRV_PCM_FORMAT_LAST, buffer, 0), 0);
}
static snd_pcm_uframes_t calculate_boundary(snd_pcm_uframes_t buffer_size)
{
snd_pcm_uframes_t boundary = buffer_size;
while (boundary * 2 <= 0x7fffffffUL - buffer_size)
boundary *= 2;
return boundary;
}
static struct avail_test_data p_avail_data[] = {
/* buf_size + hw_ptr < appl_ptr => avail = buf_size + hw_ptr - appl_ptr + boundary */
{ 128, 1000, 1129, 1073741824UL - 1 },
/*
* buf_size + hw_ptr - appl_ptr >= boundary =>
* => avail = buf_size + hw_ptr - appl_ptr - boundary
*/
{ 128, 1073741824UL, 10, 118 },
/* standard case: avail = buf_size + hw_ptr - appl_ptr */
{ 128, 1000, 1001, 127 },
};
static void test_playback_avail(struct kunit *test)
{
struct snd_pcm_runtime *r = kunit_kzalloc(test, sizeof(*r), GFP_KERNEL);
u32 i;
r->status = kunit_kzalloc(test, sizeof(*r->status), GFP_KERNEL);
r->control = kunit_kzalloc(test, sizeof(*r->control), GFP_KERNEL);
for (i = 0; i < ARRAY_SIZE(p_avail_data); i++) {
r->buffer_size = p_avail_data[i].buffer_size;
r->boundary = calculate_boundary(r->buffer_size);
r->status->hw_ptr = p_avail_data[i].hw_ptr;
r->control->appl_ptr = p_avail_data[i].appl_ptr;
KUNIT_EXPECT_EQ(test, snd_pcm_playback_avail(r), p_avail_data[i].expected_avail);
}
}
static struct avail_test_data c_avail_data[] = {
/* hw_ptr - appl_ptr < 0 => avail = hw_ptr - appl_ptr + boundary */
{ 128, 1000, 1001, 1073741824UL - 1 },
/* standard case: avail = hw_ptr - appl_ptr */
{ 128, 1001, 1000, 1 },
};
static void test_capture_avail(struct kunit *test)
{
struct snd_pcm_runtime *r = kunit_kzalloc(test, sizeof(*r), GFP_KERNEL);
u32 i;
r->status = kunit_kzalloc(test, sizeof(*r->status), GFP_KERNEL);
r->control = kunit_kzalloc(test, sizeof(*r->control), GFP_KERNEL);
for (i = 0; i < ARRAY_SIZE(c_avail_data); i++) {
r->buffer_size = c_avail_data[i].buffer_size;
r->boundary = calculate_boundary(r->buffer_size);
r->status->hw_ptr = c_avail_data[i].hw_ptr;
r->control->appl_ptr = c_avail_data[i].appl_ptr;
KUNIT_EXPECT_EQ(test, snd_pcm_capture_avail(r), c_avail_data[i].expected_avail);
}
}
static void test_card_set_id(struct kunit *test)
{
struct snd_card *card = kunit_kzalloc(test, sizeof(*card), GFP_KERNEL);
snd_card_set_id(card, VALID_NAME);
KUNIT_EXPECT_STREQ(test, card->id, VALID_NAME);
/* clear the first id character so we can set it again */
card->id[0] = '\0';
snd_card_set_id(card, NAME_W_SPEC_CHARS);
KUNIT_EXPECT_STRNEQ(test, card->id, NAME_W_SPEC_CHARS);
card->id[0] = '\0';
snd_card_set_id(card, NAME_W_SPACE);
kunit_info(test, "%s", card->id);
KUNIT_EXPECT_STREQ(test, card->id, NAME_W_SPACE_REMOVED);
}
static void test_pcm_format_name(struct kunit *test)
{
u32 i;
const char *name;
for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
name = snd_pcm_format_name(valid_fmt[i].format);
KUNIT_ASSERT_NOT_NULL_MSG(test, name, "Don't have name for %s", valid_fmt[i].name);
KUNIT_EXPECT_STREQ(test, name, valid_fmt[i].name);
}
KUNIT_ASSERT_STREQ(test, snd_pcm_format_name(WRONG_FORMAT_1), "Unknown");
KUNIT_ASSERT_STREQ(test, snd_pcm_format_name(WRONG_FORMAT_2), "Unknown");
}
static void test_card_add_component(struct kunit *test)
{
struct snd_card *card = kunit_kzalloc(test, sizeof(*card), GFP_KERNEL);
snd_component_add(card, TEST_FIRST_COMPONENT);
KUNIT_ASSERT_STREQ(test, card->components, TEST_FIRST_COMPONENT);
snd_component_add(card, TEST_SECOND_COMPONENT);
KUNIT_ASSERT_STREQ(test, card->components, TEST_FIRST_COMPONENT " " TEST_SECOND_COMPONENT);
}
static struct kunit_case sound_utils_cases[] = {
KUNIT_CASE(test_phys_format_size),
KUNIT_CASE(test_format_width),
KUNIT_CASE(test_format_endianness),
KUNIT_CASE(test_format_signed),
KUNIT_CASE(test_format_fill_silence),
KUNIT_CASE(test_playback_avail),
KUNIT_CASE(test_capture_avail),
KUNIT_CASE(test_card_set_id),
KUNIT_CASE(test_pcm_format_name),
KUNIT_CASE(test_card_add_component),
{},
};
static struct kunit_suite sound_utils_suite = {
.name = "sound-core-test",
.test_cases = sound_utils_cases,
};
kunit_test_suite(sound_utils_suite);
MODULE_AUTHOR("Ivan Orlov");
MODULE_LICENSE("GPL");

View File

@ -29,7 +29,7 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type)
if (minor >= ARRAY_SIZE(snd_oss_minors))
return NULL;
mutex_lock(&sound_oss_mutex);
guard(mutex)(&sound_oss_mutex);
mreg = snd_oss_minors[minor];
if (mreg && mreg->type == type) {
private_data = mreg->private_data;
@ -37,7 +37,6 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type)
get_device(&mreg->card_ptr->card_dev);
} else
private_data = NULL;
mutex_unlock(&sound_oss_mutex);
return private_data;
}
EXPORT_SYMBOL(snd_lookup_oss_minor_data);
@ -106,7 +105,7 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
preg->f_ops = f_ops;
preg->private_data = private_data;
preg->card_ptr = card;
mutex_lock(&sound_oss_mutex);
guard(mutex)(&sound_oss_mutex);
snd_oss_minors[minor] = preg;
minor_unit = SNDRV_MINOR_OSS_DEVICE(minor);
switch (minor_unit) {
@ -130,7 +129,6 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
goto __end;
snd_oss_minors[track2] = preg;
}
mutex_unlock(&sound_oss_mutex);
return 0;
__end:
@ -139,7 +137,6 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
if (register1 >= 0)
unregister_sound_special(register1);
snd_oss_minors[minor] = NULL;
mutex_unlock(&sound_oss_mutex);
kfree(preg);
return -EBUSY;
}
@ -156,12 +153,10 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
return 0;
if (minor < 0)
return minor;
mutex_lock(&sound_oss_mutex);
guard(mutex)(&sound_oss_mutex);
mptr = snd_oss_minors[minor];
if (mptr == NULL) {
mutex_unlock(&sound_oss_mutex);
if (mptr == NULL)
return -ENOENT;
}
switch (SNDRV_MINOR_OSS_DEVICE(minor)) {
case SNDRV_MINOR_OSS_PCM:
track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_AUDIO);
@ -176,7 +171,6 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
if (track2 >= 0)
snd_oss_minors[track2] = NULL;
snd_oss_minors[minor] = NULL;
mutex_unlock(&sound_oss_mutex);
/* call unregister_sound_special() outside sound_oss_mutex;
* otherwise may deadlock, as it can trigger the release of a card
@ -220,7 +214,7 @@ static void snd_minor_info_oss_read(struct snd_info_entry *entry,
int minor;
struct snd_minor *mptr;
mutex_lock(&sound_oss_mutex);
guard(mutex)(&sound_oss_mutex);
for (minor = 0; minor < SNDRV_OSS_MINORS; ++minor) {
mptr = snd_oss_minors[minor];
if (!mptr)
@ -233,7 +227,6 @@ static void snd_minor_info_oss_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "%3i: : %s\n", minor,
snd_oss_device_type_name(mptr->type));
}
mutex_unlock(&sound_oss_mutex);
}

View File

@ -224,14 +224,12 @@ static int check_matching_master_slave(struct snd_timer_instance *master,
return -EBUSY;
list_move_tail(&slave->open_list, &master->slave_list_head);
master->timer->num_instances++;
spin_lock_irq(&slave_active_lock);
spin_lock(&master->timer->lock);
guard(spinlock_irq)(&slave_active_lock);
guard(spinlock)(&master->timer->lock);
slave->master = master;
slave->timer = master->timer;
if (slave->flags & SNDRV_TIMER_IFLG_RUNNING)
list_add_tail(&slave->active_list, &master->slave_active_head);
spin_unlock(&master->timer->lock);
spin_unlock_irq(&slave_active_lock);
return 1;
}
@ -382,6 +380,25 @@ list_added:
}
EXPORT_SYMBOL(snd_timer_open);
/* remove slave links, called from snd_timer_close_locked() below */
static void remove_slave_links(struct snd_timer_instance *timeri,
struct snd_timer *timer)
{
struct snd_timer_instance *slave, *tmp;
guard(spinlock_irq)(&slave_active_lock);
guard(spinlock)(&timer->lock);
timeri->timer = NULL;
list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, open_list) {
list_move_tail(&slave->open_list, &snd_timer_slave_list);
timer->num_instances--;
slave->master = NULL;
slave->timer = NULL;
list_del_init(&slave->ack_list);
list_del_init(&slave->active_list);
}
}
/*
* close a timer instance
* call this with register_mutex down.
@ -390,12 +407,10 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri,
struct device **card_devp_to_put)
{
struct snd_timer *timer = timeri->timer;
struct snd_timer_instance *slave, *tmp;
if (timer) {
spin_lock_irq(&timer->lock);
guard(spinlock)(&timer->lock);
timeri->flags |= SNDRV_TIMER_IFLG_DEAD;
spin_unlock_irq(&timer->lock);
}
if (!list_empty(&timeri->open_list)) {
@ -418,21 +433,7 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri,
}
spin_unlock_irq(&timer->lock);
/* remove slave links */
spin_lock_irq(&slave_active_lock);
spin_lock(&timer->lock);
timeri->timer = NULL;
list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
open_list) {
list_move_tail(&slave->open_list, &snd_timer_slave_list);
timer->num_instances--;
slave->master = NULL;
slave->timer = NULL;
list_del_init(&slave->ack_list);
list_del_init(&slave->active_list);
}
spin_unlock(&timer->lock);
spin_unlock_irq(&slave_active_lock);
remove_slave_links(timeri, timer);
/* slave doesn't need to release timer resources below */
if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
@ -459,9 +460,8 @@ void snd_timer_close(struct snd_timer_instance *timeri)
if (snd_BUG_ON(!timeri))
return;
mutex_lock(&register_mutex);
snd_timer_close_locked(timeri, &card_dev_to_put);
mutex_unlock(&register_mutex);
scoped_guard(mutex, &register_mutex)
snd_timer_close_locked(timeri, &card_dev_to_put);
/* put_device() is called after unlock for avoiding deadlock */
if (card_dev_to_put)
put_device(card_dev_to_put);
@ -480,15 +480,13 @@ unsigned long snd_timer_resolution(struct snd_timer_instance *timeri)
{
struct snd_timer * timer;
unsigned long ret = 0;
unsigned long flags;
if (timeri == NULL)
return 0;
timer = timeri->timer;
if (timer) {
spin_lock_irqsave(&timer->lock, flags);
guard(spinlock_irqsave)(&timer->lock);
ret = snd_timer_hw_resolution(timer);
spin_unlock_irqrestore(&timer->lock, flags);
}
return ret;
}
@ -532,26 +530,19 @@ static int snd_timer_start1(struct snd_timer_instance *timeri,
{
struct snd_timer *timer;
int result;
unsigned long flags;
timer = timeri->timer;
if (!timer)
return -EINVAL;
spin_lock_irqsave(&timer->lock, flags);
if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) {
result = -EINVAL;
goto unlock;
}
if (timer->card && timer->card->shutdown) {
result = -ENODEV;
goto unlock;
}
guard(spinlock_irqsave)(&timer->lock);
if (timeri->flags & SNDRV_TIMER_IFLG_DEAD)
return -EINVAL;
if (timer->card && timer->card->shutdown)
return -ENODEV;
if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
SNDRV_TIMER_IFLG_START)) {
result = -EBUSY;
goto unlock;
}
SNDRV_TIMER_IFLG_START))
return -EBUSY;
if (start)
timeri->ticks = timeri->cticks = ticks;
@ -577,8 +568,6 @@ static int snd_timer_start1(struct snd_timer_instance *timeri,
}
snd_timer_notify1(timeri, start ? SNDRV_TIMER_EVENT_START :
SNDRV_TIMER_EVENT_CONTINUE);
unlock:
spin_unlock_irqrestore(&timer->lock, flags);
return result;
}
@ -586,53 +575,38 @@ static int snd_timer_start1(struct snd_timer_instance *timeri,
static int snd_timer_start_slave(struct snd_timer_instance *timeri,
bool start)
{
unsigned long flags;
int err;
spin_lock_irqsave(&slave_active_lock, flags);
if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) {
err = -EINVAL;
goto unlock;
}
if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) {
err = -EBUSY;
goto unlock;
}
guard(spinlock_irqsave)(&slave_active_lock);
if (timeri->flags & SNDRV_TIMER_IFLG_DEAD)
return -EINVAL;
if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING)
return -EBUSY;
timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
if (timeri->master && timeri->timer) {
spin_lock(&timeri->timer->lock);
guard(spinlock)(&timeri->timer->lock);
list_add_tail(&timeri->active_list,
&timeri->master->slave_active_head);
snd_timer_notify1(timeri, start ? SNDRV_TIMER_EVENT_START :
SNDRV_TIMER_EVENT_CONTINUE);
spin_unlock(&timeri->timer->lock);
}
err = 1; /* delayed start */
unlock:
spin_unlock_irqrestore(&slave_active_lock, flags);
return err;
return 1; /* delayed start */
}
/* stop/pause a master timer */
static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop)
{
struct snd_timer *timer;
int result = 0;
unsigned long flags;
timer = timeri->timer;
if (!timer)
return -EINVAL;
spin_lock_irqsave(&timer->lock, flags);
guard(spinlock_irqsave)(&timer->lock);
list_del_init(&timeri->ack_list);
list_del_init(&timeri->active_list);
if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
SNDRV_TIMER_IFLG_START))) {
result = -EBUSY;
goto unlock;
}
SNDRV_TIMER_IFLG_START)))
return -EBUSY;
if (timer->card && timer->card->shutdown)
goto unlock;
return 0;
if (stop) {
timeri->cticks = timeri->ticks;
timeri->pticks = 0;
@ -656,30 +630,25 @@ static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop)
timeri->flags |= SNDRV_TIMER_IFLG_PAUSED;
snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP :
SNDRV_TIMER_EVENT_PAUSE);
unlock:
spin_unlock_irqrestore(&timer->lock, flags);
return result;
return 0;
}
/* stop/pause a slave timer */
static int snd_timer_stop_slave(struct snd_timer_instance *timeri, bool stop)
{
unsigned long flags;
bool running;
spin_lock_irqsave(&slave_active_lock, flags);
guard(spinlock_irqsave)(&slave_active_lock);
running = timeri->flags & SNDRV_TIMER_IFLG_RUNNING;
timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
if (timeri->timer) {
spin_lock(&timeri->timer->lock);
guard(spinlock)(&timeri->timer->lock);
list_del_init(&timeri->ack_list);
list_del_init(&timeri->active_list);
if (running)
snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP :
SNDRV_TIMER_EVENT_PAUSE);
spin_unlock(&timeri->timer->lock);
}
spin_unlock_irqrestore(&slave_active_lock, flags);
return running ? 0 : -EBUSY;
}
@ -804,12 +773,9 @@ static void snd_timer_process_callbacks(struct snd_timer *timer,
static void snd_timer_clear_callbacks(struct snd_timer *timer,
struct list_head *head)
{
unsigned long flags;
spin_lock_irqsave(&timer->lock, flags);
guard(spinlock_irqsave)(&timer->lock);
while (!list_empty(head))
list_del_init(head->next);
spin_unlock_irqrestore(&timer->lock, flags);
}
/*
@ -819,16 +785,14 @@ static void snd_timer_clear_callbacks(struct snd_timer *timer,
static void snd_timer_work(struct work_struct *work)
{
struct snd_timer *timer = container_of(work, struct snd_timer, task_work);
unsigned long flags;
if (timer->card && timer->card->shutdown) {
snd_timer_clear_callbacks(timer, &timer->sack_list_head);
return;
}
spin_lock_irqsave(&timer->lock, flags);
guard(spinlock_irqsave)(&timer->lock);
snd_timer_process_callbacks(timer, &timer->sack_list_head);
spin_unlock_irqrestore(&timer->lock, flags);
}
/*
@ -842,8 +806,6 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
struct snd_timer_instance *ti, *ts, *tmp;
unsigned long resolution;
struct list_head *ack_list_head;
unsigned long flags;
bool use_work = false;
if (timer == NULL)
return;
@ -853,7 +815,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
return;
}
spin_lock_irqsave(&timer->lock, flags);
guard(spinlock_irqsave)(&timer->lock);
/* remember the current resolution */
resolution = snd_timer_hw_resolution(timer);
@ -919,10 +881,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
snd_timer_process_callbacks(timer, &timer->ack_list_head);
/* do we have any slow callbacks? */
use_work = !list_empty(&timer->sack_list_head);
spin_unlock_irqrestore(&timer->lock, flags);
if (use_work)
if (!list_empty(&timer->sack_list_head))
queue_work(system_highpri_wq, &timer->task_work);
}
EXPORT_SYMBOL(snd_timer_interrupt);
@ -988,7 +947,7 @@ static int snd_timer_free(struct snd_timer *timer)
if (!timer)
return 0;
mutex_lock(&register_mutex);
guard(mutex)(&register_mutex);
if (! list_empty(&timer->open_list_head)) {
struct list_head *p, *n;
struct snd_timer_instance *ti;
@ -1000,7 +959,6 @@ static int snd_timer_free(struct snd_timer *timer)
}
}
list_del(&timer->device_list);
mutex_unlock(&register_mutex);
if (timer->private_free)
timer->private_free(timer);
@ -1025,7 +983,7 @@ static int snd_timer_dev_register(struct snd_device *dev)
!timer->hw.resolution && timer->hw.c_resolution == NULL)
return -EINVAL;
mutex_lock(&register_mutex);
guard(mutex)(&register_mutex);
list_for_each_entry(timer1, &snd_timer_list, device_list) {
if (timer1->tmr_class > timer->tmr_class)
break;
@ -1046,11 +1004,9 @@ static int snd_timer_dev_register(struct snd_device *dev)
if (timer1->tmr_subdevice < timer->tmr_subdevice)
continue;
/* conflicts.. */
mutex_unlock(&register_mutex);
return -EBUSY;
}
list_add_tail(&timer->device_list, &timer1->device_list);
mutex_unlock(&register_mutex);
return 0;
}
@ -1059,20 +1015,18 @@ static int snd_timer_dev_disconnect(struct snd_device *device)
struct snd_timer *timer = device->device_data;
struct snd_timer_instance *ti;
mutex_lock(&register_mutex);
guard(mutex)(&register_mutex);
list_del_init(&timer->device_list);
/* wake up pending sleepers */
list_for_each_entry(ti, &timer->open_list_head, open_list) {
if (ti->disconnect)
ti->disconnect(ti);
}
mutex_unlock(&register_mutex);
return 0;
}
void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tstamp)
{
unsigned long flags;
unsigned long resolution = 0;
struct snd_timer_instance *ti, *ts;
@ -1083,7 +1037,7 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tst
if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_MSTART ||
event > SNDRV_TIMER_EVENT_MRESUME))
return;
spin_lock_irqsave(&timer->lock, flags);
guard(spinlock_irqsave)(&timer->lock);
if (event == SNDRV_TIMER_EVENT_MSTART ||
event == SNDRV_TIMER_EVENT_MCONTINUE ||
event == SNDRV_TIMER_EVENT_MRESUME)
@ -1095,7 +1049,6 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tst
if (ts->ccallback)
ts->ccallback(ts, event, tstamp, resolution);
}
spin_unlock_irqrestore(&timer->lock, flags);
}
EXPORT_SYMBOL(snd_timer_notify);
@ -1248,7 +1201,7 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
struct snd_timer_instance *ti;
unsigned long resolution;
mutex_lock(&register_mutex);
guard(mutex)(&register_mutex);
list_for_each_entry(timer, &snd_timer_list, device_list) {
if (timer->card && timer->card->shutdown)
continue;
@ -1270,9 +1223,8 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
timer->tmr_device, timer->tmr_subdevice);
}
snd_iprintf(buffer, "%s :", timer->name);
spin_lock_irq(&timer->lock);
resolution = snd_timer_hw_resolution(timer);
spin_unlock_irq(&timer->lock);
scoped_guard(spinlock_irq, &timer->lock)
resolution = snd_timer_hw_resolution(timer);
if (resolution)
snd_iprintf(buffer, " %lu.%03luus (%lu ticks)",
resolution / 1000,
@ -1288,7 +1240,6 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
SNDRV_TIMER_IFLG_RUNNING))
? "running" : "stopped");
}
mutex_unlock(&register_mutex);
}
static struct snd_info_entry *snd_timer_proc_entry;
@ -1329,7 +1280,7 @@ static void snd_timer_user_interrupt(struct snd_timer_instance *timeri,
struct snd_timer_read *r;
int prev;
spin_lock(&tu->qlock);
guard(spinlock)(&tu->qlock);
if (tu->qused > 0) {
prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
r = &tu->queue[prev];
@ -1348,7 +1299,6 @@ static void snd_timer_user_interrupt(struct snd_timer_instance *timeri,
tu->qused++;
}
__wake:
spin_unlock(&tu->qlock);
snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
wake_up(&tu->qchange_sleep);
}
@ -1372,7 +1322,6 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri,
{
struct snd_timer_user *tu = timeri->callback_data;
struct snd_timer_tread64 r1;
unsigned long flags;
if (event >= SNDRV_TIMER_EVENT_START &&
event <= SNDRV_TIMER_EVENT_PAUSE)
@ -1384,9 +1333,8 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri,
r1.tstamp_sec = tstamp->tv_sec;
r1.tstamp_nsec = tstamp->tv_nsec;
r1.val = resolution;
spin_lock_irqsave(&tu->qlock, flags);
snd_timer_user_append_to_tqueue(tu, &r1);
spin_unlock_irqrestore(&tu->qlock, flags);
scoped_guard(spinlock_irqsave, &tu->qlock)
snd_timer_user_append_to_tqueue(tu, &r1);
snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
wake_up(&tu->qchange_sleep);
}
@ -1410,51 +1358,48 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
memset(&r1, 0, sizeof(r1));
memset(&tstamp, 0, sizeof(tstamp));
spin_lock(&tu->qlock);
if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) |
(1 << SNDRV_TIMER_EVENT_TICK))) == 0) {
spin_unlock(&tu->qlock);
return;
}
if (tu->last_resolution != resolution || ticks > 0) {
if (timer_tstamp_monotonic)
ktime_get_ts64(&tstamp);
else
ktime_get_real_ts64(&tstamp);
}
if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) &&
tu->last_resolution != resolution) {
r1.event = SNDRV_TIMER_EVENT_RESOLUTION;
scoped_guard(spinlock, &tu->qlock) {
if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) |
(1 << SNDRV_TIMER_EVENT_TICK))) == 0)
return;
if (tu->last_resolution != resolution || ticks > 0) {
if (timer_tstamp_monotonic)
ktime_get_ts64(&tstamp);
else
ktime_get_real_ts64(&tstamp);
}
if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) &&
tu->last_resolution != resolution) {
r1.event = SNDRV_TIMER_EVENT_RESOLUTION;
r1.tstamp_sec = tstamp.tv_sec;
r1.tstamp_nsec = tstamp.tv_nsec;
r1.val = resolution;
snd_timer_user_append_to_tqueue(tu, &r1);
tu->last_resolution = resolution;
append++;
}
if ((tu->filter & (1 << SNDRV_TIMER_EVENT_TICK)) == 0)
break;
if (ticks == 0)
break;
if (tu->qused > 0) {
prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
r = &tu->tqueue[prev];
if (r->event == SNDRV_TIMER_EVENT_TICK) {
r->tstamp_sec = tstamp.tv_sec;
r->tstamp_nsec = tstamp.tv_nsec;
r->val += ticks;
append++;
break;
}
}
r1.event = SNDRV_TIMER_EVENT_TICK;
r1.tstamp_sec = tstamp.tv_sec;
r1.tstamp_nsec = tstamp.tv_nsec;
r1.val = resolution;
r1.val = ticks;
snd_timer_user_append_to_tqueue(tu, &r1);
tu->last_resolution = resolution;
append++;
}
if ((tu->filter & (1 << SNDRV_TIMER_EVENT_TICK)) == 0)
goto __wake;
if (ticks == 0)
goto __wake;
if (tu->qused > 0) {
prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
r = &tu->tqueue[prev];
if (r->event == SNDRV_TIMER_EVENT_TICK) {
r->tstamp_sec = tstamp.tv_sec;
r->tstamp_nsec = tstamp.tv_nsec;
r->val += ticks;
append++;
goto __wake;
}
}
r1.event = SNDRV_TIMER_EVENT_TICK;
r1.tstamp_sec = tstamp.tv_sec;
r1.tstamp_nsec = tstamp.tv_nsec;
r1.val = ticks;
snd_timer_user_append_to_tqueue(tu, &r1);
append++;
__wake:
spin_unlock(&tu->qlock);
if (append == 0)
return;
snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
@ -1476,14 +1421,13 @@ static int realloc_user_queue(struct snd_timer_user *tu, int size)
return -ENOMEM;
}
spin_lock_irq(&tu->qlock);
guard(spinlock_irq)(&tu->qlock);
kfree(tu->queue);
kfree(tu->tqueue);
tu->queue_size = size;
tu->queue = queue;
tu->tqueue = tqueue;
tu->qhead = tu->qtail = tu->qused = 0;
spin_unlock_irq(&tu->qlock);
return 0;
}
@ -1519,12 +1463,12 @@ static int snd_timer_user_release(struct inode *inode, struct file *file)
if (file->private_data) {
tu = file->private_data;
file->private_data = NULL;
mutex_lock(&tu->ioctl_lock);
if (tu->timeri) {
snd_timer_close(tu->timeri);
snd_timer_instance_free(tu->timeri);
scoped_guard(mutex, &tu->ioctl_lock) {
if (tu->timeri) {
snd_timer_close(tu->timeri);
snd_timer_instance_free(tu->timeri);
}
}
mutex_unlock(&tu->ioctl_lock);
snd_fasync_free(tu->fasync);
kfree(tu->queue);
kfree(tu->tqueue);
@ -1559,7 +1503,7 @@ static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
if (copy_from_user(&id, _tid, sizeof(id)))
return -EFAULT;
mutex_lock(&register_mutex);
guard(mutex)(&register_mutex);
if (id.dev_class < 0) { /* first item */
if (list_empty(&snd_timer_list))
snd_timer_user_zero_id(&id);
@ -1636,7 +1580,6 @@ static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
snd_timer_user_zero_id(&id);
}
}
mutex_unlock(&register_mutex);
if (copy_to_user(_tid, &id, sizeof(*_tid)))
return -EFAULT;
return 0;
@ -1645,70 +1588,54 @@ static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
static int snd_timer_user_ginfo(struct file *file,
struct snd_timer_ginfo __user *_ginfo)
{
struct snd_timer_ginfo *ginfo;
struct snd_timer_ginfo *ginfo __free(kfree) = NULL;
struct snd_timer_id tid;
struct snd_timer *t;
struct list_head *p;
int err = 0;
ginfo = memdup_user(_ginfo, sizeof(*ginfo));
if (IS_ERR(ginfo))
return PTR_ERR(ginfo);
return PTR_ERR(no_free_ptr(ginfo));
tid = ginfo->tid;
memset(ginfo, 0, sizeof(*ginfo));
ginfo->tid = tid;
mutex_lock(&register_mutex);
guard(mutex)(&register_mutex);
t = snd_timer_find(&tid);
if (t != NULL) {
ginfo->card = t->card ? t->card->number : -1;
if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
ginfo->flags |= SNDRV_TIMER_FLG_SLAVE;
strscpy(ginfo->id, t->id, sizeof(ginfo->id));
strscpy(ginfo->name, t->name, sizeof(ginfo->name));
spin_lock_irq(&t->lock);
if (!t)
return -ENODEV;
ginfo->card = t->card ? t->card->number : -1;
if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
ginfo->flags |= SNDRV_TIMER_FLG_SLAVE;
strscpy(ginfo->id, t->id, sizeof(ginfo->id));
strscpy(ginfo->name, t->name, sizeof(ginfo->name));
scoped_guard(spinlock_irq, &t->lock)
ginfo->resolution = snd_timer_hw_resolution(t);
spin_unlock_irq(&t->lock);
if (t->hw.resolution_min > 0) {
ginfo->resolution_min = t->hw.resolution_min;
ginfo->resolution_max = t->hw.resolution_max;
}
list_for_each(p, &t->open_list_head) {
ginfo->clients++;
}
} else {
err = -ENODEV;
if (t->hw.resolution_min > 0) {
ginfo->resolution_min = t->hw.resolution_min;
ginfo->resolution_max = t->hw.resolution_max;
}
mutex_unlock(&register_mutex);
if (err >= 0 && copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))
err = -EFAULT;
kfree(ginfo);
return err;
list_for_each(p, &t->open_list_head) {
ginfo->clients++;
}
if (copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))
return -EFAULT;
return 0;
}
static int timer_set_gparams(struct snd_timer_gparams *gparams)
{
struct snd_timer *t;
int err;
mutex_lock(&register_mutex);
guard(mutex)(&register_mutex);
t = snd_timer_find(&gparams->tid);
if (!t) {
err = -ENODEV;
goto _error;
}
if (!list_empty(&t->open_list_head)) {
err = -EBUSY;
goto _error;
}
if (!t->hw.set_period) {
err = -ENOSYS;
goto _error;
}
err = t->hw.set_period(t, gparams->period_num, gparams->period_den);
_error:
mutex_unlock(&register_mutex);
return err;
if (!t)
return -ENODEV;
if (!list_empty(&t->open_list_head))
return -EBUSY;
if (!t->hw.set_period)
return -ENOSYS;
return t->hw.set_period(t, gparams->period_num, gparams->period_den);
}
static int snd_timer_user_gparams(struct file *file,
@ -1734,10 +1661,10 @@ static int snd_timer_user_gstatus(struct file *file,
tid = gstatus.tid;
memset(&gstatus, 0, sizeof(gstatus));
gstatus.tid = tid;
mutex_lock(&register_mutex);
guard(mutex)(&register_mutex);
t = snd_timer_find(&tid);
if (t != NULL) {
spin_lock_irq(&t->lock);
guard(spinlock_irq)(&t->lock);
gstatus.resolution = snd_timer_hw_resolution(t);
if (t->hw.precise_resolution) {
t->hw.precise_resolution(t, &gstatus.resolution_num,
@ -1746,11 +1673,9 @@ static int snd_timer_user_gstatus(struct file *file,
gstatus.resolution_num = gstatus.resolution;
gstatus.resolution_den = 1000000000uL;
}
spin_unlock_irq(&t->lock);
} else {
err = -ENODEV;
}
mutex_unlock(&register_mutex);
if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus)))
err = -EFAULT;
return err;
@ -1804,9 +1729,8 @@ static int snd_timer_user_info(struct file *file,
struct snd_timer_info __user *_info)
{
struct snd_timer_user *tu;
struct snd_timer_info *info;
struct snd_timer_info *info __free(kfree) = NULL;
struct snd_timer *t;
int err = 0;
tu = file->private_data;
if (!tu->timeri)
@ -1823,13 +1747,11 @@ static int snd_timer_user_info(struct file *file,
info->flags |= SNDRV_TIMER_FLG_SLAVE;
strscpy(info->id, t->id, sizeof(info->id));
strscpy(info->name, t->name, sizeof(info->name));
spin_lock_irq(&t->lock);
info->resolution = snd_timer_hw_resolution(t);
spin_unlock_irq(&t->lock);
scoped_guard(spinlock_irq, &t->lock)
info->resolution = snd_timer_hw_resolution(t);
if (copy_to_user(_info, info, sizeof(*_info)))
err = -EFAULT;
kfree(info);
return err;
return -EFAULT;
return 0;
}
static int snd_timer_user_params(struct file *file,
@ -1887,45 +1809,47 @@ static int snd_timer_user_params(struct file *file,
goto _end;
}
snd_timer_stop(tu->timeri);
spin_lock_irq(&t->lock);
tu->timeri->flags &= ~(SNDRV_TIMER_IFLG_AUTO|
SNDRV_TIMER_IFLG_EXCLUSIVE|
SNDRV_TIMER_IFLG_EARLY_EVENT);
if (params.flags & SNDRV_TIMER_PSFLG_AUTO)
tu->timeri->flags |= SNDRV_TIMER_IFLG_AUTO;
if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE)
tu->timeri->flags |= SNDRV_TIMER_IFLG_EXCLUSIVE;
if (params.flags & SNDRV_TIMER_PSFLG_EARLY_EVENT)
tu->timeri->flags |= SNDRV_TIMER_IFLG_EARLY_EVENT;
spin_unlock_irq(&t->lock);
scoped_guard(spinlock_irq, &t->lock) {
tu->timeri->flags &= ~(SNDRV_TIMER_IFLG_AUTO|
SNDRV_TIMER_IFLG_EXCLUSIVE|
SNDRV_TIMER_IFLG_EARLY_EVENT);
if (params.flags & SNDRV_TIMER_PSFLG_AUTO)
tu->timeri->flags |= SNDRV_TIMER_IFLG_AUTO;
if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE)
tu->timeri->flags |= SNDRV_TIMER_IFLG_EXCLUSIVE;
if (params.flags & SNDRV_TIMER_PSFLG_EARLY_EVENT)
tu->timeri->flags |= SNDRV_TIMER_IFLG_EARLY_EVENT;
}
if (params.queue_size > 0 &&
(unsigned int)tu->queue_size != params.queue_size) {
err = realloc_user_queue(tu, params.queue_size);
if (err < 0)
goto _end;
}
spin_lock_irq(&tu->qlock);
tu->qhead = tu->qtail = tu->qused = 0;
if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) {
if (tu->tread) {
struct snd_timer_tread64 tread;
memset(&tread, 0, sizeof(tread));
tread.event = SNDRV_TIMER_EVENT_EARLY;
tread.tstamp_sec = 0;
tread.tstamp_nsec = 0;
tread.val = 0;
snd_timer_user_append_to_tqueue(tu, &tread);
} else {
struct snd_timer_read *r = &tu->queue[0];
r->resolution = 0;
r->ticks = 0;
tu->qused++;
tu->qtail++;
scoped_guard(spinlock_irq, &tu->qlock) {
tu->qhead = tu->qtail = tu->qused = 0;
if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) {
if (tu->tread) {
struct snd_timer_tread64 tread;
memset(&tread, 0, sizeof(tread));
tread.event = SNDRV_TIMER_EVENT_EARLY;
tread.tstamp_sec = 0;
tread.tstamp_nsec = 0;
tread.val = 0;
snd_timer_user_append_to_tqueue(tu, &tread);
} else {
struct snd_timer_read *r = &tu->queue[0];
r->resolution = 0;
r->ticks = 0;
tu->qused++;
tu->qtail++;
}
}
tu->filter = params.filter;
tu->ticks = params.ticks;
}
tu->filter = params.filter;
tu->ticks = params.ticks;
spin_unlock_irq(&tu->qlock);
err = 0;
_end:
if (copy_to_user(_params, &params, sizeof(params)))
@ -1948,9 +1872,8 @@ static int snd_timer_user_status32(struct file *file,
status.resolution = snd_timer_resolution(tu->timeri);
status.lost = tu->timeri->lost;
status.overrun = tu->overrun;
spin_lock_irq(&tu->qlock);
status.queue = tu->qused;
spin_unlock_irq(&tu->qlock);
scoped_guard(spinlock_irq, &tu->qlock)
status.queue = tu->qused;
if (copy_to_user(_status, &status, sizeof(status)))
return -EFAULT;
return 0;
@ -1971,9 +1894,8 @@ static int snd_timer_user_status64(struct file *file,
status.resolution = snd_timer_resolution(tu->timeri);
status.lost = tu->timeri->lost;
status.overrun = tu->overrun;
spin_lock_irq(&tu->qlock);
status.queue = tu->qused;
spin_unlock_irq(&tu->qlock);
scoped_guard(spinlock_irq, &tu->qlock)
status.queue = tu->qused;
if (copy_to_user(_status, &status, sizeof(status)))
return -EFAULT;
return 0;
@ -2131,12 +2053,9 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct snd_timer_user *tu = file->private_data;
long ret;
mutex_lock(&tu->ioctl_lock);
ret = __snd_timer_user_ioctl(file, cmd, arg, false);
mutex_unlock(&tu->ioctl_lock);
return ret;
guard(mutex)(&tu->ioctl_lock);
return __snd_timer_user_ioctl(file, cmd, arg, false);
}
static int snd_timer_user_fasync(int fd, struct file * file, int on)
@ -2263,12 +2182,11 @@ static __poll_t snd_timer_user_poll(struct file *file, poll_table * wait)
poll_wait(file, &tu->qchange_sleep, wait);
mask = 0;
spin_lock_irq(&tu->qlock);
guard(spinlock_irq)(&tu->qlock);
if (tu->qused)
mask |= EPOLLIN | EPOLLRDNORM;
if (tu->disconnected)
mask |= EPOLLERR;
spin_unlock_irq(&tu->qlock);
return mask;
}

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