mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 04:18:39 +08:00
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:
commit
fe46a7dd18
8
Documentation/ABI/testing/sysfs-bus-pci-devices-avs
Normal file
8
Documentation/ABI/testing/sysfs-bus-pci-devices-avs
Normal 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.
|
@ -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>;
|
||||
};
|
@ -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>;
|
||||
};
|
@ -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
|
||||
|
@ -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>;
|
||||
};
|
@ -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>;
|
||||
};
|
@ -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:
|
||||
|
@ -25,6 +25,9 @@ properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
'#sound-dai-cells':
|
||||
const: 1
|
||||
|
||||
|
@ -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];
|
||||
};
|
||||
};
|
||||
|
@ -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>;
|
||||
};
|
@ -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:
|
||||
|
162
Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml
Normal file
162
Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml
Normal 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>;
|
||||
};
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -107,7 +107,7 @@ patternProperties:
|
||||
properties:
|
||||
sound-dai:
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
maxItems: 8
|
||||
|
||||
required:
|
||||
- link-name
|
||||
|
@ -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
|
||||
|
||||
|
@ -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>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
96
Documentation/devicetree/bindings/sound/qcom,wcd939x.yaml
Normal file
96
Documentation/devicetree/bindings/sound/qcom,wcd939x.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -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
|
@ -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:
|
||||
|
41
Documentation/devicetree/bindings/sound/realtek,rt1015.yaml
Normal file
41
Documentation/devicetree/bindings/sound/realtek,rt1015.yaml
Normal 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>;
|
||||
};
|
||||
};
|
@ -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>;
|
||||
};
|
@ -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: |
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 },
|
||||
|
@ -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
|
||||
|
235
drivers/soundwire/amd_init.c
Normal file
235
drivers/soundwire/amd_init.c
Normal 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");
|
13
drivers/soundwire/amd_init.h
Normal file
13
drivers/soundwire/amd_init.h
Normal 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
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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"),
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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 */
|
||||
|
66
include/sound/cs-amp-lib.h
Normal file
66
include/sound/cs-amp-lib.h
Normal 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 */
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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)
|
||||
|
||||
);
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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/
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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(®ister_mutex);
|
||||
|
||||
if (device < 0)
|
||||
device = 0;
|
||||
else if (device < SNDRV_MINOR_HWDEPS)
|
||||
device++;
|
||||
else
|
||||
device = SNDRV_MINOR_HWDEPS;
|
||||
scoped_guard(mutex, ®ister_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(®ister_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(®ister_mutex);
|
||||
hwdep = snd_hwdep_search(card, device);
|
||||
if (hwdep)
|
||||
err = snd_hwdep_info(hwdep, info);
|
||||
else
|
||||
err = -ENXIO;
|
||||
mutex_unlock(®ister_mutex);
|
||||
return err;
|
||||
scoped_guard(mutex, ®ister_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(®ister_mutex);
|
||||
if (snd_hwdep_search(card, hwdep->device)) {
|
||||
mutex_unlock(®ister_mutex);
|
||||
guard(mutex)(®ister_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(®ister_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -454,7 +450,6 @@ static int snd_hwdep_dev_register(struct snd_device *device)
|
||||
hwdep->ossreg = 1;
|
||||
}
|
||||
#endif
|
||||
mutex_unlock(®ister_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(®ister_mutex);
|
||||
if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep) {
|
||||
mutex_unlock(®ister_mutex);
|
||||
guard(mutex)(®ister_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(®ister_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -492,11 +483,10 @@ static void snd_hwdep_proc_read(struct snd_info_entry *entry,
|
||||
{
|
||||
struct snd_hwdep *hwdep;
|
||||
|
||||
mutex_lock(®ister_mutex);
|
||||
guard(mutex)(®ister_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(®ister_mutex);
|
||||
}
|
||||
|
||||
static struct snd_info_entry *snd_hwdep_proc_entry;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
100
sound/core/pcm.c
100
sound/core/pcm.c
@ -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(®ister_mutex);
|
||||
device = snd_pcm_next(card, device);
|
||||
mutex_unlock(®ister_mutex);
|
||||
scoped_guard(mutex, ®ister_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(®ister_mutex);
|
||||
guard(mutex)(®ister_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(®ister_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(®ister_mutex);
|
||||
guard(mutex)(®ister_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(®ister_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(®ister_mutex);
|
||||
mutex_lock(&pcm->open_mutex);
|
||||
guard(mutex)(®ister_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(®ister_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(®ister_mutex);
|
||||
guard(mutex)(®ister_mutex);
|
||||
if (nfree) {
|
||||
list_del(¬ify->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(®ister_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(®ister_mutex);
|
||||
guard(mutex)(®ister_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(®ister_mutex);
|
||||
}
|
||||
|
||||
static struct snd_info_entry *snd_pcm_proc_entry;
|
||||
|
@ -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)))
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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(®ister_mutex);
|
||||
ret = __snd_rawmidi_info_select(card, info);
|
||||
mutex_unlock(®ister_mutex);
|
||||
return ret;
|
||||
guard(mutex)(®ister_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(®ister_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, ®ister_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(®ister_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(®ister_mutex);
|
||||
guard(mutex)(®ister_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(®ister_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(®ister_mutex);
|
||||
if (snd_rawmidi_search(rmidi->card, rmidi->device))
|
||||
err = -EBUSY;
|
||||
else
|
||||
list_add_tail(&rmidi->list, &snd_rawmidi_devices);
|
||||
mutex_unlock(®ister_mutex);
|
||||
scoped_guard(mutex, ®ister_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(®ister_mutex);
|
||||
list_del(&rmidi->list);
|
||||
mutex_unlock(®ister_mutex);
|
||||
scoped_guard(mutex, ®ister_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(®ister_mutex);
|
||||
mutex_lock(&rmidi->open_mutex);
|
||||
guard(mutex)(®ister_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(®ister_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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 *
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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(®ister_mutex);
|
||||
guard(mutex)(®ister_mutex);
|
||||
client = synths[card->number];
|
||||
if (client == NULL) {
|
||||
newclient = 1;
|
||||
client = kzalloc(sizeof(*client), GFP_KERNEL);
|
||||
if (client == NULL) {
|
||||
mutex_unlock(®ister_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(®ister_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(®ister_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(®ister_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(®ister_mutex);
|
||||
guard(mutex)(®ister_mutex);
|
||||
client = synths[card->number];
|
||||
if (client == NULL || client->ports[device] == NULL) {
|
||||
mutex_unlock(®ister_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(®ister_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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
312
sound/core/sound_kunit.c
Normal 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");
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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(®ister_mutex);
|
||||
snd_timer_close_locked(timeri, &card_dev_to_put);
|
||||
mutex_unlock(®ister_mutex);
|
||||
scoped_guard(mutex, ®ister_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(®ister_mutex);
|
||||
guard(mutex)(®ister_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(®ister_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(®ister_mutex);
|
||||
guard(mutex)(®ister_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(®ister_mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
list_add_tail(&timer->device_list, &timer1->device_list);
|
||||
mutex_unlock(®ister_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(®ister_mutex);
|
||||
guard(mutex)(®ister_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(®ister_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(®ister_mutex);
|
||||
guard(mutex)(®ister_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(®ister_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(®ister_mutex);
|
||||
guard(mutex)(®ister_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(®ister_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(®ister_mutex);
|
||||
guard(mutex)(®ister_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(®ister_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(®ister_mutex);
|
||||
guard(mutex)(®ister_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(®ister_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(®ister_mutex);
|
||||
guard(mutex)(®ister_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(®ister_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, ¶ms, 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
Loading…
Reference in New Issue
Block a user