sound updates for 3.20-rc1
In this batch, you can find lots of cleanups through the whole subsystem, as our good New Year's resolution. Lots of LOCs and commits are about LINE6 driver that was promoted finally from staging tree, and as usual, there've been widely spread ASoC changes. Here some highlights: ALSA core changes - Embedding struct device into ALSA core structures - sequencer core cleanups / fixes - PCM msbits constraints cleanups / fixes - New SNDRV_PCM_TRIGGER_DRAIN command - PCM kerneldoc fixes, header cleanups - PCM code cleanups using more standard codes - Control notification ID fixes Driver cleanups - Cleanups of PCI PM callbacks - Timer helper usages cleanups - Simplification (e.g. argument reduction) of many driver codes HD-audio - Hotkey and LED support on HP laptops with Realtek codecs - Dock station support on HP laptops - Toshiba Satellite S50D fixup - Enhanced wallclock timestamp handling for HD-audio - Componentization to simplify the linkage between i915 and hd-audio drivers for Intel HDMI/DP USB-audio - Akai MPC Element support - Enhanced timestamp handling ASoC - Lots of refactoringin ASoC core, moving drivers to more data driven initialization and rationalizing a lot of DAPM usage - Much improved handling of CDCLK clocks on Samsung I2S controllers - Lots of driver specific cleanups and feature improvements - CODEC support for TI PCM514x and TLV320AIC3104 devices - Board support for Tegra systems with Realtek RT5677 - New driver for Maxim max98357a - More enhancements / fixes for Intel SST driver Others - Promotion of LINE6 driver from staging along with lots of rewrites and cleanups - DT support for old non-ASoC atmel driver - oxygen cleanups, XIO2001 init, Studio Evolution SE6x support - Emu8000 DRAM size detection fix on ISA(!!) AWE64 boards - A few more ak411x fixes for ice1724 boards -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJU2ySIAAoJEGwxgFQ9KSmk/YMP/1v0r60aDt6VxlTbadt008R/ jTEIzD4oGEMkhFQdlmN8MegZlx+05vxQUCGrVy8PLelhfy/mnj6z/iUt9ohE1PqK 530eVr5FnlAbHs1JzP8Tm8Xbbtk8RXt5uvgohJvt7HBrc0Def9N/w37fUQ0ytO+s Ot/0Xm8BNsdJ90DfMVLc0Ok9cAFn4Z70gylE/PuGxbBBzxQh8PYPXtJ6Q/s5lKLV QC7VitJa0H7vsFYb+Ve7GU4cKMTt8uEPw8CdnQbDwb63ia93iWJJrlqKVUWYF2Gu K+mX5Igdb88ToXbMPrLKXe73IfFcdpWNTbj8IAv+Rp9fArylzz+3GAYmrqTAdare JEE5qAZTtJZEeD2vgNCnA4JpSbRzL0bHrEow21LnPONq3V9FB044NAeMSx3dI4j1 fk+SnqrpJMtlCtgj2PuWzIcqRiJ25F/Qax/xFeZHo7FwLIBF7z5pLu9DP4CfUSXj fDEcB9aNF2VirJkQdbhHaPqTYVf2rHQ/ebDpDHBwkqFe865IHlJ8g8MrHnAFInKN jQlSTOqi9V3two53U1JIKcB6QcBH3vh60w2JsWsQadsr45YYQ/bvBHGYNpQ00C3U rbDBANhAHaF/hFncNnOQDsH65FqHj/ZlBQRhzX0LqxN4K0DM1FqGcLf2k6u/pzZU 09+QlcIOOzN8lbvHR8Qx =/84r -----END PGP SIGNATURE----- Merge tag 'sound-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound Pull sound updates from Takashi Iwai: "In this batch, you can find lots of cleanups through the whole subsystem, as our good New Year's resolution. Lots of LOCs and commits are about LINE6 driver that was promoted finally from staging tree, and as usual, there've been widely spread ASoC changes. Here some highlights: ALSA core changes - Embedding struct device into ALSA core structures - sequencer core cleanups / fixes - PCM msbits constraints cleanups / fixes - New SNDRV_PCM_TRIGGER_DRAIN command - PCM kerneldoc fixes, header cleanups - PCM code cleanups using more standard codes - Control notification ID fixes Driver cleanups - Cleanups of PCI PM callbacks - Timer helper usages cleanups - Simplification (e.g. argument reduction) of many driver codes HD-audio - Hotkey and LED support on HP laptops with Realtek codecs - Dock station support on HP laptops - Toshiba Satellite S50D fixup - Enhanced wallclock timestamp handling for HD-audio - Componentization to simplify the linkage between i915 and hd-audio drivers for Intel HDMI/DP USB-audio - Akai MPC Element support - Enhanced timestamp handling ASoC - Lots of refactoringin ASoC core, moving drivers to more data driven initialization and rationalizing a lot of DAPM usage - Much improved handling of CDCLK clocks on Samsung I2S controllers - Lots of driver specific cleanups and feature improvements - CODEC support for TI PCM514x and TLV320AIC3104 devices - Board support for Tegra systems with Realtek RT5677 - New driver for Maxim max98357a - More enhancements / fixes for Intel SST driver Others - Promotion of LINE6 driver from staging along with lots of rewrites and cleanups - DT support for old non-ASoC atmel driver - oxygen cleanups, XIO2001 init, Studio Evolution SE6x support - Emu8000 DRAM size detection fix on ISA(!!) AWE64 boards - A few more ak411x fixes for ice1724 boards" * tag 'sound-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (542 commits) ALSA: line6: toneport: Use explicit type for firmware version ALSA: line6: Use explicit type for serial number ALSA: line6: Return EIO if read/write not successful ALSA: line6: Return error if device not responding ALSA: line6: Add delay before reading status ASoC: Intel: Clean data after SST fw fetch ALSA: hda - Add docking station support for another HP machine ALSA: control: fix failure to return new numerical ID in 'replace' event data ALSA: usb: update trigger timestamp on first non-zero URB submitted ALSA: hda: read trigger_timestamp immediately after starting DMA ALSA: pcm: allow for trigger_tstamp snapshot in .trigger ALSA: pcm: don't override timestamp unconditionally ALSA: off by one bug in snd_riptide_joystick_probe() ASoC: rt5670: Set use_single_rw flag for regmap ASoC: rt286: Add rt288 codec support ASoC: max98357a: Fix build in !CONFIG_OF case ASoC: Intel: fix platform_no_drv_owner.cocci warnings ARM: dts: Switch Odroid X2/U2 to simple-audio-card ARM: dts: Exynos4 and Odroid X2/U3 sound device nodes update ALSA: control: fix failure to return numerical ID in 'add' event ...
This commit is contained in:
commit
a323ae93a7
488 changed files with 11021 additions and 9142 deletions
18
Documentation/devicetree/bindings/sound/cdns,xtfpga-i2s.txt
Normal file
18
Documentation/devicetree/bindings/sound/cdns,xtfpga-i2s.txt
Normal file
|
@ -0,0 +1,18 @@
|
|||
Bindings for I2S controller built into xtfpga Xtensa bitstreams.
|
||||
|
||||
Required properties:
|
||||
- compatible: shall be "cdns,xtfpga-i2s".
|
||||
- reg: memory region (address and length) with device registers.
|
||||
- interrupts: interrupt for the device.
|
||||
- clocks: phandle to the clk used as master clock. I2S bus clock
|
||||
is derived from it.
|
||||
|
||||
Examples:
|
||||
|
||||
i2s0: xtfpga-i2s@0d080000 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "cdns,xtfpga-i2s";
|
||||
reg = <0x0d080000 0x40>;
|
||||
interrupts = <2 1>;
|
||||
clocks = <&cdce706 4>;
|
||||
};
|
31
Documentation/devicetree/bindings/sound/designware-i2s.txt
Normal file
31
Documentation/devicetree/bindings/sound/designware-i2s.txt
Normal file
|
@ -0,0 +1,31 @@
|
|||
DesignWare I2S controller
|
||||
|
||||
Required properties:
|
||||
- compatible : Must be "snps,designware-i2s"
|
||||
- reg : Must contain the I2S core's registers location and length
|
||||
- clocks : Pairs of phandle and specifier referencing the controller's
|
||||
clocks. The controller expects one clock: the clock used as the sampling
|
||||
rate reference clock sample.
|
||||
- clock-names : "i2sclk" for the sample rate reference clock.
|
||||
- dmas: Pairs of phandle and specifier for the DMA channels that are used by
|
||||
the core. The core expects one or two dma channels: one for transmit and
|
||||
one for receive.
|
||||
- dma-names : "tx" for the transmit channel, "rx" for the receive channel.
|
||||
|
||||
For more details on the 'dma', 'dma-names', 'clock' and 'clock-names'
|
||||
properties please check:
|
||||
* resource-names.txt
|
||||
* clock/clock-bindings.txt
|
||||
* dma/dma.txt
|
||||
|
||||
Example:
|
||||
|
||||
soc_i2s: i2s@7ff90000 {
|
||||
compatible = "snps,designware-i2s";
|
||||
reg = <0x0 0x7ff90000 0x0 0x1000>;
|
||||
clocks = <&scpi_i2sclk 0>;
|
||||
clock-names = "i2sclk";
|
||||
#sound-dai-cells = <0>;
|
||||
dmas = <&dma0 5>;
|
||||
dma-names = "tx";
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
Ingenic JZ4740 I2S controller
|
||||
|
||||
Required properties:
|
||||
- compatible : "ingenic,jz4740-i2s"
|
||||
- reg : I2S registers location and length
|
||||
- clocks : AIC and I2S PLL clock specifiers.
|
||||
- clock-names: "aic" and "i2s"
|
||||
- dmas: DMA controller phandle and DMA request line for I2S Tx and Rx channels
|
||||
- dma-names: Must be "tx" and "rx"
|
||||
|
||||
Example:
|
||||
|
||||
i2s: i2s@10020000 {
|
||||
compatible = "ingenic,jz4740-i2s";
|
||||
reg = <0x10020000 0x94>;
|
||||
|
||||
clocks = <&cgu JZ4740_CLK_AIC>, <&cgu JZ4740_CLK_I2SPLL>;
|
||||
clock-names = "aic", "i2s";
|
||||
|
||||
dmas = <&dma 2>, <&dma 3>;
|
||||
dma-names = "tx", "rx";
|
||||
|
||||
};
|
14
Documentation/devicetree/bindings/sound/max98357a.txt
Normal file
14
Documentation/devicetree/bindings/sound/max98357a.txt
Normal file
|
@ -0,0 +1,14 @@
|
|||
Maxim MAX98357A audio DAC
|
||||
|
||||
This node models the Maxim MAX98357A DAC.
|
||||
|
||||
Required properties:
|
||||
- compatible : "maxim,max98357a"
|
||||
- sdmode-gpios : GPIO specifier for the GPIO -> DAC SDMODE pin
|
||||
|
||||
Example:
|
||||
|
||||
max98357a {
|
||||
compatible = "maxim,max98357a";
|
||||
sdmode-gpios = <&qcom_pinmux 25 0>;
|
||||
};
|
|
@ -0,0 +1,67 @@
|
|||
NVIDIA Tegra audio complex, with RT5677 CODEC
|
||||
|
||||
Required properties:
|
||||
- compatible : "nvidia,tegra-audio-rt5677"
|
||||
- clocks : Must contain an entry for each entry in clock-names.
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
- clock-names : Must include the following entries:
|
||||
- pll_a
|
||||
- pll_a_out0
|
||||
- mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk)
|
||||
- nvidia,model : The user-visible name of this sound complex.
|
||||
- nvidia,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 RT5677's pins (as documented in its binding), and the jacks
|
||||
on the board:
|
||||
|
||||
* Headphone
|
||||
* Speaker
|
||||
* Headset Mic
|
||||
* Internal Mic 1
|
||||
* Internal Mic 2
|
||||
|
||||
- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
|
||||
connected to the CODEC.
|
||||
- nvidia,audio-codec : The phandle of the RT5677 audio codec. This binding
|
||||
assumes that AIF1 on the CODEC is connected to Tegra.
|
||||
|
||||
Optional properties:
|
||||
- nvidia,hp-det-gpios : The GPIO that detects headphones are plugged in
|
||||
- nvidia,hp-en-gpios : The GPIO that enables headphone amplifier
|
||||
- nvidia,mic-present-gpios: The GPIO that mic jack is plugged in
|
||||
- nvidia,dmic-clk-en-gpios : The GPIO that gates DMIC clock signal
|
||||
|
||||
Example:
|
||||
|
||||
sound {
|
||||
compatible = "nvidia,tegra-audio-rt5677-ryu",
|
||||
"nvidia,tegra-audio-rt5677";
|
||||
nvidia,model = "NVIDIA Tegra Ryu";
|
||||
|
||||
nvidia,audio-routing =
|
||||
"Headphone", "LOUT2",
|
||||
"Headphone", "LOUT1",
|
||||
"Headset Mic", "MICBIAS1",
|
||||
"IN1P", "Headset Mic",
|
||||
"IN1N", "Headset Mic",
|
||||
"DMIC L1", "Internal Mic 1",
|
||||
"DMIC R1", "Internal Mic 1",
|
||||
"DMIC L2", "Internal Mic 2",
|
||||
"DMIC R2", "Internal Mic 2",
|
||||
"Speaker", "PDM1L",
|
||||
"Speaker", "PDM1R";
|
||||
|
||||
nvidia,i2s-controller = <&tegra_i2s1>;
|
||||
nvidia,audio-codec = <&rt5677>;
|
||||
|
||||
nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(R, 7) GPIO_ACTIVE_HIGH>;
|
||||
nvidia,mic-present-gpios = <&gpio TEGRA_GPIO(O, 5) GPIO_ACTIVE_LOW>;
|
||||
nvidia,hp-en-gpios = <&rt5677 1 GPIO_ACTIVE_HIGH>;
|
||||
nvidia,dmic-clk-en-gpios = <&rt5677 2 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
clocks = <&tegra_car TEGRA124_CLK_PLL_A>,
|
||||
<&tegra_car TEGRA124_CLK_PLL_A_OUT0>,
|
||||
<&tegra_car TEGRA124_CLK_EXTERN1>;
|
||||
clock-names = "pll_a", "pll_a_out0", "mclk";
|
||||
};
|
|
@ -5,7 +5,8 @@ on the board).
|
|||
|
||||
Required properties:
|
||||
|
||||
- compatible : One of "ti,pcm5121" or "ti,pcm5122"
|
||||
- compatible : One of "ti,pcm5121", "ti,pcm5122", "ti,pcm5141" or
|
||||
"ti,pcm5142"
|
||||
|
||||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
@ -16,9 +17,16 @@ Required properties:
|
|||
Optional properties:
|
||||
|
||||
- clocks : A clock specifier for the clock connected as SCLK. If this
|
||||
is absent the device will be configured to clock from BCLK.
|
||||
is absent the device will be configured to clock from BCLK. If pll-in
|
||||
and pll-out are specified in addition to a clock, the device is
|
||||
configured to accept clock input on a specified gpio pin.
|
||||
|
||||
Example:
|
||||
- pll-in, pll-out : gpio pins used to connect the pll using <1>
|
||||
through <6>. The device will be configured for clock input on the
|
||||
given pll-in pin and PLL output on the given pll-out pin. An
|
||||
external connection from the pll-out pin to the SCLK pin is assumed.
|
||||
|
||||
Examples:
|
||||
|
||||
pcm5122: pcm5122@4c {
|
||||
compatible = "ti,pcm5122";
|
||||
|
@ -28,3 +36,17 @@ Example:
|
|||
DVDD-supply = <®_1v8>;
|
||||
CPVDD-supply = <®_3v3>;
|
||||
};
|
||||
|
||||
|
||||
pcm5142: pcm5142@4c {
|
||||
compatible = "ti,pcm5142";
|
||||
reg = <0x4c>;
|
||||
|
||||
AVDD-supply = <®_3v3_analog>;
|
||||
DVDD-supply = <®_1v8>;
|
||||
CPVDD-supply = <®_3v3>;
|
||||
|
||||
clocks = <&sck>;
|
||||
pll-in = <3>;
|
||||
pll-out = <6>;
|
||||
};
|
||||
|
|
|
@ -33,6 +33,25 @@ Required SoC Specific Properties:
|
|||
"iis" is the i2s bus clock and i2s_opclk0, i2s_opclk1 are sources of the root
|
||||
clk. i2s0 has internal mux to select the source of root clk and i2s1 and i2s2
|
||||
doesn't have any such mux.
|
||||
- #clock-cells: should be 1, this property must be present if the I2S device
|
||||
is a clock provider in terms of the common clock bindings, described in
|
||||
../clock/clock-bindings.txt.
|
||||
- clock-output-names: from the common clock bindings, names of the CDCLK
|
||||
I2S output clocks, suggested values are "i2s_cdclk0", "i2s_cdclk1",
|
||||
"i2s_cdclk3" for the I2S0, I2S1, I2S2 devices recpectively.
|
||||
|
||||
There are following clocks available at the I2S device nodes:
|
||||
CLK_I2S_CDCLK - the CDCLK (CODECLKO) gate clock,
|
||||
CLK_I2S_RCLK_PSR - the RCLK prescaler divider clock (corresponding to the
|
||||
IISPSR register),
|
||||
CLK_I2S_RCLK_SRC - the RCLKSRC mux clock (corresponding to RCLKSRC bit in
|
||||
IISMOD register).
|
||||
|
||||
Refer to the SoC datasheet for availability of the above clocks.
|
||||
The CLK_I2S_RCLK_PSR and CLK_I2S_RCLK_SRC clocks are usually only available
|
||||
in the IIS Multi Audio Interface (I2S0).
|
||||
Note: Old DTs may not have the #clock-cells, clock-output-names properties
|
||||
and then not use the I2S node as a clock supplier.
|
||||
|
||||
Optional SoC Specific Properties:
|
||||
|
||||
|
@ -41,6 +60,7 @@ Optional SoC Specific Properties:
|
|||
- pinctrl-0: Should specify pin control groups used for this controller.
|
||||
- pinctrl-names: Should contain only one value - "default".
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
i2s0: i2s@03830000 {
|
||||
|
@ -54,6 +74,8 @@ i2s0: i2s@03830000 {
|
|||
<&clock_audss EXYNOS_I2S_BUS>,
|
||||
<&clock_audss EXYNOS_SCLK_I2S>;
|
||||
clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
|
||||
#clock-cells;
|
||||
clock-output-names = "i2s_cdclk0";
|
||||
samsung,idma-addr = <0x03000000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2s0_bus>;
|
||||
|
|
|
@ -75,6 +75,11 @@ Optional CPU/CODEC subnodes properties:
|
|||
it can be specified via "clocks" if system has
|
||||
clock node (= common clock), or "system-clock-frequency"
|
||||
(if system doens't support common clock)
|
||||
If a clock is specified, it is
|
||||
enabled with clk_prepare_enable()
|
||||
in dai startup() and disabled with
|
||||
clk_disable_unprepare() in dai
|
||||
shutdown().
|
||||
|
||||
Example 1 - single DAI link:
|
||||
|
||||
|
|
92
Documentation/devicetree/bindings/sound/st,sta32x.txt
Normal file
92
Documentation/devicetree/bindings/sound/st,sta32x.txt
Normal file
|
@ -0,0 +1,92 @@
|
|||
STA32X audio CODEC
|
||||
|
||||
The driver for this device only supports I2C.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "st,sta32x"
|
||||
- reg: the I2C address of the device for I2C
|
||||
- reset-gpios: a GPIO spec for the reset pin. If specified, it will be
|
||||
deasserted before communication to the codec starts.
|
||||
|
||||
- power-down-gpios: a GPIO spec for the power down pin. If specified,
|
||||
it will be deasserted before communication to the codec
|
||||
starts.
|
||||
|
||||
- Vdda-supply: regulator spec, providing 3.3V
|
||||
- Vdd3-supply: regulator spec, providing 3.3V
|
||||
- Vcc-supply: regulator spec, providing 5V - 26V
|
||||
|
||||
Optional properties:
|
||||
|
||||
- st,output-conf: number, Selects the output configuration:
|
||||
0: 2-channel (full-bridge) power, 2-channel data-out
|
||||
1: 2 (half-bridge). 1 (full-bridge) on-board power
|
||||
2: 2 Channel (Full-Bridge) Power, 1 Channel FFX
|
||||
3: 1 Channel Mono-Parallel
|
||||
If parameter is missing, mode 0 will be enabled.
|
||||
This property has to be specified as '/bits/ 8' value.
|
||||
|
||||
- st,ch1-output-mapping: Channel 1 output mapping
|
||||
- st,ch2-output-mapping: Channel 2 output mapping
|
||||
- st,ch3-output-mapping: Channel 3 output mapping
|
||||
0: Channel 1
|
||||
1: Channel 2
|
||||
2: Channel 3
|
||||
If parameter is missing, channel 1 is chosen.
|
||||
This properties have to be specified as '/bits/ 8' values.
|
||||
|
||||
- st,thermal-warning-recover:
|
||||
If present, thermal warning recovery is enabled.
|
||||
|
||||
- st,thermal-warning-adjustment:
|
||||
If present, thermal warning adjustment is enabled.
|
||||
|
||||
- st,fault-detect-recovery:
|
||||
If present, then fault recovery will be enabled.
|
||||
|
||||
- st,drop-compensation-ns: number
|
||||
Only required for "st,ffx-power-output-mode" ==
|
||||
"variable-drop-compensation".
|
||||
Specifies the drop compensation in nanoseconds.
|
||||
The value must be in the range of 0..300, and only
|
||||
multiples of 20 are allowed. Default is 140ns.
|
||||
|
||||
- st,max-power-use-mpcc:
|
||||
If present, then MPCC bits are used for MPC coefficients,
|
||||
otherwise standard MPC coefficients are used.
|
||||
|
||||
- st,max-power-corr:
|
||||
If present, power bridge correction for THD reduction near maximum
|
||||
power output is enabled.
|
||||
|
||||
- st,am-reduction-mode:
|
||||
If present, FFX mode runs in AM reduction mode, otherwise normal
|
||||
FFX mode is used.
|
||||
|
||||
- st,odd-pwm-speed-mode:
|
||||
If present, PWM speed mode run on odd speed mode (341.3 kHz) on all
|
||||
channels. If not present, normal PWM spped mode (384 kHz) will be used.
|
||||
|
||||
- st,invalid-input-detect-mute:
|
||||
If present, automatic invalid input detect mute is enabled.
|
||||
|
||||
Example:
|
||||
|
||||
codec: sta32x@38 {
|
||||
compatible = "st,sta32x";
|
||||
reg = <0x1c>;
|
||||
reset-gpios = <&gpio1 19 0>;
|
||||
power-down-gpios = <&gpio1 16 0>;
|
||||
st,output-conf = /bits/ 8 <0x3>; // set output to 2-channel
|
||||
// (full-bridge) power,
|
||||
// 2-channel data-out
|
||||
st,ch1-output-mapping = /bits/ 8 <0>; // set channel 1 output ch 1
|
||||
st,ch2-output-mapping = /bits/ 8 <0>; // set channel 2 output ch 1
|
||||
st,ch3-output-mapping = /bits/ 8 <0>; // set channel 3 output ch 1
|
||||
st,max-power-correction; // enables power bridge
|
||||
// correction for THD reduction
|
||||
// near maximum power output
|
||||
st,invalid-input-detect-mute; // mute if no valid digital
|
||||
// audio signal is provided.
|
||||
};
|
|
@ -9,6 +9,7 @@ Required properties:
|
|||
"ti,tlv320aic33" - TLV320AIC33
|
||||
"ti,tlv320aic3007" - TLV320AIC3007
|
||||
"ti,tlv320aic3106" - TLV320AIC3106
|
||||
"ti,tlv320aic3104" - TLV320AIC3104
|
||||
|
||||
|
||||
- reg - <int> - I2C slave address
|
||||
|
@ -18,6 +19,7 @@ Optional properties:
|
|||
|
||||
- gpio-reset - gpio pin number used for codec reset
|
||||
- ai3x-gpio-func - <array of 2 int> - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality
|
||||
- Not supported on tlv320aic3104
|
||||
- ai3x-micbias-vg - MicBias Voltage required.
|
||||
1 - MICBIAS output is powered to 2.0V,
|
||||
2 - MICBIAS output is powered to 2.5V,
|
||||
|
@ -36,7 +38,13 @@ CODEC output pins:
|
|||
* HPLCOM
|
||||
* HPRCOM
|
||||
|
||||
CODEC input pins:
|
||||
CODEC input pins for TLV320AIC3104:
|
||||
* MIC2L
|
||||
* MIC2R
|
||||
* LINE1L
|
||||
* LINE1R
|
||||
|
||||
CODEC input pins for other compatible codecs:
|
||||
* MIC3L
|
||||
* MIC3R
|
||||
* LINE1L
|
||||
|
|
|
@ -13,6 +13,11 @@ Required properties:
|
|||
- interrupt-parent: The parent interrupt controller
|
||||
- interrupts: Interrupt number for /INT pin from the 227e
|
||||
|
||||
Optional properies:
|
||||
- ti,micbias: Intended MICBIAS voltage (datasheet section 9.6.7).
|
||||
Select 0/1/2/3/4/5/6/7 to specify MACBIAS voltage
|
||||
2.1V/2.2V/2.3V/2.4V/2.5V/2.6V/2.7V/2.8V
|
||||
Default value is "1" (2.2V).
|
||||
|
||||
Examples:
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ WM8904 audio CODEC
|
|||
This device supports I2C only.
|
||||
|
||||
Required properties:
|
||||
- compatible: "wlf,wm8904"
|
||||
- compatible: "wlf,wm8904" or "wlf,wm8912"
|
||||
- reg: the I2C address of the device.
|
||||
- clock-names: "mclk"
|
||||
- clocks: reference to
|
||||
|
|
|
@ -10713,6 +10713,7 @@ M: Max Filippov <jcmvbkbc@gmail.com>
|
|||
L: linux-xtensa@linux-xtensa.org
|
||||
S: Maintained
|
||||
F: drivers/spi/spi-xtensa-xtfpga.c
|
||||
F: sound/soc/xtensa/xtfpga-i2s.c
|
||||
|
||||
YAM DRIVER FOR AX.25
|
||||
M: Jean-Paul Roubelat <jpr@f6fbb.org>
|
||||
|
|
|
@ -61,9 +61,12 @@
|
|||
reg = <0x03830000 0x100>;
|
||||
clocks = <&clock_audss EXYNOS_I2S_BUS>;
|
||||
clock-names = "iis";
|
||||
#clock-cells = <1>;
|
||||
clock-output-names = "i2s_cdclk0";
|
||||
dmas = <&pdma0 12>, <&pdma0 11>, <&pdma0 10>;
|
||||
dma-names = "tx", "rx", "tx-sec";
|
||||
samsung,idma-addr = <0x03000000>;
|
||||
#sound-dai-cells = <1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -372,8 +375,11 @@
|
|||
reg = <0x13960000 0x100>;
|
||||
clocks = <&clock CLK_I2S1>;
|
||||
clock-names = "iis";
|
||||
#clock-cells = <1>;
|
||||
clock-output-names = "i2s_cdclk1";
|
||||
dmas = <&pdma1 12>, <&pdma1 11>;
|
||||
dma-names = "tx", "rx";
|
||||
#sound-dai-cells = <1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -382,8 +388,11 @@
|
|||
reg = <0x13970000 0x100>;
|
||||
clocks = <&clock CLK_I2S2>;
|
||||
clock-names = "iis";
|
||||
#clock-cells = <1>;
|
||||
clock-output-names = "i2s_cdclk2";
|
||||
dmas = <&pdma0 14>, <&pdma0 13>;
|
||||
dma-names = "tx", "rx";
|
||||
#sound-dai-cells = <1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <dt-bindings/sound/samsung-i2s.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include "exynos4412.dtsi"
|
||||
|
||||
|
@ -37,14 +38,13 @@
|
|||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
clocks = <&clock_audss EXYNOS_I2S_BUS>,
|
||||
<&clock_audss EXYNOS_DOUT_AUD_BUS>;
|
||||
clock-names = "iis", "i2s_opclk0";
|
||||
<&clock_audss EXYNOS_DOUT_AUD_BUS>,
|
||||
<&clock_audss EXYNOS_SCLK_I2S>;
|
||||
clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
|
||||
};
|
||||
|
||||
sound: sound {
|
||||
compatible = "samsung,odroidx2-audio";
|
||||
samsung,i2s-controller = <&i2s0>;
|
||||
samsung,audio-codec = <&max98090>;
|
||||
compatible = "simple-audio-card";
|
||||
assigned-clocks = <&clock_audss EXYNOS_MOUT_AUDSS>,
|
||||
<&clock_audss EXYNOS_MOUT_I2S>,
|
||||
<&clock_audss EXYNOS_DOUT_SRP>,
|
||||
|
@ -55,6 +55,20 @@
|
|||
<0>,
|
||||
<192000000>,
|
||||
<19200000>;
|
||||
|
||||
simple-audio-card,format = "i2s";
|
||||
simple-audio-card,bitclock-master = <&link0_codec>;
|
||||
simple-audio-card,frame-master = <&link0_codec>;
|
||||
|
||||
simple-audio-card,cpu {
|
||||
sound-dai = <&i2s0 0>;
|
||||
system-clock-frequency = <19200000>;
|
||||
};
|
||||
|
||||
link0_codec: simple-audio-card,codec {
|
||||
sound-dai = <&max98090>;
|
||||
clocks = <&i2s0 CLK_I2S_CDCLK>;
|
||||
};
|
||||
};
|
||||
|
||||
mmc@12550000 {
|
||||
|
@ -373,6 +387,9 @@
|
|||
reg = <0x10>;
|
||||
interrupt-parent = <&gpx0>;
|
||||
interrupts = <0 0>;
|
||||
clocks = <&i2s0 CLK_I2S_CDCLK>;
|
||||
clock-names = "mclk";
|
||||
#sound-dai-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -49,9 +49,11 @@
|
|||
};
|
||||
|
||||
&sound {
|
||||
compatible = "samsung,odroidu3-audio";
|
||||
samsung,model = "Odroid-U3";
|
||||
samsung,audio-routing =
|
||||
simple-audio-card,name = "Odroid-U3";
|
||||
simple-audio-card,widgets =
|
||||
"Headphone", "Headphone Jack",
|
||||
"Speakers", "Speakers";
|
||||
simple-audio-card,routing =
|
||||
"Headphone Jack", "HPL",
|
||||
"Headphone Jack", "HPR",
|
||||
"Headphone Jack", "MICBIAS",
|
||||
|
|
|
@ -23,8 +23,12 @@
|
|||
};
|
||||
|
||||
&sound {
|
||||
samsung,model = "Odroid-X2";
|
||||
samsung,audio-routing =
|
||||
simple-audio-card,name = "Odroid-X2";
|
||||
simple-audio-card,widgets =
|
||||
"Headphone", "Headphone Jack",
|
||||
"Microphone", "Mic Jack",
|
||||
"Microphone", "DMIC";
|
||||
simple-audio-card,routing =
|
||||
"Headphone Jack", "HPL",
|
||||
"Headphone Jack", "HPR",
|
||||
"IN1", "Mic Jack",
|
||||
|
|
|
@ -830,6 +830,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
|
||||
intel_runtime_pm_enable(dev_priv);
|
||||
|
||||
i915_audio_component_init(dev_priv);
|
||||
|
||||
return 0;
|
||||
|
||||
out_power_well:
|
||||
|
@ -870,6 +872,8 @@ int i915_driver_unload(struct drm_device *dev)
|
|||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int ret;
|
||||
|
||||
i915_audio_component_cleanup(dev_priv);
|
||||
|
||||
ret = i915_gem_suspend(dev);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to idle hardware: %d\n", ret);
|
||||
|
|
|
@ -934,8 +934,7 @@ static int i915_pm_suspend(struct device *dev)
|
|||
|
||||
static int i915_pm_suspend_late(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
struct drm_device *drm_dev = dev_to_i915(dev)->dev;
|
||||
|
||||
/*
|
||||
* We have a suspedn ordering issue with the snd-hda driver also
|
||||
|
@ -954,8 +953,7 @@ static int i915_pm_suspend_late(struct device *dev)
|
|||
|
||||
static int i915_pm_resume_early(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
struct drm_device *drm_dev = dev_to_i915(dev)->dev;
|
||||
|
||||
if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
return 0;
|
||||
|
@ -965,8 +963,7 @@ static int i915_pm_resume_early(struct device *dev)
|
|||
|
||||
static int i915_pm_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
struct drm_device *drm_dev = dev_to_i915(dev)->dev;
|
||||
|
||||
if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
return 0;
|
||||
|
|
|
@ -1698,6 +1698,9 @@ struct drm_i915_private {
|
|||
struct drm_property *broadcast_rgb_property;
|
||||
struct drm_property *force_audio_property;
|
||||
|
||||
/* hda/i915 audio component */
|
||||
bool audio_component_registered;
|
||||
|
||||
uint32_t hw_context_size;
|
||||
struct list_head context_list;
|
||||
|
||||
|
@ -1781,6 +1784,11 @@ static inline struct drm_i915_private *to_i915(const struct drm_device *dev)
|
|||
return dev->dev_private;
|
||||
}
|
||||
|
||||
static inline struct drm_i915_private *dev_to_i915(struct device *dev)
|
||||
{
|
||||
return to_i915(dev_get_drvdata(dev));
|
||||
}
|
||||
|
||||
/* Iterate over initialised rings */
|
||||
#define for_each_ring(ring__, dev_priv__, i__) \
|
||||
for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/component.h>
|
||||
#include <drm/i915_component.h>
|
||||
#include "intel_drv.h"
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_edid.h>
|
||||
|
@ -461,3 +464,110 @@ void intel_init_audio(struct drm_device *dev)
|
|||
dev_priv->display.audio_codec_disable = ilk_audio_codec_disable;
|
||||
}
|
||||
}
|
||||
|
||||
static void i915_audio_component_get_power(struct device *dev)
|
||||
{
|
||||
intel_display_power_get(dev_to_i915(dev), POWER_DOMAIN_AUDIO);
|
||||
}
|
||||
|
||||
static void i915_audio_component_put_power(struct device *dev)
|
||||
{
|
||||
intel_display_power_put(dev_to_i915(dev), POWER_DOMAIN_AUDIO);
|
||||
}
|
||||
|
||||
/* Get CDCLK in kHz */
|
||||
static int i915_audio_component_get_cdclk_freq(struct device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev_to_i915(dev);
|
||||
int ret;
|
||||
|
||||
if (WARN_ON_ONCE(!HAS_DDI(dev_priv)))
|
||||
return -ENODEV;
|
||||
|
||||
intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
|
||||
ret = intel_ddi_get_cdclk_freq(dev_priv);
|
||||
intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct i915_audio_component_ops i915_audio_component_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.get_power = i915_audio_component_get_power,
|
||||
.put_power = i915_audio_component_put_power,
|
||||
.get_cdclk_freq = i915_audio_component_get_cdclk_freq,
|
||||
};
|
||||
|
||||
static int i915_audio_component_bind(struct device *i915_dev,
|
||||
struct device *hda_dev, void *data)
|
||||
{
|
||||
struct i915_audio_component *acomp = data;
|
||||
|
||||
if (WARN_ON(acomp->ops || acomp->dev))
|
||||
return -EEXIST;
|
||||
|
||||
acomp->ops = &i915_audio_component_ops;
|
||||
acomp->dev = i915_dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void i915_audio_component_unbind(struct device *i915_dev,
|
||||
struct device *hda_dev, void *data)
|
||||
{
|
||||
struct i915_audio_component *acomp = data;
|
||||
|
||||
acomp->ops = NULL;
|
||||
acomp->dev = NULL;
|
||||
}
|
||||
|
||||
static const struct component_ops i915_audio_component_bind_ops = {
|
||||
.bind = i915_audio_component_bind,
|
||||
.unbind = i915_audio_component_unbind,
|
||||
};
|
||||
|
||||
/**
|
||||
* i915_audio_component_init - initialize and register the audio component
|
||||
* @dev_priv: i915 device instance
|
||||
*
|
||||
* This will register with the component framework a child component which
|
||||
* will bind dynamically to the snd_hda_intel driver's corresponding master
|
||||
* component when the latter is registered. During binding the child
|
||||
* initializes an instance of struct i915_audio_component which it receives
|
||||
* from the master. The master can then start to use the interface defined by
|
||||
* this struct. Each side can break the binding at any point by deregistering
|
||||
* its own component after which each side's component unbind callback is
|
||||
* called.
|
||||
*
|
||||
* We ignore any error during registration and continue with reduced
|
||||
* functionality (i.e. without HDMI audio).
|
||||
*/
|
||||
void i915_audio_component_init(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = component_add(dev_priv->dev->dev, &i915_audio_component_bind_ops);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to add audio component (%d)\n", ret);
|
||||
/* continue with reduced functionality */
|
||||
return;
|
||||
}
|
||||
|
||||
dev_priv->audio_component_registered = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_audio_component_cleanup - deregister the audio component
|
||||
* @dev_priv: i915 device instance
|
||||
*
|
||||
* Deregisters the audio component, breaking any existing binding to the
|
||||
* corresponding snd_hda_intel driver's master component.
|
||||
*/
|
||||
void i915_audio_component_cleanup(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
if (!dev_priv->audio_component_registered)
|
||||
return;
|
||||
|
||||
component_del(dev_priv->dev->dev, &i915_audio_component_bind_ops);
|
||||
dev_priv->audio_component_registered = false;
|
||||
}
|
||||
|
|
|
@ -873,6 +873,8 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire);
|
|||
void intel_init_audio(struct drm_device *dev);
|
||||
void intel_audio_codec_enable(struct intel_encoder *encoder);
|
||||
void intel_audio_codec_disable(struct intel_encoder *encoder);
|
||||
void i915_audio_component_init(struct drm_i915_private *dev_priv);
|
||||
void i915_audio_component_cleanup(struct drm_i915_private *dev_priv);
|
||||
|
||||
/* intel_display.c */
|
||||
const char *intel_output_name(int output);
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
|
||||
#include "i915_drv.h"
|
||||
#include "intel_drv.h"
|
||||
#include <drm/i915_powerwell.h>
|
||||
|
||||
/**
|
||||
* DOC: runtime pm
|
||||
|
@ -50,8 +49,6 @@
|
|||
* present for a given platform.
|
||||
*/
|
||||
|
||||
static struct i915_power_domains *hsw_pwr;
|
||||
|
||||
#define for_each_power_well(i, power_well, domain_mask, power_domains) \
|
||||
for (i = 0; \
|
||||
i < (power_domains)->power_well_count && \
|
||||
|
@ -1071,10 +1068,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
|
|||
*/
|
||||
if (IS_HASWELL(dev_priv->dev)) {
|
||||
set_power_wells(power_domains, hsw_power_wells);
|
||||
hsw_pwr = power_domains;
|
||||
} else if (IS_BROADWELL(dev_priv->dev)) {
|
||||
set_power_wells(power_domains, bdw_power_wells);
|
||||
hsw_pwr = power_domains;
|
||||
} else if (IS_CHERRYVIEW(dev_priv->dev)) {
|
||||
set_power_wells(power_domains, chv_power_wells);
|
||||
} else if (IS_VALLEYVIEW(dev_priv->dev)) {
|
||||
|
@ -1118,8 +1113,6 @@ void intel_power_domains_fini(struct drm_i915_private *dev_priv)
|
|||
* the power well is not enabled, so just enable it in case
|
||||
* we're going to unload/reload. */
|
||||
intel_display_set_init_power(dev_priv, true);
|
||||
|
||||
hsw_pwr = NULL;
|
||||
}
|
||||
|
||||
static void intel_power_domains_resume(struct drm_i915_private *dev_priv)
|
||||
|
@ -1328,52 +1321,3 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
|
|||
pm_runtime_put_autosuspend(device);
|
||||
}
|
||||
|
||||
/* Display audio driver power well request */
|
||||
int i915_request_power_well(void)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
|
||||
if (!hsw_pwr)
|
||||
return -ENODEV;
|
||||
|
||||
dev_priv = container_of(hsw_pwr, struct drm_i915_private,
|
||||
power_domains);
|
||||
intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i915_request_power_well);
|
||||
|
||||
/* Display audio driver power well release */
|
||||
int i915_release_power_well(void)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
|
||||
if (!hsw_pwr)
|
||||
return -ENODEV;
|
||||
|
||||
dev_priv = container_of(hsw_pwr, struct drm_i915_private,
|
||||
power_domains);
|
||||
intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i915_release_power_well);
|
||||
|
||||
/*
|
||||
* Private interface for the audio driver to get CDCLK in kHz.
|
||||
*
|
||||
* Caller must request power well using i915_request_power_well() prior to
|
||||
* making the call.
|
||||
*/
|
||||
int i915_get_cdclk_freq(void)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
|
||||
if (!hsw_pwr)
|
||||
return -ENODEV;
|
||||
|
||||
dev_priv = container_of(hsw_pwr, struct drm_i915_private,
|
||||
power_domains);
|
||||
|
||||
return intel_ddi_get_cdclk_freq(dev_priv);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i915_get_cdclk_freq);
|
||||
|
|
|
@ -46,8 +46,6 @@ source "drivers/staging/rtl8723au/Kconfig"
|
|||
|
||||
source "drivers/staging/rts5208/Kconfig"
|
||||
|
||||
source "drivers/staging/line6/Kconfig"
|
||||
|
||||
source "drivers/staging/octeon/Kconfig"
|
||||
|
||||
source "drivers/staging/octeon-usb/Kconfig"
|
||||
|
|
|
@ -15,7 +15,6 @@ obj-$(CONFIG_R8712U) += rtl8712/
|
|||
obj-$(CONFIG_R8188EU) += rtl8188eu/
|
||||
obj-$(CONFIG_R8723AU) += rtl8723au/
|
||||
obj-$(CONFIG_RTS5208) += rts5208/
|
||||
obj-$(CONFIG_LINE6_USB) += line6/
|
||||
obj-$(CONFIG_NETLOGIC_XLR_NET) += netlogic/
|
||||
obj-$(CONFIG_OCTEON_ETHERNET) += octeon/
|
||||
obj-$(CONFIG_OCTEON_USB) += octeon-usb/
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
menuconfig LINE6_USB
|
||||
tristate "Line6 USB support"
|
||||
depends on USB && SND
|
||||
select SND_RAWMIDI
|
||||
select SND_PCM
|
||||
help
|
||||
This is a driver for the guitar amp, cab, and effects modeller
|
||||
PODxt Pro by Line6 (and similar devices), supporting the
|
||||
following features:
|
||||
* Reading/writing individual parameters
|
||||
* Reading/writing complete channel, effects setup, and amp
|
||||
setup data
|
||||
* Channel switching
|
||||
* Virtual MIDI interface
|
||||
* Tuner access
|
||||
* Playback/capture/mixer device for any ALSA-compatible PCM
|
||||
audio application
|
||||
* Signal routing (record clean/processed guitar signal,
|
||||
re-amping)
|
||||
|
||||
Preliminary support for the Variax Workbench and TonePort
|
||||
devices is included.
|
||||
|
||||
if LINE6_USB
|
||||
|
||||
config LINE6_USB_IMPULSE_RESPONSE
|
||||
bool "measure impulse response"
|
||||
default n
|
||||
help
|
||||
Say Y here to add code to measure the impulse response of a Line6
|
||||
device. This is more accurate than user-space methods since it
|
||||
bypasses any PCM data buffering (e.g., by ALSA or jack). This is
|
||||
useful for assessing the performance of new devices, but is not
|
||||
required for normal operation.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
endif # LINE6_USB
|
|
@ -1,14 +0,0 @@
|
|||
obj-$(CONFIG_LINE6_USB) += line6usb.o
|
||||
|
||||
line6usb-y := \
|
||||
audio.o \
|
||||
capture.o \
|
||||
driver.o \
|
||||
midi.o \
|
||||
midibuf.o \
|
||||
pcm.o \
|
||||
playback.o \
|
||||
pod.o \
|
||||
toneport.o \
|
||||
variax.o \
|
||||
podhd.o
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include "driver.h"
|
||||
#include "audio.h"
|
||||
|
||||
/*
|
||||
Initialize the Line6 USB audio system.
|
||||
*/
|
||||
int line6_init_audio(struct usb_line6 *line6)
|
||||
{
|
||||
struct snd_card *card;
|
||||
int err;
|
||||
|
||||
err = snd_card_new(line6->ifcdev,
|
||||
SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
|
||||
THIS_MODULE, 0, &card);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
line6->card = card;
|
||||
|
||||
strcpy(card->id, line6->properties->id);
|
||||
strcpy(card->driver, DRIVER_NAME);
|
||||
strcpy(card->shortname, line6->properties->name);
|
||||
/* longname is 80 chars - see asound.h */
|
||||
sprintf(card->longname, "Line6 %s at USB %s", line6->properties->name,
|
||||
dev_name(line6->ifcdev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Register the Line6 USB audio system.
|
||||
*/
|
||||
int line6_register_audio(struct usb_line6 *line6)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = snd_card_register(line6->card);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Cleanup the Line6 USB audio system.
|
||||
*/
|
||||
void line6_cleanup_audio(struct usb_line6 *line6)
|
||||
{
|
||||
struct snd_card *card = line6->card;
|
||||
|
||||
if (card == NULL)
|
||||
return;
|
||||
|
||||
snd_card_disconnect(card);
|
||||
snd_card_free(card);
|
||||
line6->card = NULL;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AUDIO_H
|
||||
#define AUDIO_H
|
||||
|
||||
#include "driver.h"
|
||||
|
||||
extern void line6_cleanup_audio(struct usb_line6 *);
|
||||
extern int line6_init_audio(struct usb_line6 *);
|
||||
extern int line6_register_audio(struct usb_line6 *);
|
||||
|
||||
#endif
|
|
@ -1,432 +0,0 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "audio.h"
|
||||
#include "capture.h"
|
||||
#include "driver.h"
|
||||
#include "pcm.h"
|
||||
#include "pod.h"
|
||||
|
||||
/*
|
||||
Find a free URB and submit it.
|
||||
*/
|
||||
static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
|
||||
{
|
||||
int index;
|
||||
unsigned long flags;
|
||||
int i, urb_size;
|
||||
int ret;
|
||||
struct urb *urb_in;
|
||||
|
||||
spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
|
||||
index =
|
||||
find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS);
|
||||
|
||||
if (index < 0 || index >= LINE6_ISO_BUFFERS) {
|
||||
spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
|
||||
dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
urb_in = line6pcm->urb_audio_in[index];
|
||||
urb_size = 0;
|
||||
|
||||
for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
|
||||
struct usb_iso_packet_descriptor *fin =
|
||||
&urb_in->iso_frame_desc[i];
|
||||
fin->offset = urb_size;
|
||||
fin->length = line6pcm->max_packet_size;
|
||||
urb_size += line6pcm->max_packet_size;
|
||||
}
|
||||
|
||||
urb_in->transfer_buffer =
|
||||
line6pcm->buffer_in +
|
||||
index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
|
||||
urb_in->transfer_buffer_length = urb_size;
|
||||
urb_in->context = line6pcm;
|
||||
|
||||
ret = usb_submit_urb(urb_in, GFP_ATOMIC);
|
||||
|
||||
if (ret == 0)
|
||||
set_bit(index, &line6pcm->active_urb_in);
|
||||
else
|
||||
dev_err(line6pcm->line6->ifcdev,
|
||||
"URB in #%d submission failed (%d)\n", index, ret);
|
||||
|
||||
spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Submit all currently available capture URBs.
|
||||
*/
|
||||
int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
|
||||
ret = submit_audio_in_urb(line6pcm);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Unlink all currently active capture URBs.
|
||||
*/
|
||||
void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = LINE6_ISO_BUFFERS; i--;) {
|
||||
if (test_bit(i, &line6pcm->active_urb_in)) {
|
||||
if (!test_and_set_bit(i, &line6pcm->unlink_urb_in)) {
|
||||
struct urb *u = line6pcm->urb_audio_in[i];
|
||||
|
||||
usb_unlink_urb(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Wait until unlinking of all currently active capture URBs has been
|
||||
finished.
|
||||
*/
|
||||
void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
|
||||
{
|
||||
int timeout = HZ;
|
||||
unsigned int i;
|
||||
int alive;
|
||||
|
||||
do {
|
||||
alive = 0;
|
||||
for (i = LINE6_ISO_BUFFERS; i--;) {
|
||||
if (test_bit(i, &line6pcm->active_urb_in))
|
||||
alive++;
|
||||
}
|
||||
if (!alive)
|
||||
break;
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
schedule_timeout(1);
|
||||
} while (--timeout > 0);
|
||||
if (alive)
|
||||
snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
|
||||
}
|
||||
|
||||
/*
|
||||
Unlink all currently active capture URBs, and wait for finishing.
|
||||
*/
|
||||
void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
|
||||
{
|
||||
line6_unlink_audio_in_urbs(line6pcm);
|
||||
line6_wait_clear_audio_in_urbs(line6pcm);
|
||||
}
|
||||
|
||||
/*
|
||||
Copy data into ALSA capture buffer.
|
||||
*/
|
||||
void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize)
|
||||
{
|
||||
struct snd_pcm_substream *substream =
|
||||
get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
|
||||
int frames = fsize / bytes_per_frame;
|
||||
|
||||
if (runtime == NULL)
|
||||
return;
|
||||
|
||||
if (line6pcm->pos_in_done + frames > runtime->buffer_size) {
|
||||
/*
|
||||
The transferred area goes over buffer boundary,
|
||||
copy two separate chunks.
|
||||
*/
|
||||
int len;
|
||||
|
||||
len = runtime->buffer_size - line6pcm->pos_in_done;
|
||||
|
||||
if (len > 0) {
|
||||
memcpy(runtime->dma_area +
|
||||
line6pcm->pos_in_done * bytes_per_frame, fbuf,
|
||||
len * bytes_per_frame);
|
||||
memcpy(runtime->dma_area, fbuf + len * bytes_per_frame,
|
||||
(frames - len) * bytes_per_frame);
|
||||
} else {
|
||||
/* this is somewhat paranoid */
|
||||
dev_err(line6pcm->line6->ifcdev,
|
||||
"driver bug: len = %d\n", len);
|
||||
}
|
||||
} else {
|
||||
/* copy single chunk */
|
||||
memcpy(runtime->dma_area +
|
||||
line6pcm->pos_in_done * bytes_per_frame, fbuf, fsize);
|
||||
}
|
||||
|
||||
line6pcm->pos_in_done += frames;
|
||||
if (line6pcm->pos_in_done >= runtime->buffer_size)
|
||||
line6pcm->pos_in_done -= runtime->buffer_size;
|
||||
}
|
||||
|
||||
void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)
|
||||
{
|
||||
struct snd_pcm_substream *substream =
|
||||
get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
|
||||
|
||||
line6pcm->bytes_in += length;
|
||||
if (line6pcm->bytes_in >= line6pcm->period_in) {
|
||||
line6pcm->bytes_in %= line6pcm->period_in;
|
||||
snd_pcm_period_elapsed(substream);
|
||||
}
|
||||
}
|
||||
|
||||
void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm)
|
||||
{
|
||||
kfree(line6pcm->buffer_in);
|
||||
line6pcm->buffer_in = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for completed capture URB.
|
||||
*/
|
||||
static void audio_in_callback(struct urb *urb)
|
||||
{
|
||||
int i, index, length = 0, shutdown = 0;
|
||||
unsigned long flags;
|
||||
|
||||
struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
|
||||
|
||||
line6pcm->last_frame_in = urb->start_frame;
|
||||
|
||||
/* find index of URB */
|
||||
for (index = 0; index < LINE6_ISO_BUFFERS; ++index)
|
||||
if (urb == line6pcm->urb_audio_in[index])
|
||||
break;
|
||||
|
||||
spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
|
||||
|
||||
for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
|
||||
char *fbuf;
|
||||
int fsize;
|
||||
struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i];
|
||||
|
||||
if (fin->status == -EXDEV) {
|
||||
shutdown = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
fbuf = urb->transfer_buffer + fin->offset;
|
||||
fsize = fin->actual_length;
|
||||
|
||||
if (fsize > line6pcm->max_packet_size) {
|
||||
dev_err(line6pcm->line6->ifcdev,
|
||||
"driver and/or device bug: packet too large (%d > %d)\n",
|
||||
fsize, line6pcm->max_packet_size);
|
||||
}
|
||||
|
||||
length += fsize;
|
||||
|
||||
/* the following assumes LINE6_ISO_PACKETS == 1: */
|
||||
line6pcm->prev_fbuf = fbuf;
|
||||
line6pcm->prev_fsize = fsize;
|
||||
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
|
||||
#endif
|
||||
if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
|
||||
&line6pcm->flags) && (fsize > 0))
|
||||
line6_capture_copy(line6pcm, fbuf, fsize);
|
||||
}
|
||||
|
||||
clear_bit(index, &line6pcm->active_urb_in);
|
||||
|
||||
if (test_and_clear_bit(index, &line6pcm->unlink_urb_in))
|
||||
shutdown = 1;
|
||||
|
||||
spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
|
||||
|
||||
if (!shutdown) {
|
||||
submit_audio_in_urb(line6pcm);
|
||||
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
|
||||
#endif
|
||||
if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
|
||||
&line6pcm->flags))
|
||||
line6_capture_check_period(line6pcm, length);
|
||||
}
|
||||
}
|
||||
|
||||
/* open capture callback */
|
||||
static int snd_line6_capture_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
int err;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
|
||||
|
||||
err = snd_pcm_hw_constraint_ratdens(runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_RATE,
|
||||
(&line6pcm->
|
||||
properties->snd_line6_rates));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
runtime->hw = line6pcm->properties->snd_line6_capture_hw;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* close capture callback */
|
||||
static int snd_line6_capture_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* hw_params capture callback */
|
||||
static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
{
|
||||
int ret;
|
||||
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
|
||||
|
||||
/* -- Florian Demski [FD] */
|
||||
/* don't ask me why, but this fixes the bug on my machine */
|
||||
if (line6pcm == NULL) {
|
||||
if (substream->pcm == NULL)
|
||||
return -ENOMEM;
|
||||
if (substream->pcm->private_data == NULL)
|
||||
return -ENOMEM;
|
||||
substream->private_data = substream->pcm->private_data;
|
||||
line6pcm = snd_pcm_substream_chip(substream);
|
||||
}
|
||||
/* -- [FD] end */
|
||||
|
||||
ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_pcm_lib_malloc_pages(substream,
|
||||
params_buffer_bytes(hw_params));
|
||||
if (ret < 0) {
|
||||
line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
|
||||
return ret;
|
||||
}
|
||||
|
||||
line6pcm->period_in = params_period_bytes(hw_params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* hw_free capture callback */
|
||||
static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
|
||||
|
||||
line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
|
||||
return snd_pcm_lib_free_pages(substream);
|
||||
}
|
||||
|
||||
/* trigger callback */
|
||||
int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
|
||||
{
|
||||
int err;
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
#ifdef CONFIG_PM
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
#endif
|
||||
err = line6_pcm_acquire(line6pcm,
|
||||
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
#ifdef CONFIG_PM
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
#endif
|
||||
err = line6_pcm_release(line6pcm,
|
||||
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* capture pointer callback */
|
||||
static snd_pcm_uframes_t
|
||||
snd_line6_capture_pointer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
|
||||
|
||||
return line6pcm->pos_in_done;
|
||||
}
|
||||
|
||||
/* capture operators */
|
||||
struct snd_pcm_ops snd_line6_capture_ops = {
|
||||
.open = snd_line6_capture_open,
|
||||
.close = snd_line6_capture_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = snd_line6_capture_hw_params,
|
||||
.hw_free = snd_line6_capture_hw_free,
|
||||
.prepare = snd_line6_prepare,
|
||||
.trigger = snd_line6_trigger,
|
||||
.pointer = snd_line6_capture_pointer,
|
||||
};
|
||||
|
||||
int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* create audio URBs and fill in constant values: */
|
||||
for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
|
||||
struct urb *urb;
|
||||
|
||||
/* URB for audio in: */
|
||||
urb = line6pcm->urb_audio_in[i] =
|
||||
usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
|
||||
|
||||
if (urb == NULL) {
|
||||
dev_err(line6pcm->line6->ifcdev, "Out of memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
urb->dev = line6pcm->line6->usbdev;
|
||||
urb->pipe =
|
||||
usb_rcvisocpipe(line6pcm->line6->usbdev,
|
||||
line6pcm->ep_audio_read &
|
||||
USB_ENDPOINT_NUMBER_MASK);
|
||||
urb->transfer_flags = URB_ISO_ASAP;
|
||||
urb->start_frame = -1;
|
||||
urb->number_of_packets = LINE6_ISO_PACKETS;
|
||||
urb->interval = LINE6_ISO_INTERVAL;
|
||||
urb->error_count = 0;
|
||||
urb->complete = audio_in_callback;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,576 +0,0 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "audio.h"
|
||||
#include "capture.h"
|
||||
#include "driver.h"
|
||||
#include "playback.h"
|
||||
#include "pod.h"
|
||||
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
|
||||
static struct snd_line6_pcm *dev2pcm(struct device *dev)
|
||||
{
|
||||
struct usb_interface *interface = to_usb_interface(dev);
|
||||
struct usb_line6 *line6 = usb_get_intfdata(interface);
|
||||
struct snd_line6_pcm *line6pcm = line6->line6pcm;
|
||||
return line6pcm;
|
||||
}
|
||||
|
||||
/*
|
||||
"read" request on "impulse_volume" special file.
|
||||
*/
|
||||
static ssize_t impulse_volume_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_volume);
|
||||
}
|
||||
|
||||
/*
|
||||
"write" request on "impulse_volume" special file.
|
||||
*/
|
||||
static ssize_t impulse_volume_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct snd_line6_pcm *line6pcm = dev2pcm(dev);
|
||||
int value;
|
||||
int ret;
|
||||
|
||||
ret = kstrtoint(buf, 10, &value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
line6pcm->impulse_volume = value;
|
||||
|
||||
if (value > 0)
|
||||
line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE);
|
||||
else
|
||||
line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE);
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(impulse_volume);
|
||||
|
||||
/*
|
||||
"read" request on "impulse_period" special file.
|
||||
*/
|
||||
static ssize_t impulse_period_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_period);
|
||||
}
|
||||
|
||||
/*
|
||||
"write" request on "impulse_period" special file.
|
||||
*/
|
||||
static ssize_t impulse_period_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int value;
|
||||
int ret;
|
||||
|
||||
ret = kstrtoint(buf, 10, &value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev2pcm(dev)->impulse_period = value;
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(impulse_period);
|
||||
|
||||
#endif
|
||||
|
||||
static bool test_flags(unsigned long flags0, unsigned long flags1,
|
||||
unsigned long mask)
|
||||
{
|
||||
return ((flags0 & mask) == 0) && ((flags1 & mask) != 0);
|
||||
}
|
||||
|
||||
int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels)
|
||||
{
|
||||
unsigned long flags_old, flags_new, flags_final;
|
||||
int err;
|
||||
|
||||
do {
|
||||
flags_old = ACCESS_ONCE(line6pcm->flags);
|
||||
flags_new = flags_old | channels;
|
||||
} while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old);
|
||||
|
||||
flags_final = flags_old;
|
||||
|
||||
line6pcm->prev_fbuf = NULL;
|
||||
|
||||
if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) {
|
||||
/* Invoked multiple times in a row so allocate once only */
|
||||
if (!line6pcm->buffer_in) {
|
||||
line6pcm->buffer_in =
|
||||
kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
|
||||
line6pcm->max_packet_size, GFP_KERNEL);
|
||||
if (!line6pcm->buffer_in) {
|
||||
err = -ENOMEM;
|
||||
goto pcm_acquire_error;
|
||||
}
|
||||
|
||||
flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER;
|
||||
}
|
||||
}
|
||||
|
||||
if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) {
|
||||
/*
|
||||
Waiting for completion of active URBs in the stop handler is
|
||||
a bug, we therefore report an error if capturing is restarted
|
||||
too soon.
|
||||
*/
|
||||
if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) {
|
||||
dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
line6pcm->count_in = 0;
|
||||
line6pcm->prev_fsize = 0;
|
||||
err = line6_submit_audio_in_all_urbs(line6pcm);
|
||||
|
||||
if (err < 0)
|
||||
goto pcm_acquire_error;
|
||||
|
||||
flags_final |= channels & LINE6_BITS_CAPTURE_STREAM;
|
||||
}
|
||||
|
||||
if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) {
|
||||
/* Invoked multiple times in a row so allocate once only */
|
||||
if (!line6pcm->buffer_out) {
|
||||
line6pcm->buffer_out =
|
||||
kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
|
||||
line6pcm->max_packet_size, GFP_KERNEL);
|
||||
if (!line6pcm->buffer_out) {
|
||||
err = -ENOMEM;
|
||||
goto pcm_acquire_error;
|
||||
}
|
||||
|
||||
flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER;
|
||||
}
|
||||
}
|
||||
|
||||
if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) {
|
||||
/*
|
||||
See comment above regarding PCM restart.
|
||||
*/
|
||||
if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) {
|
||||
dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
line6pcm->count_out = 0;
|
||||
err = line6_submit_audio_out_all_urbs(line6pcm);
|
||||
|
||||
if (err < 0)
|
||||
goto pcm_acquire_error;
|
||||
|
||||
flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
pcm_acquire_error:
|
||||
/*
|
||||
If not all requested resources/streams could be obtained, release
|
||||
those which were successfully obtained (if any).
|
||||
*/
|
||||
line6_pcm_release(line6pcm, flags_final & channels);
|
||||
return err;
|
||||
}
|
||||
|
||||
int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels)
|
||||
{
|
||||
unsigned long flags_old, flags_new;
|
||||
|
||||
do {
|
||||
flags_old = ACCESS_ONCE(line6pcm->flags);
|
||||
flags_new = flags_old & ~channels;
|
||||
} while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old);
|
||||
|
||||
if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM))
|
||||
line6_unlink_audio_in_urbs(line6pcm);
|
||||
|
||||
if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) {
|
||||
line6_wait_clear_audio_in_urbs(line6pcm);
|
||||
line6_free_capture_buffer(line6pcm);
|
||||
}
|
||||
|
||||
if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM))
|
||||
line6_unlink_audio_out_urbs(line6pcm);
|
||||
|
||||
if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) {
|
||||
line6_wait_clear_audio_out_urbs(line6pcm);
|
||||
line6_free_playback_buffer(line6pcm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* trigger callback */
|
||||
int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
|
||||
struct snd_pcm_substream *s;
|
||||
int err;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&line6pcm->lock_trigger, flags);
|
||||
clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags);
|
||||
|
||||
snd_pcm_group_for_each_entry(s, substream) {
|
||||
switch (s->stream) {
|
||||
case SNDRV_PCM_STREAM_PLAYBACK:
|
||||
err = snd_line6_playback_trigger(line6pcm, cmd);
|
||||
|
||||
if (err < 0) {
|
||||
spin_unlock_irqrestore(&line6pcm->lock_trigger,
|
||||
flags);
|
||||
return err;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_STREAM_CAPTURE:
|
||||
err = snd_line6_capture_trigger(line6pcm, cmd);
|
||||
|
||||
if (err < 0) {
|
||||
spin_unlock_irqrestore(&line6pcm->lock_trigger,
|
||||
flags);
|
||||
return err;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(line6pcm->line6->ifcdev,
|
||||
"Unknown stream direction %d\n", s->stream);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&line6pcm->lock_trigger, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* control info callback */
|
||||
static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = 2;
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 256;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* control get callback */
|
||||
static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
int i;
|
||||
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
for (i = 2; i--;)
|
||||
ucontrol->value.integer.value[i] = line6pcm->volume_playback[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* control put callback */
|
||||
static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
int i, changed = 0;
|
||||
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
for (i = 2; i--;)
|
||||
if (line6pcm->volume_playback[i] !=
|
||||
ucontrol->value.integer.value[i]) {
|
||||
line6pcm->volume_playback[i] =
|
||||
ucontrol->value.integer.value[i];
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/* control definition */
|
||||
static struct snd_kcontrol_new line6_control_playback = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "PCM Playback Volume",
|
||||
.index = 0,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.info = snd_line6_control_playback_info,
|
||||
.get = snd_line6_control_playback_get,
|
||||
.put = snd_line6_control_playback_put
|
||||
};
|
||||
|
||||
/*
|
||||
Cleanup the PCM device.
|
||||
*/
|
||||
static void line6_cleanup_pcm(struct snd_pcm *pcm)
|
||||
{
|
||||
int i;
|
||||
struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);
|
||||
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_volume);
|
||||
device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_period);
|
||||
#endif
|
||||
|
||||
for (i = LINE6_ISO_BUFFERS; i--;) {
|
||||
if (line6pcm->urb_audio_out[i]) {
|
||||
usb_kill_urb(line6pcm->urb_audio_out[i]);
|
||||
usb_free_urb(line6pcm->urb_audio_out[i]);
|
||||
}
|
||||
if (line6pcm->urb_audio_in[i]) {
|
||||
usb_kill_urb(line6pcm->urb_audio_in[i]);
|
||||
usb_free_urb(line6pcm->urb_audio_in[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* create a PCM device */
|
||||
static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm)
|
||||
{
|
||||
struct snd_pcm *pcm;
|
||||
int err;
|
||||
|
||||
err = snd_pcm_new(line6pcm->line6->card,
|
||||
(char *)line6pcm->line6->properties->name,
|
||||
0, 1, 1, &pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
pcm->private_data = line6pcm;
|
||||
pcm->private_free = line6_cleanup_pcm;
|
||||
line6pcm->pcm = pcm;
|
||||
strcpy(pcm->name, line6pcm->line6->properties->name);
|
||||
|
||||
/* set operators */
|
||||
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
|
||||
&snd_line6_playback_ops);
|
||||
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops);
|
||||
|
||||
/* pre-allocation of buffers */
|
||||
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
|
||||
snd_dma_continuous_data
|
||||
(GFP_KERNEL), 64 * 1024,
|
||||
128 * 1024);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* PCM device destructor */
|
||||
static int snd_line6_pcm_free(struct snd_device *device)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Stop substream if still running.
|
||||
*/
|
||||
static void pcm_disconnect_substream(struct snd_pcm_substream *substream)
|
||||
{
|
||||
if (substream->runtime && snd_pcm_running(substream)) {
|
||||
snd_pcm_stream_lock_irq(substream);
|
||||
snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
|
||||
snd_pcm_stream_unlock_irq(substream);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Stop PCM stream.
|
||||
*/
|
||||
void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm)
|
||||
{
|
||||
pcm_disconnect_substream(get_substream
|
||||
(line6pcm, SNDRV_PCM_STREAM_CAPTURE));
|
||||
pcm_disconnect_substream(get_substream
|
||||
(line6pcm, SNDRV_PCM_STREAM_PLAYBACK));
|
||||
line6_unlink_wait_clear_audio_out_urbs(line6pcm);
|
||||
line6_unlink_wait_clear_audio_in_urbs(line6pcm);
|
||||
}
|
||||
|
||||
/*
|
||||
Create and register the PCM device and mixer entries.
|
||||
Create URBs for playback and capture.
|
||||
*/
|
||||
int line6_init_pcm(struct usb_line6 *line6,
|
||||
struct line6_pcm_properties *properties)
|
||||
{
|
||||
static struct snd_device_ops pcm_ops = {
|
||||
.dev_free = snd_line6_pcm_free,
|
||||
};
|
||||
|
||||
int err;
|
||||
int ep_read = 0, ep_write = 0;
|
||||
struct snd_line6_pcm *line6pcm;
|
||||
|
||||
if (!(line6->properties->capabilities & LINE6_BIT_PCM))
|
||||
return 0; /* skip PCM initialization and report success */
|
||||
|
||||
/* initialize PCM subsystem based on product id: */
|
||||
switch (line6->product) {
|
||||
case LINE6_DEVID_BASSPODXT:
|
||||
case LINE6_DEVID_BASSPODXTLIVE:
|
||||
case LINE6_DEVID_BASSPODXTPRO:
|
||||
case LINE6_DEVID_PODXT:
|
||||
case LINE6_DEVID_PODXTLIVE:
|
||||
case LINE6_DEVID_PODXTPRO:
|
||||
case LINE6_DEVID_PODHD300:
|
||||
case LINE6_DEVID_PODHD400:
|
||||
ep_read = 0x82;
|
||||
ep_write = 0x01;
|
||||
break;
|
||||
|
||||
case LINE6_DEVID_PODHD500:
|
||||
case LINE6_DEVID_PODX3:
|
||||
case LINE6_DEVID_PODX3LIVE:
|
||||
ep_read = 0x86;
|
||||
ep_write = 0x02;
|
||||
break;
|
||||
|
||||
case LINE6_DEVID_POCKETPOD:
|
||||
ep_read = 0x82;
|
||||
ep_write = 0x02;
|
||||
break;
|
||||
|
||||
case LINE6_DEVID_GUITARPORT:
|
||||
case LINE6_DEVID_PODSTUDIO_GX:
|
||||
case LINE6_DEVID_PODSTUDIO_UX1:
|
||||
case LINE6_DEVID_PODSTUDIO_UX2:
|
||||
case LINE6_DEVID_TONEPORT_GX:
|
||||
case LINE6_DEVID_TONEPORT_UX1:
|
||||
case LINE6_DEVID_TONEPORT_UX2:
|
||||
ep_read = 0x82;
|
||||
ep_write = 0x01;
|
||||
break;
|
||||
|
||||
/* this is for interface_number == 1:
|
||||
case LINE6_DEVID_TONEPORT_UX2:
|
||||
case LINE6_DEVID_PODSTUDIO_UX2:
|
||||
ep_read = 0x87;
|
||||
ep_write = 0x00;
|
||||
break; */
|
||||
|
||||
default:
|
||||
MISSING_CASE;
|
||||
}
|
||||
|
||||
line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL);
|
||||
|
||||
if (line6pcm == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255;
|
||||
line6pcm->volume_monitor = 255;
|
||||
line6pcm->line6 = line6;
|
||||
line6pcm->ep_audio_read = ep_read;
|
||||
line6pcm->ep_audio_write = ep_write;
|
||||
|
||||
/* Read and write buffers are sized identically, so choose minimum */
|
||||
line6pcm->max_packet_size = min(
|
||||
usb_maxpacket(line6->usbdev,
|
||||
usb_rcvisocpipe(line6->usbdev, ep_read), 0),
|
||||
usb_maxpacket(line6->usbdev,
|
||||
usb_sndisocpipe(line6->usbdev, ep_write), 1));
|
||||
|
||||
line6pcm->properties = properties;
|
||||
line6->line6pcm = line6pcm;
|
||||
|
||||
/* PCM device: */
|
||||
err = snd_device_new(line6->card, SNDRV_DEV_PCM, line6, &pcm_ops);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = snd_line6_new_pcm(line6pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
spin_lock_init(&line6pcm->lock_audio_out);
|
||||
spin_lock_init(&line6pcm->lock_audio_in);
|
||||
spin_lock_init(&line6pcm->lock_trigger);
|
||||
|
||||
err = line6_create_audio_out_urbs(line6pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = line6_create_audio_in_urbs(line6pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* mixer: */
|
||||
err =
|
||||
snd_ctl_add(line6->card,
|
||||
snd_ctl_new1(&line6_control_playback, line6pcm));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
/* impulse response test: */
|
||||
err = device_create_file(line6->ifcdev, &dev_attr_impulse_volume);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = device_create_file(line6->ifcdev, &dev_attr_impulse_period);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* prepare pcm callback */
|
||||
int snd_line6_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
|
||||
|
||||
switch (substream->stream) {
|
||||
case SNDRV_PCM_STREAM_PLAYBACK:
|
||||
if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0)
|
||||
line6_unlink_wait_clear_audio_out_urbs(line6pcm);
|
||||
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_STREAM_CAPTURE:
|
||||
if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0)
|
||||
line6_unlink_wait_clear_audio_in_urbs(line6pcm);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
MISSING_CASE;
|
||||
}
|
||||
|
||||
if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) {
|
||||
line6pcm->count_out = 0;
|
||||
line6pcm->pos_out = 0;
|
||||
line6pcm->pos_out_done = 0;
|
||||
line6pcm->bytes_out = 0;
|
||||
line6pcm->count_in = 0;
|
||||
line6pcm->pos_in_done = 0;
|
||||
line6pcm->bytes_in = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,382 +0,0 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
PCM interface to POD series devices.
|
||||
*/
|
||||
|
||||
#ifndef PCM_H
|
||||
#define PCM_H
|
||||
|
||||
#include <sound/pcm.h>
|
||||
|
||||
#include "driver.h"
|
||||
#include "usbdefs.h"
|
||||
|
||||
/* number of URBs */
|
||||
#define LINE6_ISO_BUFFERS 2
|
||||
|
||||
/*
|
||||
number of USB frames per URB
|
||||
The Line6 Windows driver always transmits two frames per packet, but
|
||||
the Linux driver performs significantly better (i.e., lower latency)
|
||||
with only one frame per packet.
|
||||
*/
|
||||
#define LINE6_ISO_PACKETS 1
|
||||
|
||||
/* in a "full speed" device (such as the PODxt Pro) this means 1ms */
|
||||
#define LINE6_ISO_INTERVAL 1
|
||||
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
#define LINE6_IMPULSE_DEFAULT_PERIOD 100
|
||||
#endif
|
||||
|
||||
/*
|
||||
Get substream from Line6 PCM data structure
|
||||
*/
|
||||
#define get_substream(line6pcm, stream) \
|
||||
(line6pcm->pcm->streams[stream].substream)
|
||||
|
||||
/*
|
||||
PCM mode bits.
|
||||
|
||||
There are several features of the Line6 USB driver which require PCM
|
||||
data to be exchanged with the device:
|
||||
*) PCM playback and capture via ALSA
|
||||
*) software monitoring (for devices without hardware monitoring)
|
||||
*) optional impulse response measurement
|
||||
However, from the device's point of view, there is just a single
|
||||
capture and playback stream, which must be shared between these
|
||||
subsystems. It is therefore necessary to maintain the state of the
|
||||
subsystems with respect to PCM usage. We define several constants of
|
||||
the form LINE6_BIT_PCM_<subsystem>_<direction>_<resource> with the
|
||||
following meanings:
|
||||
*) <subsystem> is one of
|
||||
-) ALSA: PCM playback and capture via ALSA
|
||||
-) MONITOR: software monitoring
|
||||
-) IMPULSE: optional impulse response measurement
|
||||
*) <direction> is one of
|
||||
-) PLAYBACK: audio output (from host to device)
|
||||
-) CAPTURE: audio input (from device to host)
|
||||
*) <resource> is one of
|
||||
-) BUFFER: buffer required by PCM data stream
|
||||
-) STREAM: actual PCM data stream
|
||||
|
||||
The subsystems call line6_pcm_acquire() to acquire the (shared)
|
||||
resources needed for a particular operation (e.g., allocate the buffer
|
||||
for ALSA playback or start the capture stream for software monitoring).
|
||||
When a resource is no longer needed, it is released by calling
|
||||
line6_pcm_release(). Buffer allocation and stream startup are handled
|
||||
separately to allow the ALSA kernel driver to perform them at
|
||||
appropriate places (since the callback which starts a PCM stream is not
|
||||
allowed to sleep).
|
||||
*/
|
||||
enum {
|
||||
/* individual bit indices: */
|
||||
LINE6_INDEX_PCM_ALSA_PLAYBACK_BUFFER,
|
||||
LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM,
|
||||
LINE6_INDEX_PCM_ALSA_CAPTURE_BUFFER,
|
||||
LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
|
||||
LINE6_INDEX_PCM_MONITOR_PLAYBACK_BUFFER,
|
||||
LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM,
|
||||
LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER,
|
||||
LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM,
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER,
|
||||
LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM,
|
||||
LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER,
|
||||
LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM,
|
||||
#endif
|
||||
LINE6_INDEX_PAUSE_PLAYBACK,
|
||||
LINE6_INDEX_PREPARED,
|
||||
|
||||
/* individual bit masks: */
|
||||
LINE6_BIT(PCM_ALSA_PLAYBACK_BUFFER),
|
||||
LINE6_BIT(PCM_ALSA_PLAYBACK_STREAM),
|
||||
LINE6_BIT(PCM_ALSA_CAPTURE_BUFFER),
|
||||
LINE6_BIT(PCM_ALSA_CAPTURE_STREAM),
|
||||
LINE6_BIT(PCM_MONITOR_PLAYBACK_BUFFER),
|
||||
LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM),
|
||||
LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER),
|
||||
LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM),
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER),
|
||||
LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM),
|
||||
LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER),
|
||||
LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM),
|
||||
#endif
|
||||
LINE6_BIT(PAUSE_PLAYBACK),
|
||||
LINE6_BIT(PREPARED),
|
||||
|
||||
/* combined bit masks (by operation): */
|
||||
LINE6_BITS_PCM_ALSA_BUFFER =
|
||||
LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
|
||||
LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER,
|
||||
|
||||
LINE6_BITS_PCM_ALSA_STREAM =
|
||||
LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
|
||||
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM,
|
||||
|
||||
LINE6_BITS_PCM_MONITOR =
|
||||
LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER |
|
||||
LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM |
|
||||
LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER |
|
||||
LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
|
||||
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
LINE6_BITS_PCM_IMPULSE =
|
||||
LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
|
||||
LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
|
||||
LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
|
||||
LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM,
|
||||
#endif
|
||||
|
||||
/* combined bit masks (by direction): */
|
||||
LINE6_BITS_PLAYBACK_BUFFER =
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
|
||||
#endif
|
||||
LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
|
||||
LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER ,
|
||||
|
||||
LINE6_BITS_PLAYBACK_STREAM =
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
|
||||
#endif
|
||||
LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
|
||||
LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM ,
|
||||
|
||||
LINE6_BITS_CAPTURE_BUFFER =
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
|
||||
#endif
|
||||
LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER |
|
||||
LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER ,
|
||||
|
||||
LINE6_BITS_CAPTURE_STREAM =
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM |
|
||||
#endif
|
||||
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM |
|
||||
LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
|
||||
|
||||
LINE6_BITS_STREAM =
|
||||
LINE6_BITS_PLAYBACK_STREAM |
|
||||
LINE6_BITS_CAPTURE_STREAM
|
||||
};
|
||||
|
||||
struct line6_pcm_properties {
|
||||
struct snd_pcm_hardware snd_line6_playback_hw, snd_line6_capture_hw;
|
||||
struct snd_pcm_hw_constraint_ratdens snd_line6_rates;
|
||||
int bytes_per_frame;
|
||||
};
|
||||
|
||||
struct snd_line6_pcm {
|
||||
/**
|
||||
Pointer back to the Line6 driver data structure.
|
||||
*/
|
||||
struct usb_line6 *line6;
|
||||
|
||||
/**
|
||||
Properties.
|
||||
*/
|
||||
struct line6_pcm_properties *properties;
|
||||
|
||||
/**
|
||||
ALSA pcm stream
|
||||
*/
|
||||
struct snd_pcm *pcm;
|
||||
|
||||
/**
|
||||
URBs for audio playback.
|
||||
*/
|
||||
struct urb *urb_audio_out[LINE6_ISO_BUFFERS];
|
||||
|
||||
/**
|
||||
URBs for audio capture.
|
||||
*/
|
||||
struct urb *urb_audio_in[LINE6_ISO_BUFFERS];
|
||||
|
||||
/**
|
||||
Temporary buffer for playback.
|
||||
Since the packet size is not known in advance, this buffer is
|
||||
large enough to store maximum size packets.
|
||||
*/
|
||||
unsigned char *buffer_out;
|
||||
|
||||
/**
|
||||
Temporary buffer for capture.
|
||||
Since the packet size is not known in advance, this buffer is
|
||||
large enough to store maximum size packets.
|
||||
*/
|
||||
unsigned char *buffer_in;
|
||||
|
||||
/**
|
||||
Previously captured frame (for software monitoring).
|
||||
*/
|
||||
unsigned char *prev_fbuf;
|
||||
|
||||
/**
|
||||
Size of previously captured frame (for software monitoring).
|
||||
*/
|
||||
int prev_fsize;
|
||||
|
||||
/**
|
||||
Free frame position in the playback buffer.
|
||||
*/
|
||||
snd_pcm_uframes_t pos_out;
|
||||
|
||||
/**
|
||||
Count processed bytes for playback.
|
||||
This is modulo period size (to determine when a period is
|
||||
finished).
|
||||
*/
|
||||
unsigned bytes_out;
|
||||
|
||||
/**
|
||||
Counter to create desired playback sample rate.
|
||||
*/
|
||||
unsigned count_out;
|
||||
|
||||
/**
|
||||
Playback period size in bytes
|
||||
*/
|
||||
unsigned period_out;
|
||||
|
||||
/**
|
||||
Processed frame position in the playback buffer.
|
||||
The contents of the output ring buffer have been consumed by
|
||||
the USB subsystem (i.e., sent to the USB device) up to this
|
||||
position.
|
||||
*/
|
||||
snd_pcm_uframes_t pos_out_done;
|
||||
|
||||
/**
|
||||
Count processed bytes for capture.
|
||||
This is modulo period size (to determine when a period is
|
||||
finished).
|
||||
*/
|
||||
unsigned bytes_in;
|
||||
|
||||
/**
|
||||
Counter to create desired capture sample rate.
|
||||
*/
|
||||
unsigned count_in;
|
||||
|
||||
/**
|
||||
Capture period size in bytes
|
||||
*/
|
||||
unsigned period_in;
|
||||
|
||||
/**
|
||||
Processed frame position in the capture buffer.
|
||||
The contents of the output ring buffer have been consumed by
|
||||
the USB subsystem (i.e., sent to the USB device) up to this
|
||||
position.
|
||||
*/
|
||||
snd_pcm_uframes_t pos_in_done;
|
||||
|
||||
/**
|
||||
Bit mask of active playback URBs.
|
||||
*/
|
||||
unsigned long active_urb_out;
|
||||
|
||||
/**
|
||||
Maximum size of USB packet.
|
||||
*/
|
||||
int max_packet_size;
|
||||
|
||||
/**
|
||||
USB endpoint for listening to audio data.
|
||||
*/
|
||||
int ep_audio_read;
|
||||
|
||||
/**
|
||||
USB endpoint for writing audio data.
|
||||
*/
|
||||
int ep_audio_write;
|
||||
|
||||
/**
|
||||
Bit mask of active capture URBs.
|
||||
*/
|
||||
unsigned long active_urb_in;
|
||||
|
||||
/**
|
||||
Bit mask of playback URBs currently being unlinked.
|
||||
*/
|
||||
unsigned long unlink_urb_out;
|
||||
|
||||
/**
|
||||
Bit mask of capture URBs currently being unlinked.
|
||||
*/
|
||||
unsigned long unlink_urb_in;
|
||||
|
||||
/**
|
||||
Spin lock to protect updates of the playback buffer positions (not
|
||||
contents!)
|
||||
*/
|
||||
spinlock_t lock_audio_out;
|
||||
|
||||
/**
|
||||
Spin lock to protect updates of the capture buffer positions (not
|
||||
contents!)
|
||||
*/
|
||||
spinlock_t lock_audio_in;
|
||||
|
||||
/**
|
||||
Spin lock to protect trigger.
|
||||
*/
|
||||
spinlock_t lock_trigger;
|
||||
|
||||
/**
|
||||
PCM playback volume (left and right).
|
||||
*/
|
||||
int volume_playback[2];
|
||||
|
||||
/**
|
||||
PCM monitor volume.
|
||||
*/
|
||||
int volume_monitor;
|
||||
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
/**
|
||||
Volume of impulse response test signal (if zero, test is disabled).
|
||||
*/
|
||||
int impulse_volume;
|
||||
|
||||
/**
|
||||
Period of impulse response test signal.
|
||||
*/
|
||||
int impulse_period;
|
||||
|
||||
/**
|
||||
Counter for impulse response test signal.
|
||||
*/
|
||||
int impulse_count;
|
||||
#endif
|
||||
|
||||
/**
|
||||
Several status bits (see LINE6_BIT_*).
|
||||
*/
|
||||
unsigned long flags;
|
||||
|
||||
int last_frame_in, last_frame_out;
|
||||
};
|
||||
|
||||
extern int line6_init_pcm(struct usb_line6 *line6,
|
||||
struct line6_pcm_properties *properties);
|
||||
extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd);
|
||||
extern int snd_line6_prepare(struct snd_pcm_substream *substream);
|
||||
extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm);
|
||||
extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels);
|
||||
extern int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels);
|
||||
|
||||
#endif
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef POD_H
|
||||
#define POD_H
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
|
||||
#include "driver.h"
|
||||
|
||||
/*
|
||||
PODxt Live interfaces
|
||||
*/
|
||||
#define PODXTLIVE_INTERFACE_POD 0
|
||||
#define PODXTLIVE_INTERFACE_VARIAX 1
|
||||
|
||||
/*
|
||||
Locate name in binary program dump
|
||||
*/
|
||||
#define POD_NAME_OFFSET 0
|
||||
#define POD_NAME_LENGTH 16
|
||||
|
||||
/*
|
||||
Other constants
|
||||
*/
|
||||
#define POD_CONTROL_SIZE 0x80
|
||||
#define POD_BUFSIZE_DUMPREQ 7
|
||||
#define POD_STARTUP_DELAY 1000
|
||||
|
||||
/*
|
||||
Stages of POD startup procedure
|
||||
*/
|
||||
enum {
|
||||
POD_STARTUP_INIT = 1,
|
||||
POD_STARTUP_VERSIONREQ,
|
||||
POD_STARTUP_WORKQUEUE,
|
||||
POD_STARTUP_SETUP,
|
||||
POD_STARTUP_LAST = POD_STARTUP_SETUP - 1
|
||||
};
|
||||
|
||||
struct usb_line6_pod {
|
||||
/**
|
||||
Generic Line6 USB data.
|
||||
*/
|
||||
struct usb_line6 line6;
|
||||
|
||||
/**
|
||||
Instrument monitor level.
|
||||
*/
|
||||
int monitor_level;
|
||||
|
||||
/**
|
||||
Timer for device initializaton.
|
||||
*/
|
||||
struct timer_list startup_timer;
|
||||
|
||||
/**
|
||||
Work handler for device initializaton.
|
||||
*/
|
||||
struct work_struct startup_work;
|
||||
|
||||
/**
|
||||
Current progress in startup procedure.
|
||||
*/
|
||||
int startup_progress;
|
||||
|
||||
/**
|
||||
Serial number of device.
|
||||
*/
|
||||
int serial_number;
|
||||
|
||||
/**
|
||||
Firmware version (x 100).
|
||||
*/
|
||||
int firmware_version;
|
||||
|
||||
/**
|
||||
Device ID.
|
||||
*/
|
||||
int device_id;
|
||||
};
|
||||
|
||||
extern void line6_pod_disconnect(struct usb_interface *interface);
|
||||
extern int line6_pod_init(struct usb_interface *interface,
|
||||
struct usb_line6_pod *pod);
|
||||
extern void line6_pod_process_message(struct usb_line6_pod *pod);
|
||||
extern void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
|
||||
u8 value);
|
||||
|
||||
#endif
|
|
@ -1,154 +0,0 @@
|
|||
/*
|
||||
* Line6 Pod HD
|
||||
*
|
||||
* Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
|
||||
#include "audio.h"
|
||||
#include "driver.h"
|
||||
#include "pcm.h"
|
||||
#include "podhd.h"
|
||||
|
||||
#define PODHD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */
|
||||
|
||||
static struct snd_ratden podhd_ratden = {
|
||||
.num_min = 48000,
|
||||
.num_max = 48000,
|
||||
.num_step = 1,
|
||||
.den = 1,
|
||||
};
|
||||
|
||||
static struct line6_pcm_properties podhd_pcm_properties = {
|
||||
.snd_line6_playback_hw = {
|
||||
.info = (SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
#ifdef CONFIG_PM
|
||||
SNDRV_PCM_INFO_RESUME |
|
||||
#endif
|
||||
SNDRV_PCM_INFO_SYNC_START),
|
||||
.formats = SNDRV_PCM_FMTBIT_S24_3LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.rate_min = 48000,
|
||||
.rate_max = 48000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.buffer_bytes_max = 60000,
|
||||
.period_bytes_min = 64,
|
||||
.period_bytes_max = 8192,
|
||||
.periods_min = 1,
|
||||
.periods_max = 1024},
|
||||
.snd_line6_capture_hw = {
|
||||
.info = (SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
#ifdef CONFIG_PM
|
||||
SNDRV_PCM_INFO_RESUME |
|
||||
#endif
|
||||
SNDRV_PCM_INFO_SYNC_START),
|
||||
.formats = SNDRV_PCM_FMTBIT_S24_3LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.rate_min = 48000,
|
||||
.rate_max = 48000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.buffer_bytes_max = 60000,
|
||||
.period_bytes_min = 64,
|
||||
.period_bytes_max = 8192,
|
||||
.periods_min = 1,
|
||||
.periods_max = 1024},
|
||||
.snd_line6_rates = {
|
||||
.nrats = 1,
|
||||
.rats = &podhd_ratden},
|
||||
.bytes_per_frame = PODHD_BYTES_PER_FRAME
|
||||
};
|
||||
|
||||
/*
|
||||
POD HD destructor.
|
||||
*/
|
||||
static void podhd_destruct(struct usb_interface *interface)
|
||||
{
|
||||
struct usb_line6_podhd *podhd = usb_get_intfdata(interface);
|
||||
|
||||
if (podhd == NULL)
|
||||
return;
|
||||
line6_cleanup_audio(&podhd->line6);
|
||||
}
|
||||
|
||||
/*
|
||||
Try to init POD HD device.
|
||||
*/
|
||||
static int podhd_try_init(struct usb_interface *interface,
|
||||
struct usb_line6_podhd *podhd)
|
||||
{
|
||||
int err;
|
||||
struct usb_line6 *line6 = &podhd->line6;
|
||||
|
||||
if ((interface == NULL) || (podhd == NULL))
|
||||
return -ENODEV;
|
||||
|
||||
/* initialize audio system: */
|
||||
err = line6_init_audio(line6);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* initialize MIDI subsystem: */
|
||||
err = line6_init_midi(line6);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* initialize PCM subsystem: */
|
||||
err = line6_init_pcm(line6, &podhd_pcm_properties);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* register USB audio system: */
|
||||
err = line6_register_audio(line6);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
Init POD HD device (and clean up in case of failure).
|
||||
*/
|
||||
int line6_podhd_init(struct usb_interface *interface,
|
||||
struct usb_line6_podhd *podhd)
|
||||
{
|
||||
int err = podhd_try_init(interface, podhd);
|
||||
|
||||
if (err < 0)
|
||||
podhd_destruct(interface);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
POD HD device disconnected.
|
||||
*/
|
||||
void line6_podhd_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct usb_line6_podhd *podhd;
|
||||
|
||||
if (interface == NULL)
|
||||
return;
|
||||
podhd = usb_get_intfdata(interface);
|
||||
|
||||
if (podhd != NULL) {
|
||||
struct snd_line6_pcm *line6pcm = podhd->line6.line6pcm;
|
||||
|
||||
if (line6pcm != NULL)
|
||||
line6_pcm_disconnect(line6pcm);
|
||||
}
|
||||
|
||||
podhd_destruct(interface);
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* Line6 Pod HD
|
||||
*
|
||||
* Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PODHD_H
|
||||
#define PODHD_H
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include "driver.h"
|
||||
|
||||
struct usb_line6_podhd {
|
||||
/**
|
||||
Generic Line6 USB data.
|
||||
*/
|
||||
struct usb_line6 line6;
|
||||
};
|
||||
|
||||
extern void line6_podhd_disconnect(struct usb_interface *interface);
|
||||
extern int line6_podhd_init(struct usb_interface *interface,
|
||||
struct usb_line6_podhd *podhd);
|
||||
|
||||
#endif /* PODHD_H */
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef DRIVER_REVISION
|
||||
/* current subversion revision */
|
||||
#define DRIVER_REVISION " (904)"
|
||||
#endif
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TONEPORT_H
|
||||
#define TONEPORT_H
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <sound/core.h>
|
||||
|
||||
#include "driver.h"
|
||||
|
||||
struct usb_line6_toneport {
|
||||
/**
|
||||
Generic Line6 USB data.
|
||||
*/
|
||||
struct usb_line6 line6;
|
||||
|
||||
/**
|
||||
Source selector.
|
||||
*/
|
||||
int source;
|
||||
|
||||
/**
|
||||
Serial number of device.
|
||||
*/
|
||||
int serial_number;
|
||||
|
||||
/**
|
||||
Firmware version (x 100).
|
||||
*/
|
||||
int firmware_version;
|
||||
|
||||
/**
|
||||
Timer for delayed PCM startup.
|
||||
*/
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
||||
extern void line6_toneport_disconnect(struct usb_interface *interface);
|
||||
extern int line6_toneport_init(struct usb_interface *interface,
|
||||
struct usb_line6_toneport *toneport);
|
||||
extern void line6_toneport_reset_resume(struct usb_line6_toneport *toneport);
|
||||
|
||||
#endif
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
*
|
||||
* Copyright (C) 2005-2008 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef USBDEFS_H
|
||||
#define USBDEFS_H
|
||||
|
||||
#define LINE6_VENDOR_ID 0x0e41
|
||||
|
||||
#define USB_INTERVALS_PER_SECOND 1000
|
||||
|
||||
/*
|
||||
Device ids.
|
||||
*/
|
||||
#define LINE6_DEVID_BASSPODXT 0x4250
|
||||
#define LINE6_DEVID_BASSPODXTLIVE 0x4642
|
||||
#define LINE6_DEVID_BASSPODXTPRO 0x4252
|
||||
#define LINE6_DEVID_GUITARPORT 0x4750
|
||||
#define LINE6_DEVID_POCKETPOD 0x5051
|
||||
#define LINE6_DEVID_PODHD300 0x5057
|
||||
#define LINE6_DEVID_PODHD400 0x5058
|
||||
#define LINE6_DEVID_PODHD500 0x414D
|
||||
#define LINE6_DEVID_PODSTUDIO_GX 0x4153
|
||||
#define LINE6_DEVID_PODSTUDIO_UX1 0x4150
|
||||
#define LINE6_DEVID_PODSTUDIO_UX2 0x4151
|
||||
#define LINE6_DEVID_PODX3 0x414a
|
||||
#define LINE6_DEVID_PODX3LIVE 0x414b
|
||||
#define LINE6_DEVID_PODXT 0x5044
|
||||
#define LINE6_DEVID_PODXTLIVE 0x4650
|
||||
#define LINE6_DEVID_PODXTPRO 0x5050
|
||||
#define LINE6_DEVID_TONEPORT_GX 0x4147
|
||||
#define LINE6_DEVID_TONEPORT_UX1 0x4141
|
||||
#define LINE6_DEVID_TONEPORT_UX2 0x4142
|
||||
#define LINE6_DEVID_VARIAX 0x534d
|
||||
|
||||
#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x
|
||||
|
||||
enum {
|
||||
LINE6_INDEX_BASSPODXT,
|
||||
LINE6_INDEX_BASSPODXTLIVE,
|
||||
LINE6_INDEX_BASSPODXTPRO,
|
||||
LINE6_INDEX_GUITARPORT,
|
||||
LINE6_INDEX_POCKETPOD,
|
||||
LINE6_INDEX_PODHD300,
|
||||
LINE6_INDEX_PODHD400,
|
||||
LINE6_INDEX_PODHD500,
|
||||
LINE6_INDEX_PODSTUDIO_GX,
|
||||
LINE6_INDEX_PODSTUDIO_UX1,
|
||||
LINE6_INDEX_PODSTUDIO_UX2,
|
||||
LINE6_INDEX_PODX3,
|
||||
LINE6_INDEX_PODX3LIVE,
|
||||
LINE6_INDEX_PODXT,
|
||||
LINE6_INDEX_PODXTLIVE,
|
||||
LINE6_INDEX_PODXTPRO,
|
||||
LINE6_INDEX_TONEPORT_GX,
|
||||
LINE6_INDEX_TONEPORT_UX1,
|
||||
LINE6_INDEX_TONEPORT_UX2,
|
||||
LINE6_INDEX_VARIAX,
|
||||
|
||||
LINE6_BIT(BASSPODXT),
|
||||
LINE6_BIT(BASSPODXTLIVE),
|
||||
LINE6_BIT(BASSPODXTPRO),
|
||||
LINE6_BIT(GUITARPORT),
|
||||
LINE6_BIT(POCKETPOD),
|
||||
LINE6_BIT(PODHD300),
|
||||
LINE6_BIT(PODHD400),
|
||||
LINE6_BIT(PODHD500),
|
||||
LINE6_BIT(PODSTUDIO_GX),
|
||||
LINE6_BIT(PODSTUDIO_UX1),
|
||||
LINE6_BIT(PODSTUDIO_UX2),
|
||||
LINE6_BIT(PODX3),
|
||||
LINE6_BIT(PODX3LIVE),
|
||||
LINE6_BIT(PODXT),
|
||||
LINE6_BIT(PODXTLIVE),
|
||||
LINE6_BIT(PODXTPRO),
|
||||
LINE6_BIT(TONEPORT_GX),
|
||||
LINE6_BIT(TONEPORT_UX1),
|
||||
LINE6_BIT(TONEPORT_UX2),
|
||||
LINE6_BIT(VARIAX),
|
||||
|
||||
LINE6_BITS_PRO = LINE6_BIT_BASSPODXTPRO | LINE6_BIT_PODXTPRO,
|
||||
LINE6_BITS_LIVE = LINE6_BIT_BASSPODXTLIVE | LINE6_BIT_PODXTLIVE |
|
||||
LINE6_BIT_PODX3LIVE,
|
||||
LINE6_BITS_PODXTALL = LINE6_BIT_PODXT | LINE6_BIT_PODXTLIVE |
|
||||
LINE6_BIT_PODXTPRO,
|
||||
LINE6_BITS_PODX3ALL = LINE6_BIT_PODX3 | LINE6_BIT_PODX3LIVE,
|
||||
LINE6_BITS_PODHDALL = LINE6_BIT_PODHD300 |
|
||||
LINE6_BIT_PODHD400 |
|
||||
LINE6_BIT_PODHD500,
|
||||
LINE6_BITS_BASSPODXTALL = LINE6_BIT_BASSPODXT |
|
||||
LINE6_BIT_BASSPODXTLIVE |
|
||||
LINE6_BIT_BASSPODXTPRO
|
||||
};
|
||||
|
||||
/* device supports settings parameter via USB */
|
||||
#define LINE6_BIT_CONTROL (1 << 0)
|
||||
/* device supports PCM input/output via USB */
|
||||
#define LINE6_BIT_PCM (1 << 1)
|
||||
/* device support hardware monitoring */
|
||||
#define LINE6_BIT_HWMON (1 << 2)
|
||||
|
||||
#define LINE6_BIT_CTRL_PCM_HW (LINE6_BIT_CONTROL | \
|
||||
LINE6_BIT_PCM | \
|
||||
LINE6_BIT_HWMON)
|
||||
|
||||
#define LINE6_FALLBACK_INTERVAL 10
|
||||
#define LINE6_FALLBACK_MAXPACKETSIZE 16
|
||||
|
||||
#endif
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef VARIAX_H
|
||||
#define VARIAX_H
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/wait.h>
|
||||
#include <sound/core.h>
|
||||
|
||||
#include "driver.h"
|
||||
|
||||
#define VARIAX_STARTUP_DELAY1 1000
|
||||
#define VARIAX_STARTUP_DELAY3 100
|
||||
#define VARIAX_STARTUP_DELAY4 100
|
||||
|
||||
/*
|
||||
Stages of Variax startup procedure
|
||||
*/
|
||||
enum {
|
||||
VARIAX_STARTUP_INIT = 1,
|
||||
VARIAX_STARTUP_VERSIONREQ,
|
||||
VARIAX_STARTUP_WAIT,
|
||||
VARIAX_STARTUP_ACTIVATE,
|
||||
VARIAX_STARTUP_WORKQUEUE,
|
||||
VARIAX_STARTUP_SETUP,
|
||||
VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1
|
||||
};
|
||||
|
||||
struct usb_line6_variax {
|
||||
/**
|
||||
Generic Line6 USB data.
|
||||
*/
|
||||
struct usb_line6 line6;
|
||||
|
||||
/**
|
||||
Buffer for activation code.
|
||||
*/
|
||||
unsigned char *buffer_activate;
|
||||
|
||||
/**
|
||||
Handler for device initializaton.
|
||||
*/
|
||||
struct work_struct startup_work;
|
||||
|
||||
/**
|
||||
Timers for device initializaton.
|
||||
*/
|
||||
struct timer_list startup_timer1;
|
||||
struct timer_list startup_timer2;
|
||||
|
||||
/**
|
||||
Current progress in startup procedure.
|
||||
*/
|
||||
int startup_progress;
|
||||
};
|
||||
|
||||
extern void line6_variax_disconnect(struct usb_interface *interface);
|
||||
extern int line6_variax_init(struct usb_interface *interface,
|
||||
struct usb_line6_variax *variax);
|
||||
extern void line6_variax_process_message(struct usb_line6_variax *variax);
|
||||
|
||||
#endif
|
38
include/drm/i915_component.h
Normal file
38
include/drm/i915_component.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright © 2014 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _I915_COMPONENT_H_
|
||||
#define _I915_COMPONENT_H_
|
||||
|
||||
struct i915_audio_component {
|
||||
struct device *dev;
|
||||
|
||||
const struct i915_audio_component_ops {
|
||||
struct module *owner;
|
||||
void (*get_power)(struct device *);
|
||||
void (*put_power)(struct device *);
|
||||
int (*get_cdclk_freq)(struct device *);
|
||||
} *ops;
|
||||
};
|
||||
|
||||
#endif /* _I915_COMPONENT_H_ */
|
|
@ -1,37 +0,0 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2013 Intel Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef _I915_POWERWELL_H_
|
||||
#define _I915_POWERWELL_H_
|
||||
|
||||
/* For use by hda_i915 driver */
|
||||
extern int i915_request_power_well(void);
|
||||
extern int i915_release_power_well(void);
|
||||
extern int i915_get_cdclk_freq(void);
|
||||
|
||||
#endif /* _I915_POWERWELL_H_ */
|
8
include/dt-bindings/sound/samsung-i2s.h
Normal file
8
include/dt-bindings/sound/samsung-i2s.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef _DT_BINDINGS_SAMSUNG_I2S_H
|
||||
#define _DT_BINDINGS_SAMSUNG_I2S_H
|
||||
|
||||
#define CLK_I2S_CDCLK 0
|
||||
#define CLK_I2S_RCLK_SRC 1
|
||||
#define CLK_I2S_RCLK_PSR 2
|
||||
|
||||
#endif /* _DT_BINDINGS_SAMSUNG_I2S_H */
|
|
@ -170,10 +170,9 @@ extern int snd_ad1816a_create(struct snd_card *card, unsigned long port,
|
|||
int irq, int dma1, int dma2,
|
||||
struct snd_ad1816a *chip);
|
||||
|
||||
extern int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm);
|
||||
extern int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device);
|
||||
extern int snd_ad1816a_mixer(struct snd_ad1816a *chip);
|
||||
extern int snd_ad1816a_timer(struct snd_ad1816a *chip, int device,
|
||||
struct snd_timer **rtimer);
|
||||
extern int snd_ad1816a_timer(struct snd_ad1816a *chip, int device);
|
||||
#ifdef CONFIG_PM
|
||||
extern void snd_ad1816a_suspend(struct snd_ad1816a *chip);
|
||||
extern void snd_ad1816a_resume(struct snd_ad1816a *chip);
|
||||
|
|
|
@ -287,6 +287,7 @@ struct ak4113 {
|
|||
ak4113_read_t *read;
|
||||
void *private_data;
|
||||
atomic_t wq_processing;
|
||||
struct mutex reinit_mutex;
|
||||
spinlock_t lock;
|
||||
unsigned char regmap[AK4113_WRITABLE_REGS];
|
||||
struct snd_kcontrol *kctls[AK4113_CONTROLS];
|
||||
|
@ -317,5 +318,13 @@ int snd_ak4113_build(struct ak4113 *ak4113,
|
|||
int snd_ak4113_external_rate(struct ak4113 *ak4113);
|
||||
int snd_ak4113_check_rate_and_errors(struct ak4113 *ak4113, unsigned int flags);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
void snd_ak4113_suspend(struct ak4113 *chip);
|
||||
void snd_ak4113_resume(struct ak4113 *chip);
|
||||
#else
|
||||
static inline void snd_ak4113_suspend(struct ak4113 *chip) {}
|
||||
static inline void snd_ak4113_resume(struct ak4113 *chip) {}
|
||||
#endif
|
||||
|
||||
#endif /* __SOUND_AK4113_H */
|
||||
|
||||
|
|
|
@ -169,6 +169,7 @@ struct ak4114 {
|
|||
ak4114_read_t * read;
|
||||
void * private_data;
|
||||
atomic_t wq_processing;
|
||||
struct mutex reinit_mutex;
|
||||
spinlock_t lock;
|
||||
unsigned char regmap[6];
|
||||
unsigned char txcsb[5];
|
||||
|
@ -199,5 +200,13 @@ int snd_ak4114_build(struct ak4114 *ak4114,
|
|||
int snd_ak4114_external_rate(struct ak4114 *ak4114);
|
||||
int snd_ak4114_check_rate_and_errors(struct ak4114 *ak4114, unsigned int flags);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
void snd_ak4114_suspend(struct ak4114 *chip);
|
||||
void snd_ak4114_resume(struct ak4114 *chip);
|
||||
#else
|
||||
static inline void snd_ak4114_suspend(struct ak4114 *chip) {}
|
||||
static inline void snd_ak4114_resume(struct ak4114 *chip) {}
|
||||
#endif
|
||||
|
||||
#endif /* __SOUND_AK4114_H */
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/compress_offload.h>
|
||||
#include <sound/asound.h>
|
||||
#include <sound/pcm.h>
|
||||
|
@ -134,7 +135,7 @@ struct snd_compr_ops {
|
|||
/**
|
||||
* struct snd_compr: Compressed device
|
||||
* @name: DSP device name
|
||||
* @dev: Device pointer
|
||||
* @dev: associated device instance
|
||||
* @ops: pointer to DSP callbacks
|
||||
* @private_data: pointer to DSP pvt data
|
||||
* @card: sound card pointer
|
||||
|
@ -144,7 +145,7 @@ struct snd_compr_ops {
|
|||
*/
|
||||
struct snd_compr {
|
||||
const char *name;
|
||||
struct device *dev;
|
||||
struct device dev;
|
||||
struct snd_compr_ops *ops;
|
||||
void *private_data;
|
||||
struct snd_card *card;
|
||||
|
|
|
@ -93,12 +93,17 @@ struct snd_kctl_event {
|
|||
|
||||
struct pid;
|
||||
|
||||
enum {
|
||||
SND_CTL_SUBDEV_PCM,
|
||||
SND_CTL_SUBDEV_RAWMIDI,
|
||||
SND_CTL_SUBDEV_ITEMS,
|
||||
};
|
||||
|
||||
struct snd_ctl_file {
|
||||
struct list_head list; /* list of all control files */
|
||||
struct snd_card *card;
|
||||
struct pid *pid;
|
||||
int prefer_pcm_subdevice;
|
||||
int prefer_rawmidi_subdevice;
|
||||
int preferred_subdevice[SND_CTL_SUBDEV_ITEMS];
|
||||
wait_queue_head_t change_sleep;
|
||||
spinlock_t read_lock;
|
||||
struct fasync_struct *fasync;
|
||||
|
@ -138,6 +143,8 @@ int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn);
|
|||
#define snd_ctl_unregister_ioctl_compat(fcn)
|
||||
#endif
|
||||
|
||||
int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type);
|
||||
|
||||
static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
|
||||
{
|
||||
return id->numid - kctl->id.numid;
|
||||
|
|
|
@ -109,6 +109,7 @@ struct snd_card {
|
|||
private data */
|
||||
struct list_head devices; /* devices */
|
||||
|
||||
struct device ctl_dev; /* control device */
|
||||
unsigned int last_numid; /* last used numeric ID */
|
||||
struct rw_semaphore controls_rwsem; /* controls list lock */
|
||||
rwlock_t ctl_files_rwlock; /* ctl_files list lock */
|
||||
|
@ -131,6 +132,7 @@ struct snd_card {
|
|||
struct completion *release_completion;
|
||||
struct device *dev; /* device assigned to this card */
|
||||
struct device card_dev; /* cardX object for sysfs */
|
||||
const struct attribute_group *dev_groups[4]; /* assigned sysfs attr */
|
||||
bool registered; /* card_dev is registered? */
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
@ -206,43 +208,13 @@ extern struct class *sound_class;
|
|||
|
||||
void snd_request_card(int card);
|
||||
|
||||
int snd_register_device_for_dev(int type, struct snd_card *card,
|
||||
int dev,
|
||||
const struct file_operations *f_ops,
|
||||
void *private_data,
|
||||
const char *name,
|
||||
struct device *device);
|
||||
void snd_device_initialize(struct device *dev, struct snd_card *card);
|
||||
|
||||
/**
|
||||
* snd_register_device - Register the ALSA device file for the card
|
||||
* @type: the device type, SNDRV_DEVICE_TYPE_XXX
|
||||
* @card: the card instance
|
||||
* @dev: the device index
|
||||
* @f_ops: the file operations
|
||||
* @private_data: user pointer for f_ops->open()
|
||||
* @name: the device file name
|
||||
*
|
||||
* Registers an ALSA device file for the given card.
|
||||
* The operators have to be set in reg parameter.
|
||||
*
|
||||
* This function uses the card's device pointer to link to the
|
||||
* correct &struct device.
|
||||
*
|
||||
* Return: Zero if successful, or a negative error code on failure.
|
||||
*/
|
||||
static inline int snd_register_device(int type, struct snd_card *card, int dev,
|
||||
const struct file_operations *f_ops,
|
||||
void *private_data,
|
||||
const char *name)
|
||||
{
|
||||
return snd_register_device_for_dev(type, card, dev, f_ops,
|
||||
private_data, name,
|
||||
snd_card_get_device_link(card));
|
||||
}
|
||||
|
||||
int snd_unregister_device(int type, struct snd_card *card, int dev);
|
||||
int snd_register_device(int type, struct snd_card *card, int dev,
|
||||
const struct file_operations *f_ops,
|
||||
void *private_data, struct device *device);
|
||||
int snd_unregister_device(struct device *dev);
|
||||
void *snd_lookup_minor_data(unsigned int minor, int type);
|
||||
struct device *snd_get_device(int type, struct snd_card *card, int dev);
|
||||
|
||||
#ifdef CONFIG_SND_OSSEMUL
|
||||
int snd_register_oss_device(int type, struct snd_card *card, int dev,
|
||||
|
@ -291,6 +263,8 @@ void snd_card_set_id(struct snd_card *card, const char *id);
|
|||
int snd_card_register(struct snd_card *card);
|
||||
int snd_card_info_init(void);
|
||||
int snd_card_info_done(void);
|
||||
int snd_card_add_dev_attr(struct snd_card *card,
|
||||
const struct attribute_group *group);
|
||||
int snd_component_add(struct snd_card *card, const char *component);
|
||||
int snd_card_file_add(struct snd_card *card, struct file *file);
|
||||
int snd_card_file_remove(struct snd_card *card, struct file *file);
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <uapi/sound/emu10k1.h>
|
||||
|
||||
/* ------------------- DEFINES -------------------- */
|
||||
|
@ -1809,17 +1809,17 @@ int snd_emu10k1_create(struct snd_card *card,
|
|||
uint subsystem,
|
||||
struct snd_emu10k1 ** remu);
|
||||
|
||||
int snd_emu10k1_pcm(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
|
||||
int snd_emu10k1_pcm_mic(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
|
||||
int snd_emu10k1_pcm_efx(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
|
||||
int snd_p16v_pcm(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
|
||||
int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device);
|
||||
int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device);
|
||||
int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device);
|
||||
int snd_p16v_pcm(struct snd_emu10k1 *emu, int device);
|
||||
int snd_p16v_free(struct snd_emu10k1 * emu);
|
||||
int snd_p16v_mixer(struct snd_emu10k1 * emu);
|
||||
int snd_emu10k1_pcm_multi(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
|
||||
int snd_emu10k1_fx8010_pcm(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
|
||||
int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device);
|
||||
int snd_emu10k1_fx8010_pcm(struct snd_emu10k1 *emu, int device);
|
||||
int snd_emu10k1_mixer(struct snd_emu10k1 * emu, int pcm_device, int multi_device);
|
||||
int snd_emu10k1_timer(struct snd_emu10k1 * emu, int device);
|
||||
int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct snd_hwdep ** rhwdep);
|
||||
int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device);
|
||||
|
||||
irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id);
|
||||
|
||||
|
|
|
@ -115,8 +115,7 @@ int snd_es1688_create(struct snd_card *card,
|
|||
int mpu_irq,
|
||||
int dma8,
|
||||
unsigned short hardware);
|
||||
int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device,
|
||||
struct snd_pcm **rpcm);
|
||||
int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device);
|
||||
int snd_es1688_mixer(struct snd_card *card, struct snd_es1688 *chip);
|
||||
int snd_es1688_reset(struct snd_es1688 *chip);
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include <sound/timer.h>
|
||||
#include <sound/seq_midi_emul.h>
|
||||
#include <sound/seq_device.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
/* IO ports */
|
||||
|
||||
|
@ -591,7 +591,7 @@ int snd_gf1_new_mixer(struct snd_gus_card * gus);
|
|||
|
||||
/* gus_pcm.c */
|
||||
|
||||
int snd_gf1_pcm_new(struct snd_gus_card * gus, int pcm_dev, int control_index, struct snd_pcm ** rpcm);
|
||||
int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index);
|
||||
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
extern void snd_gf1_print_voice_registers(struct snd_gus_card * gus);
|
||||
|
@ -620,7 +620,7 @@ void snd_gus_irq_profile_init(struct snd_gus_card *gus);
|
|||
|
||||
/* gus_uart.c */
|
||||
|
||||
int snd_gf1_rawmidi_new(struct snd_gus_card * gus, int device, struct snd_rawmidi **rrawmidi);
|
||||
int snd_gf1_rawmidi_new(struct snd_gus_card *gus, int device);
|
||||
|
||||
/* gus_dram.c */
|
||||
int snd_gus_dram_write(struct snd_gus_card *gus, char __user *ptr,
|
||||
|
|
|
@ -68,8 +68,7 @@ struct snd_hwdep {
|
|||
wait_queue_head_t open_wait;
|
||||
void *private_data;
|
||||
void (*private_free) (struct snd_hwdep *hwdep);
|
||||
struct device *dev;
|
||||
const struct attribute_group **groups;
|
||||
struct device dev;
|
||||
|
||||
struct mutex open_mutex;
|
||||
int used; /* reference counter */
|
||||
|
|
|
@ -94,9 +94,6 @@ struct snd_pcm_ops {
|
|||
#define SNDRV_PCM_DEVICES 8
|
||||
#endif
|
||||
|
||||
#define SNDRV_PCM_IOCTL1_FALSE ((void *)0)
|
||||
#define SNDRV_PCM_IOCTL1_TRUE ((void *)1)
|
||||
|
||||
#define SNDRV_PCM_IOCTL1_RESET 0
|
||||
#define SNDRV_PCM_IOCTL1_INFO 1
|
||||
#define SNDRV_PCM_IOCTL1_CHANNEL_INFO 2
|
||||
|
@ -109,6 +106,7 @@ struct snd_pcm_ops {
|
|||
#define SNDRV_PCM_TRIGGER_PAUSE_RELEASE 4
|
||||
#define SNDRV_PCM_TRIGGER_SUSPEND 5
|
||||
#define SNDRV_PCM_TRIGGER_RESUME 6
|
||||
#define SNDRV_PCM_TRIGGER_DRAIN 7
|
||||
|
||||
#define SNDRV_PCM_POS_XRUN ((snd_pcm_uframes_t)-1)
|
||||
|
||||
|
@ -275,12 +273,19 @@ struct snd_pcm_hw_constraint_list {
|
|||
unsigned int mask;
|
||||
};
|
||||
|
||||
struct snd_pcm_hw_constraint_ranges {
|
||||
unsigned int count;
|
||||
const struct snd_interval *ranges;
|
||||
unsigned int mask;
|
||||
};
|
||||
|
||||
struct snd_pcm_hwptr_log;
|
||||
|
||||
struct snd_pcm_runtime {
|
||||
/* -- Status -- */
|
||||
struct snd_pcm_substream *trigger_master;
|
||||
struct timespec trigger_tstamp; /* trigger timestamp */
|
||||
bool trigger_tstamp_latched; /* trigger timestamp latched in low-level driver/hardware */
|
||||
int overrange;
|
||||
snd_pcm_uframes_t avail_max;
|
||||
snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */
|
||||
|
@ -449,6 +454,7 @@ struct snd_pcm_str {
|
|||
#endif
|
||||
#endif
|
||||
struct snd_kcontrol *chmap_kctl; /* channel-mapping controls */
|
||||
struct device dev;
|
||||
};
|
||||
|
||||
struct snd_pcm {
|
||||
|
@ -465,7 +471,6 @@ struct snd_pcm {
|
|||
wait_queue_head_t open_wait;
|
||||
void *private_data;
|
||||
void (*private_free) (struct snd_pcm *pcm);
|
||||
struct device *dev; /* actual hw device this belongs to */
|
||||
bool internal; /* pcm is for internal use only */
|
||||
bool nonatomic; /* whole PCM operations are in non-atomic context */
|
||||
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
|
||||
|
@ -520,7 +525,6 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream);
|
|||
int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, struct file *file,
|
||||
struct snd_pcm_substream **rsubstream);
|
||||
void snd_pcm_detach_substream(struct snd_pcm_substream *substream);
|
||||
void snd_pcm_vma_notify_data(void *client, void *data);
|
||||
int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area);
|
||||
|
||||
|
||||
|
@ -910,6 +914,8 @@ void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
|
|||
const struct snd_interval *b, struct snd_interval *c);
|
||||
int snd_interval_list(struct snd_interval *i, unsigned int count,
|
||||
const unsigned int *list, unsigned int mask);
|
||||
int snd_interval_ranges(struct snd_interval *i, unsigned int count,
|
||||
const struct snd_interval *list, unsigned int mask);
|
||||
int snd_interval_ratnum(struct snd_interval *i,
|
||||
unsigned int rats_count, struct snd_ratnum *rats,
|
||||
unsigned int *nump, unsigned int *denp);
|
||||
|
@ -934,6 +940,10 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,
|
|||
unsigned int cond,
|
||||
snd_pcm_hw_param_t var,
|
||||
const struct snd_pcm_hw_constraint_list *l);
|
||||
int snd_pcm_hw_constraint_ranges(struct snd_pcm_runtime *runtime,
|
||||
unsigned int cond,
|
||||
snd_pcm_hw_param_t var,
|
||||
const struct snd_pcm_hw_constraint_ranges *r);
|
||||
int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime,
|
||||
unsigned int cond,
|
||||
snd_pcm_hw_param_t var,
|
||||
|
@ -986,21 +996,15 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format); /* in bits */
|
|||
ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples);
|
||||
const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format);
|
||||
int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int frames);
|
||||
snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsigned, int big_endian);
|
||||
|
||||
void snd_pcm_set_ops(struct snd_pcm * pcm, int direction,
|
||||
const struct snd_pcm_ops *ops);
|
||||
void snd_pcm_set_sync(struct snd_pcm_substream *substream);
|
||||
int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream);
|
||||
int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
|
||||
unsigned int cmd, void *arg);
|
||||
int snd_pcm_update_state(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_runtime *runtime);
|
||||
int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream);
|
||||
int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream);
|
||||
int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream);
|
||||
int snd_pcm_playback_xrun_asap(struct snd_pcm_substream *substream);
|
||||
int snd_pcm_capture_xrun_asap(struct snd_pcm_substream *substream);
|
||||
void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr);
|
||||
void snd_pcm_period_elapsed(struct snd_pcm_substream *substream);
|
||||
snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream,
|
||||
|
|
|
@ -38,31 +38,6 @@ int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
|
|||
#define MASK_OFS(i) ((i) >> 5)
|
||||
#define MASK_BIT(i) (1U << ((i) & 31))
|
||||
|
||||
static inline unsigned int ld2(u_int32_t v)
|
||||
{
|
||||
unsigned r = 0;
|
||||
|
||||
if (v >= 0x10000) {
|
||||
v >>= 16;
|
||||
r += 16;
|
||||
}
|
||||
if (v >= 0x100) {
|
||||
v >>= 8;
|
||||
r += 8;
|
||||
}
|
||||
if (v >= 0x10) {
|
||||
v >>= 4;
|
||||
r += 4;
|
||||
}
|
||||
if (v >= 4) {
|
||||
v >>= 2;
|
||||
r += 2;
|
||||
}
|
||||
if (v >= 2)
|
||||
r++;
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline size_t snd_mask_sizeof(void)
|
||||
{
|
||||
return sizeof(struct snd_mask);
|
||||
|
@ -92,7 +67,7 @@ static inline unsigned int snd_mask_min(const struct snd_mask *mask)
|
|||
int i;
|
||||
for (i = 0; i < SNDRV_MASK_SIZE; i++) {
|
||||
if (mask->bits[i])
|
||||
return ffs(mask->bits[i]) - 1 + (i << 5);
|
||||
return __ffs(mask->bits[i]) + (i << 5);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -102,7 +77,7 @@ static inline unsigned int snd_mask_max(const struct snd_mask *mask)
|
|||
int i;
|
||||
for (i = SNDRV_MASK_SIZE - 1; i >= 0; i--) {
|
||||
if (mask->bits[i])
|
||||
return ld2(mask->bits[i]) + (i << 5);
|
||||
return __fls(mask->bits[i]) + (i << 5);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -325,43 +300,68 @@ static inline int snd_interval_eq(const struct snd_interval *i1, const struct sn
|
|||
i1->max == i2->max && i1->openmax == i2->openmax;
|
||||
}
|
||||
|
||||
static inline unsigned int add(unsigned int a, unsigned int b)
|
||||
/**
|
||||
* params_access - get the access type from the hw params
|
||||
* @p: hw params
|
||||
*/
|
||||
static inline snd_pcm_access_t params_access(const struct snd_pcm_hw_params *p)
|
||||
{
|
||||
if (a >= UINT_MAX - b)
|
||||
return UINT_MAX;
|
||||
return a + b;
|
||||
return (__force snd_pcm_access_t)snd_mask_min(hw_param_mask_c(p,
|
||||
SNDRV_PCM_HW_PARAM_ACCESS));
|
||||
}
|
||||
|
||||
static inline unsigned int sub(unsigned int a, unsigned int b)
|
||||
/**
|
||||
* params_format - get the sample format from the hw params
|
||||
* @p: hw params
|
||||
*/
|
||||
static inline snd_pcm_format_t params_format(const struct snd_pcm_hw_params *p)
|
||||
{
|
||||
if (a > b)
|
||||
return a - b;
|
||||
return 0;
|
||||
return (__force snd_pcm_format_t)snd_mask_min(hw_param_mask_c(p,
|
||||
SNDRV_PCM_HW_PARAM_FORMAT));
|
||||
}
|
||||
|
||||
#define params_access(p) ((__force snd_pcm_access_t)\
|
||||
snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_ACCESS)))
|
||||
#define params_format(p) ((__force snd_pcm_format_t)\
|
||||
snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_FORMAT)))
|
||||
#define params_subformat(p) \
|
||||
snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_SUBFORMAT))
|
||||
/**
|
||||
* params_subformat - get the sample subformat from the hw params
|
||||
* @p: hw params
|
||||
*/
|
||||
static inline snd_pcm_subformat_t
|
||||
params_subformat(const struct snd_pcm_hw_params *p)
|
||||
{
|
||||
return (__force snd_pcm_subformat_t)snd_mask_min(hw_param_mask_c(p,
|
||||
SNDRV_PCM_HW_PARAM_SUBFORMAT));
|
||||
}
|
||||
|
||||
/**
|
||||
* params_period_bytes - get the period size (in bytes) from the hw params
|
||||
* @p: hw params
|
||||
*/
|
||||
static inline unsigned int
|
||||
params_period_bytes(const struct snd_pcm_hw_params *p)
|
||||
{
|
||||
return (params_period_size(p) *
|
||||
snd_pcm_format_physical_width(params_format(p)) *
|
||||
params_channels(p)) / 8;
|
||||
return hw_param_interval_c(p, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)->min;
|
||||
}
|
||||
|
||||
static inline int
|
||||
params_width(const struct snd_pcm_hw_params *p)
|
||||
/**
|
||||
* params_width - get the number of bits of the sample format from the hw params
|
||||
* @p: hw params
|
||||
*
|
||||
* This function returns the number of bits per sample that the selected sample
|
||||
* format of the hw params has.
|
||||
*/
|
||||
static inline int params_width(const struct snd_pcm_hw_params *p)
|
||||
{
|
||||
return snd_pcm_format_width(params_format(p));
|
||||
}
|
||||
|
||||
static inline int
|
||||
params_physical_width(const struct snd_pcm_hw_params *p)
|
||||
/*
|
||||
* params_physical_width - get the storage size of the sample format from the hw params
|
||||
* @p: hw params
|
||||
*
|
||||
* This functions returns the number of bits per sample that the selected sample
|
||||
* format of the hw params takes up in memory. This will be equal or larger than
|
||||
* params_width().
|
||||
*/
|
||||
static inline int params_physical_width(const struct snd_pcm_hw_params *p)
|
||||
{
|
||||
return snd_pcm_format_physical_width(params_format(p));
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/wait.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
|
||||
#include <sound/seq_device.h>
|
||||
|
@ -139,7 +140,8 @@ struct snd_rawmidi {
|
|||
struct mutex open_mutex;
|
||||
wait_queue_head_t open_wait;
|
||||
|
||||
struct snd_info_entry *dev;
|
||||
struct device dev;
|
||||
|
||||
struct snd_info_entry *proc_entry;
|
||||
|
||||
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
|
||||
|
|
|
@ -55,6 +55,7 @@ struct rsnd_ssi_platform_info {
|
|||
struct rsnd_src_platform_info {
|
||||
u32 convert_rate; /* sampling rate convert */
|
||||
int dma_id; /* for Gen2 SCU */
|
||||
int irq;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -37,6 +37,9 @@ struct rt5677_platform_data {
|
|||
OFF, GPIO4, GPIO5 and GPIO6 respectively */
|
||||
unsigned int jd2_gpio;
|
||||
unsigned int jd3_gpio;
|
||||
|
||||
/* Set MICBIAS1 VDD 1v8 or 3v3 */
|
||||
bool micbias1_vdd_3v3;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <sound/pcm.h>
|
||||
#include <sound/rawmidi.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
enum sb_hw_type {
|
||||
SB_HW_AUTO,
|
||||
|
@ -308,7 +308,7 @@ void snd_sbmixer_resume(struct snd_sb *chip);
|
|||
#endif
|
||||
|
||||
/* sb8_init.c */
|
||||
int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm);
|
||||
int snd_sb8dsp_pcm(struct snd_sb *chip, int device);
|
||||
/* sb8.c */
|
||||
irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip);
|
||||
int snd_sb8_playback_open(struct snd_pcm_substream *substream);
|
||||
|
@ -317,10 +317,10 @@ int snd_sb8_playback_close(struct snd_pcm_substream *substream);
|
|||
int snd_sb8_capture_close(struct snd_pcm_substream *substream);
|
||||
/* midi8.c */
|
||||
irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb *chip);
|
||||
int snd_sb8dsp_midi(struct snd_sb *chip, int device, struct snd_rawmidi ** rrawmidi);
|
||||
int snd_sb8dsp_midi(struct snd_sb *chip, int device);
|
||||
|
||||
/* sb16_init.c */
|
||||
int snd_sb16dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm);
|
||||
int snd_sb16dsp_pcm(struct snd_sb *chip, int device);
|
||||
const struct snd_pcm_ops *snd_sb16dsp_get_pcm_ops(int direction);
|
||||
int snd_sb16dsp_configure(struct snd_sb *chip);
|
||||
/* sb16.c */
|
||||
|
|
|
@ -27,11 +27,8 @@
|
|||
typedef struct snd_seq_real_time snd_seq_real_time_t;
|
||||
typedef union snd_seq_timestamp snd_seq_timestamp_t;
|
||||
|
||||
/* maximum number of events dequeued per schedule interval */
|
||||
#define SNDRV_SEQ_MAX_DEQUEUE 50
|
||||
|
||||
/* maximum number of queues */
|
||||
#define SNDRV_SEQ_MAX_QUEUES 8
|
||||
#define SNDRV_SEQ_MAX_QUEUES 32
|
||||
|
||||
/* max number of concurrent clients */
|
||||
#define SNDRV_SEQ_MAX_CLIENTS 192
|
||||
|
@ -42,9 +39,6 @@ typedef union snd_seq_timestamp snd_seq_timestamp_t;
|
|||
/* max number of events in memory pool */
|
||||
#define SNDRV_SEQ_MAX_EVENTS 2000
|
||||
|
||||
/* default number of events in memory chunk */
|
||||
#define SNDRV_SEQ_DEFAULT_CHUNK_EVENTS 64
|
||||
|
||||
/* default number of events in memory pool */
|
||||
#define SNDRV_SEQ_DEFAULT_EVENTS 500
|
||||
|
||||
|
@ -70,7 +64,6 @@ struct snd_seq_port_callback {
|
|||
int (*unuse)(void *private_data, struct snd_seq_port_subscribe *info);
|
||||
int (*event_input)(struct snd_seq_event *ev, int direct, void *private_data, int atomic, int hop);
|
||||
void (*private_free)(void *private_data);
|
||||
unsigned int callback_all; /* call subscribe callbacks at each connection/disconnection */
|
||||
/*...*/
|
||||
};
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ struct asoc_simple_dai {
|
|||
unsigned int sysclk;
|
||||
int slots;
|
||||
int slot_width;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
struct asoc_simple_card_info {
|
||||
|
|
|
@ -405,7 +405,7 @@ int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
|
|||
struct snd_soc_dapm_update *update);
|
||||
|
||||
/* dapm sys fs - used by the core */
|
||||
int snd_soc_dapm_sys_add(struct device *dev);
|
||||
extern struct attribute *soc_dapm_dev_attrs[];
|
||||
void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
|
||||
struct dentry *parent);
|
||||
|
||||
|
@ -431,7 +431,6 @@ int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
|
|||
const char *pin);
|
||||
int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
|
||||
const char *pin);
|
||||
void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card);
|
||||
unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol);
|
||||
|
||||
/* Mostly internal - should not normally be used */
|
||||
|
@ -526,7 +525,6 @@ struct snd_soc_dapm_widget {
|
|||
enum snd_soc_dapm_type id;
|
||||
const char *name; /* widget name */
|
||||
const char *sname; /* stream name */
|
||||
struct snd_soc_codec *codec;
|
||||
struct list_head list;
|
||||
struct snd_soc_dapm_context *dapm;
|
||||
|
||||
|
|
|
@ -429,6 +429,9 @@ bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd);
|
|||
void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream);
|
||||
void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream);
|
||||
|
||||
int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
|
||||
unsigned int dai_fmt);
|
||||
|
||||
/* Utility functions to get clock rates from various things */
|
||||
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
|
||||
int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
|
||||
|
|
|
@ -24,12 +24,20 @@
|
|||
#define STA32X_THERMAL_RECOVERY_ENABLE 2
|
||||
|
||||
struct sta32x_platform_data {
|
||||
int output_conf;
|
||||
int ch1_output_mapping;
|
||||
int ch2_output_mapping;
|
||||
int ch3_output_mapping;
|
||||
int thermal_conf;
|
||||
u8 output_conf;
|
||||
u8 ch1_output_mapping;
|
||||
u8 ch2_output_mapping;
|
||||
u8 ch3_output_mapping;
|
||||
int needs_esd_watchdog;
|
||||
u8 drop_compensation_ns;
|
||||
unsigned int thermal_warning_recovery:1;
|
||||
unsigned int thermal_warning_adjustment:1;
|
||||
unsigned int fault_detect_recovery:1;
|
||||
unsigned int max_power_use_mpcc:1;
|
||||
unsigned int max_power_correction:1;
|
||||
unsigned int am_reduction_mode:1;
|
||||
unsigned int odd_pwm_speed_mode:1;
|
||||
unsigned int invalid_input_detect_mute:1;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_SND__STA32X_H */
|
||||
|
|
|
@ -154,8 +154,8 @@ int snd_wss_create(struct snd_card *card,
|
|||
unsigned short hardware,
|
||||
unsigned short hwshare,
|
||||
struct snd_wss **rchip);
|
||||
int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm);
|
||||
int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer);
|
||||
int snd_wss_pcm(struct snd_wss *chip, int device);
|
||||
int snd_wss_timer(struct snd_wss *chip, int device);
|
||||
int snd_wss_mixer(struct snd_wss *chip);
|
||||
|
||||
const struct snd_pcm_ops *snd_wss_get_pcm_ops(int direction);
|
||||
|
@ -167,7 +167,7 @@ int snd_cs4236_create(struct snd_card *card,
|
|||
unsigned short hardware,
|
||||
unsigned short hwshare,
|
||||
struct snd_wss **rchip);
|
||||
int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm);
|
||||
int snd_cs4236_pcm(struct snd_wss *chip, int device);
|
||||
int snd_cs4236_mixer(struct snd_wss *chip);
|
||||
|
||||
/*
|
||||
|
|
|
@ -268,6 +268,7 @@ typedef int __bitwise snd_pcm_subformat_t;
|
|||
#define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */
|
||||
#define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000 /* period wakeup can be disabled */
|
||||
#define SNDRV_PCM_INFO_HAS_WALL_CLOCK 0x01000000 /* has audio wall clock for audio/system time sync */
|
||||
#define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 /* internal kernel flag - trigger in drain */
|
||||
#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */
|
||||
|
||||
typedef int __bitwise snd_pcm_state_t;
|
||||
|
|
76
include/uapi/sound/usb_stream.h
Normal file
76
include/uapi/sound/usb_stream.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (C) 2007, 2008 Karsten Wiese <fzu@wemgehoertderstaat.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _UAPI__SOUND_USB_STREAM_H
|
||||
#define _UAPI__SOUND_USB_STREAM_H
|
||||
|
||||
#define USB_STREAM_INTERFACE_VERSION 2
|
||||
|
||||
#define SNDRV_USB_STREAM_IOCTL_SET_PARAMS \
|
||||
_IOW('H', 0x90, struct usb_stream_config)
|
||||
|
||||
struct usb_stream_packet {
|
||||
unsigned offset;
|
||||
unsigned length;
|
||||
};
|
||||
|
||||
|
||||
struct usb_stream_config {
|
||||
unsigned version;
|
||||
unsigned sample_rate;
|
||||
unsigned period_frames;
|
||||
unsigned frame_size;
|
||||
};
|
||||
|
||||
struct usb_stream {
|
||||
struct usb_stream_config cfg;
|
||||
unsigned read_size;
|
||||
unsigned write_size;
|
||||
|
||||
int period_size;
|
||||
|
||||
unsigned state;
|
||||
|
||||
int idle_insize;
|
||||
int idle_outsize;
|
||||
int sync_packet;
|
||||
unsigned insize_done;
|
||||
unsigned periods_done;
|
||||
unsigned periods_polled;
|
||||
|
||||
struct usb_stream_packet outpacket[2];
|
||||
unsigned inpackets;
|
||||
unsigned inpacket_head;
|
||||
unsigned inpacket_split;
|
||||
unsigned inpacket_split_at;
|
||||
unsigned next_inpacket_split;
|
||||
unsigned next_inpacket_split_at;
|
||||
struct usb_stream_packet inpacket[0];
|
||||
};
|
||||
|
||||
enum usb_stream_state {
|
||||
usb_stream_invalid,
|
||||
usb_stream_stopped,
|
||||
usb_stream_sync0,
|
||||
usb_stream_sync1,
|
||||
usb_stream_ready,
|
||||
usb_stream_running,
|
||||
usb_stream_xrun,
|
||||
};
|
||||
|
||||
#endif /* _UAPI__SOUND_USB_STREAM_H */
|
|
@ -9,8 +9,8 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/macio.h>
|
||||
#include <asm/pmac_feature.h>
|
||||
|
|
|
@ -74,10 +74,9 @@ static void i2sbus_release_dev(struct device *dev)
|
|||
int i;
|
||||
|
||||
i2sdev = container_of(dev, struct i2sbus_dev, sound.ofdev.dev);
|
||||
|
||||
if (i2sdev->intfregs) iounmap(i2sdev->intfregs);
|
||||
if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma);
|
||||
if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma);
|
||||
iounmap(i2sdev->intfregs);
|
||||
iounmap(i2sdev->out.dbdma);
|
||||
iounmap(i2sdev->in.dbdma);
|
||||
for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++)
|
||||
release_and_free_resource(i2sdev->allocated_resource[i]);
|
||||
free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring);
|
||||
|
@ -318,9 +317,9 @@ static int i2sbus_add_dev(struct macio_dev *macio,
|
|||
free_irq(dev->interrupts[i], dev);
|
||||
free_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring);
|
||||
free_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring);
|
||||
if (dev->intfregs) iounmap(dev->intfregs);
|
||||
if (dev->out.dbdma) iounmap(dev->out.dbdma);
|
||||
if (dev->in.dbdma) iounmap(dev->in.dbdma);
|
||||
iounmap(dev->intfregs);
|
||||
iounmap(dev->out.dbdma);
|
||||
iounmap(dev->in.dbdma);
|
||||
for (i=0;i<3;i++)
|
||||
release_and_free_resource(dev->allocated_resource[i]);
|
||||
mutex_destroy(&dev->lock);
|
||||
|
@ -381,10 +380,8 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state)
|
|||
|
||||
list_for_each_entry(i2sdev, &control->list, item) {
|
||||
/* Notify Alsa */
|
||||
if (i2sdev->sound.pcm) {
|
||||
/* Suspend PCM streams */
|
||||
snd_pcm_suspend_all(i2sdev->sound.pcm);
|
||||
}
|
||||
/* Suspend PCM streams */
|
||||
snd_pcm_suspend_all(i2sdev->sound.pcm);
|
||||
|
||||
/* Notify codecs */
|
||||
list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* GPL v2, can be found in COPYING.
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
|
@ -968,7 +968,6 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
|
|||
printk(KERN_DEBUG "i2sbus: failed to create pcm\n");
|
||||
goto out_put_ci_module;
|
||||
}
|
||||
dev->pcm->dev = &dev->ofdev.dev;
|
||||
}
|
||||
|
||||
/* ALSA yet again sucks.
|
||||
|
@ -988,6 +987,8 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
|
|||
goto out_put_ci_module;
|
||||
snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
|
||||
&i2sbus_playback_ops);
|
||||
dev->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].dev.parent =
|
||||
&dev->ofdev.dev;
|
||||
i2sdev->out.created = 1;
|
||||
}
|
||||
|
||||
|
@ -1003,6 +1004,8 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
|
|||
goto out_put_ci_module;
|
||||
snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE,
|
||||
&i2sbus_record_ops);
|
||||
dev->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].dev.parent =
|
||||
&dev->ofdev.dev;
|
||||
i2sdev->in.created = 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -889,8 +889,8 @@ static int aaci_probe_ac97(struct aaci *aaci)
|
|||
static void aaci_free_card(struct snd_card *card)
|
||||
{
|
||||
struct aaci *aaci = card->private_data;
|
||||
if (aaci->base)
|
||||
iounmap(aaci->base);
|
||||
|
||||
iounmap(aaci->base);
|
||||
}
|
||||
|
||||
static struct aaci *aaci_init_card(struct amba_device *dev)
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
|
@ -34,10 +37,10 @@
|
|||
#include <linux/platform_data/dma-dw.h>
|
||||
#include <linux/dma/dw.h>
|
||||
|
||||
#ifdef CONFIG_AVR32
|
||||
#include <mach/cpu.h>
|
||||
|
||||
#ifdef CONFIG_ARCH_AT91
|
||||
#include <mach/hardware.h>
|
||||
#else
|
||||
#define cpu_is_at32ap7000() 0
|
||||
#endif
|
||||
|
||||
#include "ac97c.h"
|
||||
|
@ -902,6 +905,40 @@ static void atmel_ac97c_reset(struct atmel_ac97c *chip)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id atmel_ac97c_dt_ids[] = {
|
||||
{ .compatible = "atmel,at91sam9263-ac97c", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, atmel_ac97c_dt_ids);
|
||||
|
||||
static struct ac97c_platform_data *atmel_ac97c_probe_dt(struct device *dev)
|
||||
{
|
||||
struct ac97c_platform_data *pdata;
|
||||
struct device_node *node = dev->of_node;
|
||||
const struct of_device_id *match;
|
||||
|
||||
if (!node) {
|
||||
dev_err(dev, "Device does not have associated DT data\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pdata->reset_pin = of_get_named_gpio(dev->of_node, "ac97-gpios", 2);
|
||||
|
||||
return pdata;
|
||||
}
|
||||
#else
|
||||
static struct ac97c_platform_data *atmel_ac97c_probe_dt(struct device *dev)
|
||||
{
|
||||
dev_err(dev, "no platform data defined\n");
|
||||
return ERR_PTR(-ENXIO);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int atmel_ac97c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_card *card;
|
||||
|
@ -922,10 +959,11 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
|
|||
return -ENXIO;
|
||||
}
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
if (!pdata) {
|
||||
dev_dbg(&pdev->dev, "no platform data\n");
|
||||
return -ENXIO;
|
||||
pdata = atmel_ac97c_probe_dt(&pdev->dev);
|
||||
if (IS_ERR(pdata))
|
||||
return PTR_ERR(pdata);
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
|
@ -1204,6 +1242,7 @@ static struct platform_driver atmel_ac97c_driver = {
|
|||
.driver = {
|
||||
.name = "atmel_ac97c",
|
||||
.pm = ATMEL_AC97C_PM_OPS,
|
||||
.of_match_table = of_match_ptr(atmel_ac97c_dt_ids),
|
||||
},
|
||||
};
|
||||
module_platform_driver(atmel_ac97c_driver);
|
||||
|
|
|
@ -868,12 +868,12 @@ static int snd_compress_dev_register(struct snd_device *device)
|
|||
return -EBADFD;
|
||||
compr = device->device_data;
|
||||
|
||||
sprintf(str, "comprC%iD%i", compr->card->number, compr->device);
|
||||
pr_debug("reg %s for device %s, direction %d\n", str, compr->name,
|
||||
compr->direction);
|
||||
/* register compressed device */
|
||||
ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card,
|
||||
compr->device, &snd_compr_file_ops, compr, str);
|
||||
ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS,
|
||||
compr->card, compr->device,
|
||||
&snd_compr_file_ops, compr, &compr->dev);
|
||||
if (ret < 0) {
|
||||
pr_err("snd_register_device failed\n %d", ret);
|
||||
return ret;
|
||||
|
@ -887,8 +887,16 @@ static int snd_compress_dev_disconnect(struct snd_device *device)
|
|||
struct snd_compr *compr;
|
||||
|
||||
compr = device->device_data;
|
||||
snd_unregister_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card,
|
||||
compr->device);
|
||||
snd_unregister_device(&compr->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_compress_dev_free(struct snd_device *device)
|
||||
{
|
||||
struct snd_compr *compr;
|
||||
|
||||
compr = device->device_data;
|
||||
put_device(&compr->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -903,7 +911,7 @@ int snd_compress_new(struct snd_card *card, int device,
|
|||
int dirn, struct snd_compr *compr)
|
||||
{
|
||||
static struct snd_device_ops ops = {
|
||||
.dev_free = NULL,
|
||||
.dev_free = snd_compress_dev_free,
|
||||
.dev_register = snd_compress_dev_register,
|
||||
.dev_disconnect = snd_compress_dev_disconnect,
|
||||
};
|
||||
|
@ -911,6 +919,10 @@ int snd_compress_new(struct snd_card *card, int device,
|
|||
compr->card = card;
|
||||
compr->device = device;
|
||||
compr->direction = dirn;
|
||||
|
||||
snd_device_initialize(&compr->dev, card);
|
||||
dev_set_name(&compr->dev, "comprC%iD%i", card->number, device);
|
||||
|
||||
return snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_compress_new);
|
||||
|
@ -948,7 +960,7 @@ int snd_compress_register(struct snd_compr *device)
|
|||
{
|
||||
int retval;
|
||||
|
||||
if (device->name == NULL || device->dev == NULL || device->ops == NULL)
|
||||
if (device->name == NULL || device->ops == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("Registering compressed device %s\n", device->name);
|
||||
|
|
|
@ -50,7 +50,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
|
|||
unsigned long flags;
|
||||
struct snd_card *card;
|
||||
struct snd_ctl_file *ctl;
|
||||
int err;
|
||||
int i, err;
|
||||
|
||||
err = nonseekable_open(inode, file);
|
||||
if (err < 0)
|
||||
|
@ -79,8 +79,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
|
|||
init_waitqueue_head(&ctl->change_sleep);
|
||||
spin_lock_init(&ctl->read_lock);
|
||||
ctl->card = card;
|
||||
ctl->prefer_pcm_subdevice = -1;
|
||||
ctl->prefer_rawmidi_subdevice = -1;
|
||||
for (i = 0; i < SND_CTL_SUBDEV_ITEMS; i++)
|
||||
ctl->preferred_subdevice[i] = -1;
|
||||
ctl->pid = get_pid(task_pid(current));
|
||||
file->private_data = ctl;
|
||||
write_lock_irqsave(&card->ctl_files_rwlock, flags);
|
||||
|
@ -373,6 +373,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
|
|||
card->controls_count += kcontrol->count;
|
||||
kcontrol->id.numid = card->last_numid + 1;
|
||||
card->last_numid += kcontrol->count;
|
||||
id = kcontrol->id;
|
||||
count = kcontrol->count;
|
||||
up_write(&card->controls_rwsem);
|
||||
for (idx = 0; idx < count; idx++, id.index++, id.numid++)
|
||||
|
@ -439,6 +440,7 @@ add:
|
|||
card->controls_count += kcontrol->count;
|
||||
kcontrol->id.numid = card->last_numid + 1;
|
||||
card->last_numid += kcontrol->count;
|
||||
id = kcontrol->id;
|
||||
count = kcontrol->count;
|
||||
up_write(&card->controls_rwsem);
|
||||
for (idx = 0; idx < count; idx++, id.index++, id.numid++)
|
||||
|
@ -1607,6 +1609,27 @@ static int snd_ctl_fasync(int fd, struct file * file, int on)
|
|||
return fasync_helper(fd, file, on, &ctl->fasync);
|
||||
}
|
||||
|
||||
/* return the preferred subdevice number if already assigned;
|
||||
* otherwise return -1
|
||||
*/
|
||||
int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type)
|
||||
{
|
||||
struct snd_ctl_file *kctl;
|
||||
int subdevice = -1;
|
||||
|
||||
read_lock(&card->ctl_files_rwlock);
|
||||
list_for_each_entry(kctl, &card->ctl_files, list) {
|
||||
if (kctl->pid == task_pid(current)) {
|
||||
subdevice = kctl->preferred_subdevice[type];
|
||||
if (subdevice != -1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&card->ctl_files_rwlock);
|
||||
return subdevice;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice);
|
||||
|
||||
/*
|
||||
* ioctl32 compat
|
||||
*/
|
||||
|
@ -1639,19 +1662,9 @@ static const struct file_operations snd_ctl_f_ops =
|
|||
static int snd_ctl_dev_register(struct snd_device *device)
|
||||
{
|
||||
struct snd_card *card = device->device_data;
|
||||
int err, cardnum;
|
||||
char name[16];
|
||||
|
||||
if (snd_BUG_ON(!card))
|
||||
return -ENXIO;
|
||||
cardnum = card->number;
|
||||
if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))
|
||||
return -ENXIO;
|
||||
sprintf(name, "controlC%i", cardnum);
|
||||
if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
|
||||
&snd_ctl_f_ops, card, name)) < 0)
|
||||
return err;
|
||||
return 0;
|
||||
return snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
|
||||
&snd_ctl_f_ops, card, &card->ctl_dev);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1661,13 +1674,6 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
|
|||
{
|
||||
struct snd_card *card = device->device_data;
|
||||
struct snd_ctl_file *ctl;
|
||||
int err, cardnum;
|
||||
|
||||
if (snd_BUG_ON(!card))
|
||||
return -ENXIO;
|
||||
cardnum = card->number;
|
||||
if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))
|
||||
return -ENXIO;
|
||||
|
||||
read_lock(&card->ctl_files_rwlock);
|
||||
list_for_each_entry(ctl, &card->ctl_files, list) {
|
||||
|
@ -1676,10 +1682,7 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
|
|||
}
|
||||
read_unlock(&card->ctl_files_rwlock);
|
||||
|
||||
if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
|
||||
card, -1)) < 0)
|
||||
return err;
|
||||
return 0;
|
||||
return snd_unregister_device(&card->ctl_dev);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1696,6 +1699,7 @@ static int snd_ctl_dev_free(struct snd_device *device)
|
|||
snd_ctl_remove(card, control);
|
||||
}
|
||||
up_write(&card->controls_rwsem);
|
||||
put_device(&card->ctl_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1710,10 +1714,20 @@ int snd_ctl_create(struct snd_card *card)
|
|||
.dev_register = snd_ctl_dev_register,
|
||||
.dev_disconnect = snd_ctl_dev_disconnect,
|
||||
};
|
||||
int err;
|
||||
|
||||
if (snd_BUG_ON(!card))
|
||||
return -ENXIO;
|
||||
return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
|
||||
if (snd_BUG_ON(card->number < 0 || card->number >= SNDRV_CARDS))
|
||||
return -ENXIO;
|
||||
|
||||
snd_device_initialize(&card->ctl_dev, card);
|
||||
dev_set_name(&card->ctl_dev, "controlC%d", card->number);
|
||||
|
||||
err = snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
|
||||
if (err < 0)
|
||||
put_device(&card->ctl_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -38,7 +38,6 @@ MODULE_LICENSE("GPL");
|
|||
static LIST_HEAD(snd_hwdep_devices);
|
||||
static DEFINE_MUTEX(register_mutex);
|
||||
|
||||
static int snd_hwdep_free(struct snd_hwdep *hwdep);
|
||||
static int snd_hwdep_dev_free(struct snd_device *device);
|
||||
static int snd_hwdep_dev_register(struct snd_device *device);
|
||||
static int snd_hwdep_dev_disconnect(struct snd_device *device);
|
||||
|
@ -345,6 +344,11 @@ static const struct file_operations snd_hwdep_f_ops =
|
|||
.mmap = snd_hwdep_mmap,
|
||||
};
|
||||
|
||||
static void release_hwdep_device(struct device *dev)
|
||||
{
|
||||
kfree(container_of(dev, struct snd_hwdep, dev));
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hwdep_new - create a new hwdep instance
|
||||
* @card: the card instance
|
||||
|
@ -378,48 +382,49 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
|
|||
dev_err(card->dev, "hwdep: cannot allocate\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
init_waitqueue_head(&hwdep->open_wait);
|
||||
mutex_init(&hwdep->open_mutex);
|
||||
hwdep->card = card;
|
||||
hwdep->device = device;
|
||||
if (id)
|
||||
strlcpy(hwdep->id, id, sizeof(hwdep->id));
|
||||
|
||||
snd_device_initialize(&hwdep->dev, card);
|
||||
hwdep->dev.release = release_hwdep_device;
|
||||
dev_set_name(&hwdep->dev, "hwC%iD%i", card->number, device);
|
||||
#ifdef CONFIG_SND_OSSEMUL
|
||||
hwdep->oss_type = -1;
|
||||
#endif
|
||||
if ((err = snd_device_new(card, SNDRV_DEV_HWDEP, hwdep, &ops)) < 0) {
|
||||
snd_hwdep_free(hwdep);
|
||||
|
||||
err = snd_device_new(card, SNDRV_DEV_HWDEP, hwdep, &ops);
|
||||
if (err < 0) {
|
||||
put_device(&hwdep->dev);
|
||||
return err;
|
||||
}
|
||||
init_waitqueue_head(&hwdep->open_wait);
|
||||
mutex_init(&hwdep->open_mutex);
|
||||
|
||||
if (rhwdep)
|
||||
*rhwdep = hwdep;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_hwdep_new);
|
||||
|
||||
static int snd_hwdep_free(struct snd_hwdep *hwdep)
|
||||
static int snd_hwdep_dev_free(struct snd_device *device)
|
||||
{
|
||||
struct snd_hwdep *hwdep = device->device_data;
|
||||
if (!hwdep)
|
||||
return 0;
|
||||
if (hwdep->private_free)
|
||||
hwdep->private_free(hwdep);
|
||||
kfree(hwdep);
|
||||
put_device(&hwdep->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_hwdep_dev_free(struct snd_device *device)
|
||||
{
|
||||
struct snd_hwdep *hwdep = device->device_data;
|
||||
return snd_hwdep_free(hwdep);
|
||||
}
|
||||
|
||||
static int snd_hwdep_dev_register(struct snd_device *device)
|
||||
{
|
||||
struct snd_hwdep *hwdep = device->device_data;
|
||||
struct snd_card *card = hwdep->card;
|
||||
struct device *dev;
|
||||
int err;
|
||||
char name[32];
|
||||
|
||||
mutex_lock(®ister_mutex);
|
||||
if (snd_hwdep_search(card, hwdep->device)) {
|
||||
|
@ -427,53 +432,30 @@ static int snd_hwdep_dev_register(struct snd_device *device)
|
|||
return -EBUSY;
|
||||
}
|
||||
list_add_tail(&hwdep->list, &snd_hwdep_devices);
|
||||
sprintf(name, "hwC%iD%i", hwdep->card->number, hwdep->device);
|
||||
dev = hwdep->dev;
|
||||
if (!dev)
|
||||
dev = snd_card_get_device_link(hwdep->card);
|
||||
err = snd_register_device_for_dev(SNDRV_DEVICE_TYPE_HWDEP,
|
||||
hwdep->card, hwdep->device,
|
||||
&snd_hwdep_f_ops, hwdep, name, dev);
|
||||
err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP,
|
||||
hwdep->card, hwdep->device,
|
||||
&snd_hwdep_f_ops, hwdep, &hwdep->dev);
|
||||
if (err < 0) {
|
||||
dev_err(dev,
|
||||
"unable to register hardware dependent device %i:%i\n",
|
||||
card->number, hwdep->device);
|
||||
dev_err(&hwdep->dev, "unable to register\n");
|
||||
list_del(&hwdep->list);
|
||||
mutex_unlock(®ister_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (hwdep->groups) {
|
||||
struct device *d = snd_get_device(SNDRV_DEVICE_TYPE_HWDEP,
|
||||
hwdep->card, hwdep->device);
|
||||
if (d) {
|
||||
if (hwdep->private_data)
|
||||
dev_set_drvdata(d, hwdep->private_data);
|
||||
err = sysfs_create_groups(&d->kobj, hwdep->groups);
|
||||
if (err < 0)
|
||||
dev_warn(dev,
|
||||
"hwdep %d:%d: cannot create sysfs groups\n",
|
||||
card->number, hwdep->device);
|
||||
put_device(d);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SND_OSSEMUL
|
||||
hwdep->ossreg = 0;
|
||||
if (hwdep->oss_type >= 0) {
|
||||
if ((hwdep->oss_type == SNDRV_OSS_DEVICE_TYPE_DMFM) && (hwdep->device != 0)) {
|
||||
dev_warn(dev,
|
||||
if (hwdep->oss_type == SNDRV_OSS_DEVICE_TYPE_DMFM &&
|
||||
hwdep->device)
|
||||
dev_warn(&hwdep->dev,
|
||||
"only hwdep device 0 can be registered as OSS direct FM device!\n");
|
||||
} else {
|
||||
if (snd_register_oss_device(hwdep->oss_type,
|
||||
card, hwdep->device,
|
||||
&snd_hwdep_f_ops, hwdep) < 0) {
|
||||
dev_err(dev,
|
||||
"unable to register OSS compatibility device %i:%i\n",
|
||||
card->number, hwdep->device);
|
||||
} else
|
||||
hwdep->ossreg = 1;
|
||||
}
|
||||
else if (snd_register_oss_device(hwdep->oss_type,
|
||||
card, hwdep->device,
|
||||
&snd_hwdep_f_ops, hwdep) < 0)
|
||||
dev_warn(&hwdep->dev,
|
||||
"unable to register OSS compatibility device\n");
|
||||
else
|
||||
hwdep->ossreg = 1;
|
||||
}
|
||||
#endif
|
||||
mutex_unlock(®ister_mutex);
|
||||
|
@ -497,7 +479,7 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
|
|||
if (hwdep->ossreg)
|
||||
snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device);
|
||||
#endif
|
||||
snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device);
|
||||
snd_unregister_device(&hwdep->dev);
|
||||
list_del_init(&hwdep->list);
|
||||
mutex_unlock(&hwdep->open_mutex);
|
||||
mutex_unlock(®ister_mutex);
|
||||
|
|
|
@ -157,8 +157,31 @@ static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int),
|
|||
return mask; /* unchanged */
|
||||
}
|
||||
|
||||
/* the default release callback set in snd_device_initialize() below;
|
||||
* this is just NOP for now, as almost all jobs are already done in
|
||||
* dev_free callback of snd_device chain instead.
|
||||
*/
|
||||
static void default_release(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_device_initialize - Initialize struct device for sound devices
|
||||
* @dev: device to initialize
|
||||
* @card: card to assign, optional
|
||||
*/
|
||||
void snd_device_initialize(struct device *dev, struct snd_card *card)
|
||||
{
|
||||
device_initialize(dev);
|
||||
if (card)
|
||||
dev->parent = &card->card_dev;
|
||||
dev->class = sound_class;
|
||||
dev->release = default_release;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_device_initialize);
|
||||
|
||||
static int snd_card_do_free(struct snd_card *card);
|
||||
static const struct attribute_group *card_dev_attr_groups[];
|
||||
static const struct attribute_group card_dev_attr_group;
|
||||
|
||||
static void release_card_device(struct device *dev)
|
||||
{
|
||||
|
@ -246,7 +269,8 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
|
|||
card->card_dev.parent = parent;
|
||||
card->card_dev.class = sound_class;
|
||||
card->card_dev.release = release_card_device;
|
||||
card->card_dev.groups = card_dev_attr_groups;
|
||||
card->card_dev.groups = card->dev_groups;
|
||||
card->dev_groups[0] = &card_dev_attr_group;
|
||||
err = kobject_set_name(&card->card_dev.kobj, "card%d", idx);
|
||||
if (err < 0)
|
||||
goto __error;
|
||||
|
@ -677,14 +701,32 @@ static struct attribute *card_dev_attrs[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group card_dev_attr_group = {
|
||||
static const struct attribute_group card_dev_attr_group = {
|
||||
.attrs = card_dev_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *card_dev_attr_groups[] = {
|
||||
&card_dev_attr_group,
|
||||
NULL
|
||||
/**
|
||||
* snd_card_add_dev_attr - Append a new sysfs attribute group to card
|
||||
* @card: card instance
|
||||
* @group: attribute group to append
|
||||
*/
|
||||
int snd_card_add_dev_attr(struct snd_card *card,
|
||||
const struct attribute_group *group)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* loop for (arraysize-1) here to keep NULL at the last entry */
|
||||
for (i = 0; i < ARRAY_SIZE(card->dev_groups) - 1; i++) {
|
||||
if (!card->dev_groups[i]) {
|
||||
card->dev_groups[i] = group;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
dev_err(card->dev, "Too many groups assigned\n");
|
||||
return -ENOSPC;
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(snd_card_add_dev_attr);
|
||||
|
||||
/**
|
||||
* snd_card_register - register the soundcard
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <sound/core.h>
|
||||
|
||||
/**
|
||||
|
|
|
@ -719,7 +719,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
|
|||
|
||||
oss_buffer_size = snd_pcm_plug_client_size(substream,
|
||||
snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size;
|
||||
oss_buffer_size = 1 << ld2(oss_buffer_size);
|
||||
oss_buffer_size = rounddown_pow_of_two(oss_buffer_size);
|
||||
if (atomic_read(&substream->mmap_count)) {
|
||||
if (oss_buffer_size > runtime->oss.mmap_bytes)
|
||||
oss_buffer_size = runtime->oss.mmap_bytes;
|
||||
|
@ -755,14 +755,14 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
|
|||
min_period_size = snd_pcm_plug_client_size(substream,
|
||||
snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
|
||||
min_period_size *= oss_frame_size;
|
||||
min_period_size = 1 << (ld2(min_period_size - 1) + 1);
|
||||
min_period_size = roundup_pow_of_two(min_period_size);
|
||||
if (oss_period_size < min_period_size)
|
||||
oss_period_size = min_period_size;
|
||||
|
||||
max_period_size = snd_pcm_plug_client_size(substream,
|
||||
snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
|
||||
max_period_size *= oss_frame_size;
|
||||
max_period_size = 1 << ld2(max_period_size);
|
||||
max_period_size = rounddown_pow_of_two(max_period_size);
|
||||
if (oss_period_size > max_period_size)
|
||||
oss_period_size = max_period_size;
|
||||
|
||||
|
|
|
@ -161,7 +161,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
|
|||
|
||||
if (get_user(val, (int __user *)arg))
|
||||
return -EFAULT;
|
||||
control->prefer_pcm_subdevice = val;
|
||||
control->preferred_subdevice[SND_CTL_SUBDEV_PCM] = val;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -673,6 +673,8 @@ static inline int snd_pcm_substream_proc_init(struct snd_pcm_substream *substrea
|
|||
static inline int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) { return 0; }
|
||||
#endif /* CONFIG_SND_VERBOSE_PROCFS */
|
||||
|
||||
static const struct attribute_group *pcm_dev_attr_groups[];
|
||||
|
||||
/**
|
||||
* snd_pcm_new_stream - create a new PCM stream
|
||||
* @pcm: the pcm instance
|
||||
|
@ -698,7 +700,15 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
|
|||
pstr->stream = stream;
|
||||
pstr->pcm = pcm;
|
||||
pstr->substream_count = substream_count;
|
||||
if (substream_count > 0 && !pcm->internal) {
|
||||
if (!substream_count)
|
||||
return 0;
|
||||
|
||||
snd_device_initialize(&pstr->dev, pcm->card);
|
||||
pstr->dev.groups = pcm_dev_attr_groups;
|
||||
dev_set_name(&pstr->dev, "pcmC%iD%i%c", pcm->card->number, pcm->device,
|
||||
stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c');
|
||||
|
||||
if (!pcm->internal) {
|
||||
err = snd_pcm_stream_proc_init(pstr);
|
||||
if (err < 0) {
|
||||
pcm_err(pcm, "Error in snd_pcm_stream_proc_init\n");
|
||||
|
@ -868,6 +878,8 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
|
|||
kfree(setup);
|
||||
}
|
||||
#endif
|
||||
if (pstr->substream_count)
|
||||
put_device(&pstr->dev);
|
||||
}
|
||||
|
||||
static int snd_pcm_free(struct snd_pcm *pcm)
|
||||
|
@ -901,9 +913,8 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
|
|||
struct snd_pcm_str * pstr;
|
||||
struct snd_pcm_substream *substream;
|
||||
struct snd_pcm_runtime *runtime;
|
||||
struct snd_ctl_file *kctl;
|
||||
struct snd_card *card;
|
||||
int prefer_subdevice = -1;
|
||||
int prefer_subdevice;
|
||||
size_t size;
|
||||
|
||||
if (snd_BUG_ON(!pcm || !rsubstream))
|
||||
|
@ -914,15 +925,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
|
|||
return -ENODEV;
|
||||
|
||||
card = pcm->card;
|
||||
read_lock(&card->ctl_files_rwlock);
|
||||
list_for_each_entry(kctl, &card->ctl_files, list) {
|
||||
if (kctl->pid == task_pid(current)) {
|
||||
prefer_subdevice = kctl->prefer_pcm_subdevice;
|
||||
if (prefer_subdevice != -1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&card->ctl_files_rwlock);
|
||||
prefer_subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_PCM);
|
||||
|
||||
switch (stream) {
|
||||
case SNDRV_PCM_STREAM_PLAYBACK:
|
||||
|
@ -1078,9 +1081,7 @@ static int snd_pcm_dev_register(struct snd_device *device)
|
|||
int cidx, err;
|
||||
struct snd_pcm_substream *substream;
|
||||
struct snd_pcm_notify *notify;
|
||||
char str[16];
|
||||
struct snd_pcm *pcm;
|
||||
struct device *dev;
|
||||
|
||||
if (snd_BUG_ON(!device || !device->device_data))
|
||||
return -ENXIO;
|
||||
|
@ -1097,42 +1098,22 @@ static int snd_pcm_dev_register(struct snd_device *device)
|
|||
continue;
|
||||
switch (cidx) {
|
||||
case SNDRV_PCM_STREAM_PLAYBACK:
|
||||
sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device);
|
||||
devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
|
||||
break;
|
||||
case SNDRV_PCM_STREAM_CAPTURE:
|
||||
sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device);
|
||||
devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
|
||||
break;
|
||||
}
|
||||
/* device pointer to use, pcm->dev takes precedence if
|
||||
* it is assigned, otherwise fall back to card's device
|
||||
* if possible */
|
||||
dev = pcm->dev;
|
||||
if (!dev)
|
||||
dev = snd_card_get_device_link(pcm->card);
|
||||
/* register pcm */
|
||||
err = snd_register_device_for_dev(devtype, pcm->card,
|
||||
pcm->device,
|
||||
&snd_pcm_f_ops[cidx],
|
||||
pcm, str, dev);
|
||||
err = snd_register_device(devtype, pcm->card, pcm->device,
|
||||
&snd_pcm_f_ops[cidx], pcm,
|
||||
&pcm->streams[cidx].dev);
|
||||
if (err < 0) {
|
||||
list_del(&pcm->list);
|
||||
mutex_unlock(®ister_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
dev = snd_get_device(devtype, pcm->card, pcm->device);
|
||||
if (dev) {
|
||||
err = sysfs_create_groups(&dev->kobj,
|
||||
pcm_dev_attr_groups);
|
||||
if (err < 0)
|
||||
dev_warn(dev,
|
||||
"pcm %d:%d: cannot create sysfs groups\n",
|
||||
pcm->card->number, pcm->device);
|
||||
put_device(dev);
|
||||
}
|
||||
|
||||
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
|
||||
snd_pcm_timer_init(substream);
|
||||
}
|
||||
|
@ -1149,7 +1130,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
|
|||
struct snd_pcm *pcm = device->device_data;
|
||||
struct snd_pcm_notify *notify;
|
||||
struct snd_pcm_substream *substream;
|
||||
int cidx, devtype;
|
||||
int cidx;
|
||||
|
||||
mutex_lock(®ister_mutex);
|
||||
if (list_empty(&pcm->list))
|
||||
|
@ -1172,16 +1153,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
|
|||
notify->n_disconnect(pcm);
|
||||
}
|
||||
for (cidx = 0; cidx < 2; cidx++) {
|
||||
devtype = -1;
|
||||
switch (cidx) {
|
||||
case SNDRV_PCM_STREAM_PLAYBACK:
|
||||
devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
|
||||
break;
|
||||
case SNDRV_PCM_STREAM_CAPTURE:
|
||||
devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
|
||||
break;
|
||||
}
|
||||
snd_unregister_device(devtype, pcm->card, pcm->device);
|
||||
snd_unregister_device(&pcm->streams[cidx].dev);
|
||||
if (pcm->streams[cidx].chmap_kctl) {
|
||||
snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl);
|
||||
pcm->streams[cidx].chmap_kctl = NULL;
|
||||
|
|
|
@ -1015,6 +1015,60 @@ int snd_interval_list(struct snd_interval *i, unsigned int count,
|
|||
|
||||
EXPORT_SYMBOL(snd_interval_list);
|
||||
|
||||
/**
|
||||
* snd_interval_ranges - refine the interval value from the list of ranges
|
||||
* @i: the interval value to refine
|
||||
* @count: the number of elements in the list of ranges
|
||||
* @ranges: the ranges list
|
||||
* @mask: the bit-mask to evaluate
|
||||
*
|
||||
* Refines the interval value from the list of ranges.
|
||||
* When mask is non-zero, only the elements corresponding to bit 1 are
|
||||
* evaluated.
|
||||
*
|
||||
* Return: Positive if the value is changed, zero if it's not changed, or a
|
||||
* negative error code.
|
||||
*/
|
||||
int snd_interval_ranges(struct snd_interval *i, unsigned int count,
|
||||
const struct snd_interval *ranges, unsigned int mask)
|
||||
{
|
||||
unsigned int k;
|
||||
struct snd_interval range_union;
|
||||
struct snd_interval range;
|
||||
|
||||
if (!count) {
|
||||
snd_interval_none(i);
|
||||
return -EINVAL;
|
||||
}
|
||||
snd_interval_any(&range_union);
|
||||
range_union.min = UINT_MAX;
|
||||
range_union.max = 0;
|
||||
for (k = 0; k < count; k++) {
|
||||
if (mask && !(mask & (1 << k)))
|
||||
continue;
|
||||
snd_interval_copy(&range, &ranges[k]);
|
||||
if (snd_interval_refine(&range, i) < 0)
|
||||
continue;
|
||||
if (snd_interval_empty(&range))
|
||||
continue;
|
||||
|
||||
if (range.min < range_union.min) {
|
||||
range_union.min = range.min;
|
||||
range_union.openmin = 1;
|
||||
}
|
||||
if (range.min == range_union.min && !range.openmin)
|
||||
range_union.openmin = 0;
|
||||
if (range.max > range_union.max) {
|
||||
range_union.max = range.max;
|
||||
range_union.openmax = 1;
|
||||
}
|
||||
if (range.max == range_union.max && !range.openmax)
|
||||
range_union.openmax = 0;
|
||||
}
|
||||
return snd_interval_refine(i, &range_union);
|
||||
}
|
||||
EXPORT_SYMBOL(snd_interval_ranges);
|
||||
|
||||
static int snd_interval_step(struct snd_interval *i, unsigned int step)
|
||||
{
|
||||
unsigned int n;
|
||||
|
@ -1221,6 +1275,37 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,
|
|||
|
||||
EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
|
||||
|
||||
static int snd_pcm_hw_rule_ranges(struct snd_pcm_hw_params *params,
|
||||
struct snd_pcm_hw_rule *rule)
|
||||
{
|
||||
struct snd_pcm_hw_constraint_ranges *r = rule->private;
|
||||
return snd_interval_ranges(hw_param_interval(params, rule->var),
|
||||
r->count, r->ranges, r->mask);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* snd_pcm_hw_constraint_ranges - apply list of range constraints to a parameter
|
||||
* @runtime: PCM runtime instance
|
||||
* @cond: condition bits
|
||||
* @var: hw_params variable to apply the list of range constraints
|
||||
* @r: ranges
|
||||
*
|
||||
* Apply the list of range constraints to an interval parameter.
|
||||
*
|
||||
* Return: Zero if successful, or a negative error code on failure.
|
||||
*/
|
||||
int snd_pcm_hw_constraint_ranges(struct snd_pcm_runtime *runtime,
|
||||
unsigned int cond,
|
||||
snd_pcm_hw_param_t var,
|
||||
const struct snd_pcm_hw_constraint_ranges *r)
|
||||
{
|
||||
return snd_pcm_hw_rule_add(runtime, cond, var,
|
||||
snd_pcm_hw_rule_ranges, (void *)r,
|
||||
var, -1);
|
||||
}
|
||||
EXPORT_SYMBOL(snd_pcm_hw_constraint_ranges);
|
||||
|
||||
static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,
|
||||
struct snd_pcm_hw_rule *rule)
|
||||
{
|
||||
|
@ -1299,8 +1384,14 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
|
|||
int width = l & 0xffff;
|
||||
unsigned int msbits = l >> 16;
|
||||
struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
|
||||
if (snd_interval_single(i) && snd_interval_value(i) == width)
|
||||
params->msbits = msbits;
|
||||
|
||||
if (!snd_interval_single(i))
|
||||
return 0;
|
||||
|
||||
if ((snd_interval_value(i) == width) ||
|
||||
(width == 0 && snd_interval_value(i) > msbits))
|
||||
params->msbits = min_not_zero(params->msbits, msbits);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1311,6 +1402,11 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
|
|||
* @width: sample bits width
|
||||
* @msbits: msbits width
|
||||
*
|
||||
* This constraint will set the number of most significant bits (msbits) if a
|
||||
* sample format with the specified width has been select. If width is set to 0
|
||||
* the msbits will be set for any sample format with a width larger than the
|
||||
* specified msbits.
|
||||
*
|
||||
* Return: Zero if successful, or a negative error code on failure.
|
||||
*/
|
||||
int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime,
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/time.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/aio.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/control.h>
|
||||
|
@ -34,7 +35,6 @@
|
|||
#include <sound/pcm_params.h>
|
||||
#include <sound/timer.h>
|
||||
#include <sound/minors.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* Compatibility
|
||||
|
@ -420,7 +420,8 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
|
|||
|
||||
hw = &substream->runtime->hw;
|
||||
if (!params->info) {
|
||||
params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES;
|
||||
params->info = hw->info & ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES |
|
||||
SNDRV_PCM_INFO_DRAIN_TRIGGER);
|
||||
if (!hw_support_mmap(substream))
|
||||
params->info &= ~(SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID);
|
||||
|
@ -719,8 +720,11 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
|
|||
runtime->status->audio_tstamp;
|
||||
goto _tstamp_end;
|
||||
}
|
||||
} else {
|
||||
/* get tstamp only in fallback mode and only if enabled */
|
||||
if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
|
||||
snd_pcm_gettime(runtime, &status->tstamp);
|
||||
}
|
||||
snd_pcm_gettime(runtime, &status->tstamp);
|
||||
_tstamp_end:
|
||||
status->appl_ptr = runtime->control->appl_ptr;
|
||||
status->hw_ptr = runtime->status->hw_ptr;
|
||||
|
@ -806,7 +810,8 @@ static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream)
|
|||
if (runtime->trigger_master == NULL)
|
||||
return;
|
||||
if (runtime->trigger_master == substream) {
|
||||
snd_pcm_gettime(runtime, &runtime->trigger_tstamp);
|
||||
if (!runtime->trigger_tstamp_latched)
|
||||
snd_pcm_gettime(runtime, &runtime->trigger_tstamp);
|
||||
} else {
|
||||
snd_pcm_trigger_tstamp(runtime->trigger_master);
|
||||
runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp;
|
||||
|
@ -975,6 +980,7 @@ static int snd_pcm_pre_start(struct snd_pcm_substream *substream, int state)
|
|||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
|
||||
!snd_pcm_playback_data(substream))
|
||||
return -EPIPE;
|
||||
runtime->trigger_tstamp_latched = false;
|
||||
runtime->trigger_master = substream;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1566,6 +1572,13 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state)
|
|||
snd_pcm_post_stop(substream, new_state);
|
||||
}
|
||||
}
|
||||
|
||||
if (runtime->status->state == SNDRV_PCM_STATE_DRAINING &&
|
||||
runtime->trigger_master == substream &&
|
||||
(runtime->hw.info & SNDRV_PCM_INFO_DRAIN_TRIGGER))
|
||||
return substream->ops->trigger(substream,
|
||||
SNDRV_PCM_TRIGGER_DRAIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,11 +57,11 @@ static LIST_HEAD(snd_rawmidi_devices);
|
|||
static DEFINE_MUTEX(register_mutex);
|
||||
|
||||
#define rmidi_err(rmidi, fmt, args...) \
|
||||
dev_err((rmidi)->card->dev, fmt, ##args)
|
||||
dev_err(&(rmidi)->dev, fmt, ##args)
|
||||
#define rmidi_warn(rmidi, fmt, args...) \
|
||||
dev_warn((rmidi)->card->dev, fmt, ##args)
|
||||
dev_warn(&(rmidi)->dev, fmt, ##args)
|
||||
#define rmidi_dbg(rmidi, fmt, args...) \
|
||||
dev_dbg((rmidi)->card->dev, fmt, ##args)
|
||||
dev_dbg(&(rmidi)->dev, fmt, ##args)
|
||||
|
||||
static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device)
|
||||
{
|
||||
|
@ -369,7 +369,6 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
|
|||
struct snd_rawmidi *rmidi;
|
||||
struct snd_rawmidi_file *rawmidi_file = NULL;
|
||||
wait_queue_t wait;
|
||||
struct snd_ctl_file *kctl;
|
||||
|
||||
if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK))
|
||||
return -EINVAL; /* invalid combination */
|
||||
|
@ -413,16 +412,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
|
|||
init_waitqueue_entry(&wait, current);
|
||||
add_wait_queue(&rmidi->open_wait, &wait);
|
||||
while (1) {
|
||||
subdevice = -1;
|
||||
read_lock(&card->ctl_files_rwlock);
|
||||
list_for_each_entry(kctl, &card->ctl_files, list) {
|
||||
if (kctl->pid == task_pid(current)) {
|
||||
subdevice = kctl->prefer_rawmidi_subdevice;
|
||||
if (subdevice != -1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&card->ctl_files_rwlock);
|
||||
subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_RAWMIDI);
|
||||
err = rawmidi_open_priv(rmidi, subdevice, fflags, rawmidi_file);
|
||||
if (err >= 0)
|
||||
break;
|
||||
|
@ -862,7 +852,7 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card,
|
|||
|
||||
if (get_user(val, (int __user *)argp))
|
||||
return -EFAULT;
|
||||
control->prefer_rawmidi_subdevice = val;
|
||||
control->preferred_subdevice[SND_CTL_SUBDEV_RAWMIDI] = val;
|
||||
return 0;
|
||||
}
|
||||
case SNDRV_CTL_IOCTL_RAWMIDI_INFO:
|
||||
|
@ -1453,6 +1443,11 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void release_rawmidi_device(struct device *dev)
|
||||
{
|
||||
kfree(container_of(dev, struct snd_rawmidi, dev));
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_rawmidi_new - create a rawmidi instance
|
||||
* @card: the card instance
|
||||
|
@ -1497,6 +1492,11 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
|
|||
|
||||
if (id != NULL)
|
||||
strlcpy(rmidi->id, id, sizeof(rmidi->id));
|
||||
|
||||
snd_device_initialize(&rmidi->dev, card);
|
||||
rmidi->dev.release = release_rawmidi_device;
|
||||
dev_set_name(&rmidi->dev, "midiC%iD%i", card->number, device);
|
||||
|
||||
if ((err = snd_rawmidi_alloc_substreams(rmidi,
|
||||
&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT],
|
||||
SNDRV_RAWMIDI_STREAM_INPUT,
|
||||
|
@ -1548,7 +1548,7 @@ static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
|
|||
snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
|
||||
if (rmidi->private_free)
|
||||
rmidi->private_free(rmidi);
|
||||
kfree(rmidi);
|
||||
put_device(&rmidi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1581,19 +1581,18 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
|
|||
return -EBUSY;
|
||||
}
|
||||
list_add_tail(&rmidi->list, &snd_rawmidi_devices);
|
||||
sprintf(name, "midiC%iD%i", rmidi->card->number, rmidi->device);
|
||||
if ((err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI,
|
||||
rmidi->card, rmidi->device,
|
||||
&snd_rawmidi_f_ops, rmidi, name)) < 0) {
|
||||
rmidi_err(rmidi, "unable to register rawmidi device %i:%i\n",
|
||||
rmidi->card->number, rmidi->device);
|
||||
err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI,
|
||||
rmidi->card, rmidi->device,
|
||||
&snd_rawmidi_f_ops, rmidi, &rmidi->dev);
|
||||
if (err < 0) {
|
||||
rmidi_err(rmidi, "unable to register\n");
|
||||
list_del(&rmidi->list);
|
||||
mutex_unlock(®ister_mutex);
|
||||
return err;
|
||||
}
|
||||
if (rmidi->ops && rmidi->ops->dev_register &&
|
||||
(err = rmidi->ops->dev_register(rmidi)) < 0) {
|
||||
snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
|
||||
snd_unregister_device(&rmidi->dev);
|
||||
list_del(&rmidi->list);
|
||||
mutex_unlock(®ister_mutex);
|
||||
return err;
|
||||
|
@ -1681,7 +1680,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
|
|||
rmidi->ossreg = 0;
|
||||
}
|
||||
#endif /* CONFIG_SND_OSSEMUL */
|
||||
snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
|
||||
snd_unregister_device(&rmidi->dev);
|
||||
mutex_unlock(&rmidi->open_mutex);
|
||||
mutex_unlock(®ister_mutex);
|
||||
return 0;
|
||||
|
|
|
@ -237,8 +237,7 @@ snd_seq_oss_midi_check_exit_port(int client, int port)
|
|||
spin_unlock_irqrestore(®ister_lock, flags);
|
||||
snd_use_lock_free(&mdev->use_lock);
|
||||
snd_use_lock_sync(&mdev->use_lock);
|
||||
if (mdev->coder)
|
||||
snd_midi_event_free(mdev->coder);
|
||||
snd_midi_event_free(mdev->coder);
|
||||
kfree(mdev);
|
||||
}
|
||||
spin_lock_irqsave(®ister_lock, flags);
|
||||
|
@ -265,8 +264,7 @@ snd_seq_oss_midi_clear_all(void)
|
|||
spin_lock_irqsave(®ister_lock, flags);
|
||||
for (i = 0; i < max_midi_devs; i++) {
|
||||
if ((mdev = midi_devs[i]) != NULL) {
|
||||
if (mdev->coder)
|
||||
snd_midi_event_free(mdev->coder);
|
||||
snd_midi_event_free(mdev->coder);
|
||||
kfree(mdev);
|
||||
midi_devs[i] = NULL;
|
||||
}
|
||||
|
|
|
@ -1133,7 +1133,7 @@ static int snd_seq_ioctl_system_info(struct snd_seq_client *client, void __user
|
|||
/* fill the info fields */
|
||||
info.queues = SNDRV_SEQ_MAX_QUEUES;
|
||||
info.clients = SNDRV_SEQ_MAX_CLIENTS;
|
||||
info.ports = 256; /* fixed limit */
|
||||
info.ports = SNDRV_SEQ_MAX_PORTS;
|
||||
info.channels = 256; /* fixed limit */
|
||||
info.cur_clients = client_usage.cur;
|
||||
info.cur_queues = snd_seq_queue_get_cur_queues();
|
||||
|
@ -1279,7 +1279,6 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client,
|
|||
port->owner = callback->owner;
|
||||
port->private_data = callback->private_data;
|
||||
port->private_free = callback->private_free;
|
||||
port->callback_all = callback->callback_all;
|
||||
port->event_input = callback->event_input;
|
||||
port->c_src.open = callback->subscribe;
|
||||
port->c_src.close = callback->unsubscribe;
|
||||
|
@ -2571,6 +2570,8 @@ static const struct file_operations snd_seq_f_ops =
|
|||
.compat_ioctl = snd_seq_ioctl_compat,
|
||||
};
|
||||
|
||||
static struct device seq_dev;
|
||||
|
||||
/*
|
||||
* register sequencer device
|
||||
*/
|
||||
|
@ -2578,12 +2579,17 @@ int __init snd_sequencer_device_init(void)
|
|||
{
|
||||
int err;
|
||||
|
||||
snd_device_initialize(&seq_dev, NULL);
|
||||
dev_set_name(&seq_dev, "seq");
|
||||
|
||||
if (mutex_lock_interruptible(®ister_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if ((err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0,
|
||||
&snd_seq_f_ops, NULL, "seq")) < 0) {
|
||||
err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0,
|
||||
&snd_seq_f_ops, NULL, &seq_dev);
|
||||
if (err < 0) {
|
||||
mutex_unlock(®ister_mutex);
|
||||
put_device(&seq_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -2599,5 +2605,6 @@ int __init snd_sequencer_device_init(void)
|
|||
*/
|
||||
void __exit snd_sequencer_device_done(void)
|
||||
{
|
||||
snd_unregister_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0);
|
||||
snd_unregister_device(&seq_dev);
|
||||
put_device(&seq_dev);
|
||||
}
|
||||
|
|
|
@ -268,8 +268,7 @@ static void snd_seq_midisynth_delete(struct seq_midisynth *msynth)
|
|||
snd_seq_event_port_detach(msynth->seq_client, msynth->seq_port);
|
||||
}
|
||||
|
||||
if (msynth->parser)
|
||||
snd_midi_event_free(msynth->parser);
|
||||
snd_midi_event_free(msynth->parser);
|
||||
}
|
||||
|
||||
/* register new midi synth port */
|
||||
|
|
|
@ -134,7 +134,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
|
|||
if (snd_BUG_ON(!client))
|
||||
return NULL;
|
||||
|
||||
if (client->num_ports >= SNDRV_SEQ_MAX_PORTS - 1) {
|
||||
if (client->num_ports >= SNDRV_SEQ_MAX_PORTS) {
|
||||
pr_warn("ALSA: seq: too many ports for client %d\n", client->number);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -411,9 +411,6 @@ int snd_seq_get_port_info(struct snd_seq_client_port * port,
|
|||
* invoked.
|
||||
* This feature is useful if these callbacks are associated with
|
||||
* initialization or termination of devices (see seq_midi.c).
|
||||
*
|
||||
* If callback_all option is set, the callback function is invoked
|
||||
* at each connection/disconnection.
|
||||
*/
|
||||
|
||||
static int subscribe_port(struct snd_seq_client *client,
|
||||
|
@ -427,7 +424,7 @@ static int subscribe_port(struct snd_seq_client *client,
|
|||
if (!try_module_get(port->owner))
|
||||
return -EFAULT;
|
||||
grp->count++;
|
||||
if (grp->open && (port->callback_all || grp->count == 1)) {
|
||||
if (grp->open && grp->count == 1) {
|
||||
err = grp->open(port->private_data, info);
|
||||
if (err < 0) {
|
||||
module_put(port->owner);
|
||||
|
@ -452,7 +449,7 @@ static int unsubscribe_port(struct snd_seq_client *client,
|
|||
if (! grp->count)
|
||||
return -EINVAL;
|
||||
grp->count--;
|
||||
if (grp->close && (port->callback_all || grp->count == 0))
|
||||
if (grp->close && grp->count == 0)
|
||||
err = grp->close(port->private_data, info);
|
||||
if (send_ack && client->type == USER_CLIENT)
|
||||
snd_seq_client_notify_subscription(port->addr.client, port->addr.port,
|
||||
|
|
|
@ -73,7 +73,6 @@ struct snd_seq_client_port {
|
|||
int atomic, int hop);
|
||||
void (*private_free)(void *private_data);
|
||||
void *private_data;
|
||||
unsigned int callback_all : 1;
|
||||
unsigned int closing : 1;
|
||||
unsigned int timestamping: 1;
|
||||
unsigned int time_real: 1;
|
||||
|
|
|
@ -242,30 +242,30 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev)
|
|||
#endif
|
||||
|
||||
/**
|
||||
* snd_register_device_for_dev - Register the ALSA device file for the card
|
||||
* snd_register_device - Register the ALSA device file for the card
|
||||
* @type: the device type, SNDRV_DEVICE_TYPE_XXX
|
||||
* @card: the card instance
|
||||
* @dev: the device index
|
||||
* @f_ops: the file operations
|
||||
* @private_data: user pointer for f_ops->open()
|
||||
* @name: the device file name
|
||||
* @device: the &struct device to link this new device to
|
||||
* @device: the device to register
|
||||
*
|
||||
* Registers an ALSA device file for the given card.
|
||||
* The operators have to be set in reg parameter.
|
||||
*
|
||||
* Return: Zero if successful, or a negative error code on failure.
|
||||
*/
|
||||
int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
|
||||
const struct file_operations *f_ops,
|
||||
void *private_data,
|
||||
const char *name, struct device *device)
|
||||
int snd_register_device(int type, struct snd_card *card, int dev,
|
||||
const struct file_operations *f_ops,
|
||||
void *private_data, struct device *device)
|
||||
{
|
||||
int minor;
|
||||
int err = 0;
|
||||
struct snd_minor *preg;
|
||||
|
||||
if (snd_BUG_ON(!name))
|
||||
if (snd_BUG_ON(!device))
|
||||
return -EINVAL;
|
||||
|
||||
preg = kmalloc(sizeof *preg, GFP_KERNEL);
|
||||
if (preg == NULL)
|
||||
return -ENOMEM;
|
||||
|
@ -284,102 +284,56 @@ int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
|
|||
minor = -EBUSY;
|
||||
#endif
|
||||
if (minor < 0) {
|
||||
mutex_unlock(&sound_mutex);
|
||||
kfree(preg);
|
||||
return minor;
|
||||
err = minor;
|
||||
goto error;
|
||||
}
|
||||
|
||||
preg->dev = device;
|
||||
device->devt = MKDEV(major, minor);
|
||||
err = device_add(device);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
snd_minors[minor] = preg;
|
||||
preg->dev = device_create(sound_class, device, MKDEV(major, minor),
|
||||
private_data, "%s", name);
|
||||
if (IS_ERR(preg->dev)) {
|
||||
snd_minors[minor] = NULL;
|
||||
mutex_unlock(&sound_mutex);
|
||||
minor = PTR_ERR(preg->dev);
|
||||
kfree(preg);
|
||||
return minor;
|
||||
}
|
||||
|
||||
error:
|
||||
mutex_unlock(&sound_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_register_device_for_dev);
|
||||
|
||||
/* find the matching minor record
|
||||
* return the index of snd_minor, or -1 if not found
|
||||
*/
|
||||
static int find_snd_minor(int type, struct snd_card *card, int dev)
|
||||
{
|
||||
int cardnum, minor;
|
||||
struct snd_minor *mptr;
|
||||
|
||||
cardnum = card ? card->number : -1;
|
||||
for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor)
|
||||
if ((mptr = snd_minors[minor]) != NULL &&
|
||||
mptr->type == type &&
|
||||
mptr->card == cardnum &&
|
||||
mptr->device == dev)
|
||||
return minor;
|
||||
return -1;
|
||||
if (err < 0)
|
||||
kfree(preg);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_register_device);
|
||||
|
||||
/**
|
||||
* snd_unregister_device - unregister the device on the given card
|
||||
* @type: the device type, SNDRV_DEVICE_TYPE_XXX
|
||||
* @card: the card instance
|
||||
* @dev: the device index
|
||||
* @dev: the device instance
|
||||
*
|
||||
* Unregisters the device file already registered via
|
||||
* snd_register_device().
|
||||
*
|
||||
* Return: Zero if successful, or a negative error code on failure.
|
||||
*/
|
||||
int snd_unregister_device(int type, struct snd_card *card, int dev)
|
||||
int snd_unregister_device(struct device *dev)
|
||||
{
|
||||
int minor;
|
||||
struct snd_minor *preg;
|
||||
|
||||
mutex_lock(&sound_mutex);
|
||||
minor = find_snd_minor(type, card, dev);
|
||||
if (minor < 0) {
|
||||
mutex_unlock(&sound_mutex);
|
||||
return -EINVAL;
|
||||
for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
|
||||
preg = snd_minors[minor];
|
||||
if (preg && preg->dev == dev) {
|
||||
snd_minors[minor] = NULL;
|
||||
device_del(dev);
|
||||
kfree(preg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
device_destroy(sound_class, MKDEV(major, minor));
|
||||
|
||||
kfree(snd_minors[minor]);
|
||||
snd_minors[minor] = NULL;
|
||||
mutex_unlock(&sound_mutex);
|
||||
if (minor >= ARRAY_SIZE(snd_minors))
|
||||
return -ENOENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_unregister_device);
|
||||
|
||||
/**
|
||||
* snd_get_device - get the assigned device to the given type and device number
|
||||
* @type: the device type, SNDRV_DEVICE_TYPE_XXX
|
||||
* @card:the card instance
|
||||
* @dev: the device index
|
||||
*
|
||||
* The caller needs to release it via put_device() after using it.
|
||||
*/
|
||||
struct device *snd_get_device(int type, struct snd_card *card, int dev)
|
||||
{
|
||||
int minor;
|
||||
struct device *d = NULL;
|
||||
|
||||
mutex_lock(&sound_mutex);
|
||||
minor = find_snd_minor(type, card, dev);
|
||||
if (minor >= 0) {
|
||||
d = snd_minors[minor]->dev;
|
||||
if (d)
|
||||
get_device(d);
|
||||
}
|
||||
mutex_unlock(&sound_mutex);
|
||||
return d;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_get_device);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
/*
|
||||
* INFO PART
|
||||
|
|
|
@ -1030,9 +1030,7 @@ static int snd_timer_register_system(void)
|
|||
snd_timer_free(timer);
|
||||
return -ENOMEM;
|
||||
}
|
||||
init_timer(&priv->tlist);
|
||||
priv->tlist.function = snd_timer_s_function;
|
||||
priv->tlist.data = (unsigned long) timer;
|
||||
setup_timer(&priv->tlist, snd_timer_s_function, (unsigned long) timer);
|
||||
timer->private_data = priv;
|
||||
timer->private_free = snd_timer_free_system;
|
||||
return snd_timer_global_register(timer);
|
||||
|
@ -1942,6 +1940,17 @@ static const struct file_operations snd_timer_f_ops =
|
|||
.fasync = snd_timer_user_fasync,
|
||||
};
|
||||
|
||||
/* unregister the system timer */
|
||||
static void snd_timer_free_all(void)
|
||||
{
|
||||
struct snd_timer *timer, *n;
|
||||
|
||||
list_for_each_entry_safe(timer, n, &snd_timer_list, device_list)
|
||||
snd_timer_free(timer);
|
||||
}
|
||||
|
||||
static struct device timer_dev;
|
||||
|
||||
/*
|
||||
* ENTRY functions
|
||||
*/
|
||||
|
@ -1950,30 +1959,39 @@ static int __init alsa_timer_init(void)
|
|||
{
|
||||
int err;
|
||||
|
||||
snd_device_initialize(&timer_dev, NULL);
|
||||
dev_set_name(&timer_dev, "timer");
|
||||
|
||||
#ifdef SNDRV_OSS_INFO_DEV_TIMERS
|
||||
snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1,
|
||||
"system timer");
|
||||
#endif
|
||||
|
||||
if ((err = snd_timer_register_system()) < 0)
|
||||
err = snd_timer_register_system();
|
||||
if (err < 0) {
|
||||
pr_err("ALSA: unable to register system timer (%i)\n", err);
|
||||
if ((err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0,
|
||||
&snd_timer_f_ops, NULL, "timer")) < 0)
|
||||
put_device(&timer_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0,
|
||||
&snd_timer_f_ops, NULL, &timer_dev);
|
||||
if (err < 0) {
|
||||
pr_err("ALSA: unable to register timer device (%i)\n", err);
|
||||
snd_timer_free_all();
|
||||
put_device(&timer_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
snd_timer_proc_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit alsa_timer_exit(void)
|
||||
{
|
||||
struct list_head *p, *n;
|
||||
|
||||
snd_unregister_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0);
|
||||
/* unregister the system timer */
|
||||
list_for_each_safe(p, n, &snd_timer_list) {
|
||||
struct snd_timer *timer = list_entry(p, struct snd_timer, device_list);
|
||||
snd_timer_free(timer);
|
||||
}
|
||||
snd_unregister_device(&timer_dev);
|
||||
snd_timer_free_all();
|
||||
put_device(&timer_dev);
|
||||
snd_timer_proc_done();
|
||||
#ifdef SNDRV_OSS_INFO_DEV_TIMERS
|
||||
snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1);
|
||||
|
|
|
@ -181,8 +181,7 @@ static void loopback_timer_start(struct loopback_pcm *dpcm)
|
|||
}
|
||||
tick = dpcm->period_size_frac - dpcm->irq_pos;
|
||||
tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps;
|
||||
dpcm->timer.expires = jiffies + tick;
|
||||
add_timer(&dpcm->timer);
|
||||
mod_timer(&dpcm->timer, jiffies + tick);
|
||||
}
|
||||
|
||||
/* call in cable->lock */
|
||||
|
|
|
@ -245,9 +245,8 @@ struct dummy_systimer_pcm {
|
|||
|
||||
static void dummy_systimer_rearm(struct dummy_systimer_pcm *dpcm)
|
||||
{
|
||||
dpcm->timer.expires = jiffies +
|
||||
(dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate;
|
||||
add_timer(&dpcm->timer);
|
||||
mod_timer(&dpcm->timer, jiffies +
|
||||
(dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate);
|
||||
}
|
||||
|
||||
static void dummy_systimer_update(struct dummy_systimer_pcm *dpcm)
|
||||
|
@ -340,9 +339,8 @@ static int dummy_systimer_create(struct snd_pcm_substream *substream)
|
|||
if (!dpcm)
|
||||
return -ENOMEM;
|
||||
substream->runtime->private_data = dpcm;
|
||||
init_timer(&dpcm->timer);
|
||||
dpcm->timer.data = (unsigned long) dpcm;
|
||||
dpcm->timer.function = dummy_systimer_callback;
|
||||
setup_timer(&dpcm->timer, dummy_systimer_callback,
|
||||
(unsigned long) dpcm);
|
||||
spin_lock_init(&dpcm->lock);
|
||||
dpcm->substream = substream;
|
||||
return 0;
|
||||
|
|
|
@ -1094,8 +1094,7 @@ static int snd_ml403_ac97cr_free(struct snd_ml403_ac97cr *ml403_ac97cr)
|
|||
if (ml403_ac97cr->capture_irq >= 0)
|
||||
free_irq(ml403_ac97cr->capture_irq, ml403_ac97cr);
|
||||
/* give back "port" */
|
||||
if (ml403_ac97cr->port != NULL)
|
||||
iounmap(ml403_ac97cr->port);
|
||||
iounmap(ml403_ac97cr->port);
|
||||
kfree(ml403_ac97cr);
|
||||
PDEBUG(INIT_INFO, "free(): (done)\n");
|
||||
return 0;
|
||||
|
@ -1238,14 +1237,11 @@ snd_ml403_ac97cr_mixer(struct snd_ml403_ac97cr *ml403_ac97cr)
|
|||
}
|
||||
|
||||
static int
|
||||
snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device,
|
||||
struct snd_pcm **rpcm)
|
||||
snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device)
|
||||
{
|
||||
struct snd_pcm *pcm;
|
||||
int err;
|
||||
|
||||
if (rpcm)
|
||||
*rpcm = NULL;
|
||||
err = snd_pcm_new(ml403_ac97cr->card, "ML403AC97CR/1", device, 1, 1,
|
||||
&pcm);
|
||||
if (err < 0)
|
||||
|
@ -1263,8 +1259,6 @@ snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device,
|
|||
snd_dma_continuous_data(GFP_KERNEL),
|
||||
64 * 1024,
|
||||
128 * 1024);
|
||||
if (rpcm)
|
||||
*rpcm = pcm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1298,7 +1292,7 @@ static int snd_ml403_ac97cr_probe(struct platform_device *pfdev)
|
|||
return err;
|
||||
}
|
||||
PDEBUG(INIT_INFO, "probe(): mixer done\n");
|
||||
err = snd_ml403_ac97cr_pcm(ml403_ac97cr, 0, NULL);
|
||||
err = snd_ml403_ac97cr_pcm(ml403_ac97cr, 0);
|
||||
if (err < 0) {
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -176,8 +176,7 @@ static void snd_mpu401_uart_timer(unsigned long data)
|
|||
|
||||
spin_lock_irqsave(&mpu->timer_lock, flags);
|
||||
/*mpu->mode |= MPU401_MODE_TIMER;*/
|
||||
mpu->timer.expires = 1 + jiffies;
|
||||
add_timer(&mpu->timer);
|
||||
mod_timer(&mpu->timer, 1 + jiffies);
|
||||
spin_unlock_irqrestore(&mpu->timer_lock, flags);
|
||||
if (mpu->rmidi)
|
||||
_snd_mpu401_uart_interrupt(mpu);
|
||||
|
@ -192,11 +191,9 @@ static void snd_mpu401_uart_add_timer (struct snd_mpu401 *mpu, int input)
|
|||
|
||||
spin_lock_irqsave (&mpu->timer_lock, flags);
|
||||
if (mpu->timer_invoked == 0) {
|
||||
init_timer(&mpu->timer);
|
||||
mpu->timer.data = (unsigned long)mpu;
|
||||
mpu->timer.function = snd_mpu401_uart_timer;
|
||||
mpu->timer.expires = 1 + jiffies;
|
||||
add_timer(&mpu->timer);
|
||||
setup_timer(&mpu->timer, snd_mpu401_uart_timer,
|
||||
(unsigned long)mpu);
|
||||
mod_timer(&mpu->timer, 1 + jiffies);
|
||||
}
|
||||
mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER :
|
||||
MPU401_MODE_OUTPUT_TIMER;
|
||||
|
|
|
@ -414,8 +414,7 @@ static void snd_mtpav_output_timer(unsigned long data)
|
|||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
/* reprogram timer */
|
||||
chip->timer.expires = 1 + jiffies;
|
||||
add_timer(&chip->timer);
|
||||
mod_timer(&chip->timer, 1 + jiffies);
|
||||
/* process each port */
|
||||
for (p = 0; p <= chip->num_ports * 2 + MTPAV_PIDX_BROADCAST; p++) {
|
||||
struct mtpav_port *portp = &chip->ports[p];
|
||||
|
@ -428,8 +427,7 @@ static void snd_mtpav_output_timer(unsigned long data)
|
|||
/* spinlock held! */
|
||||
static void snd_mtpav_add_output_timer(struct mtpav *chip)
|
||||
{
|
||||
chip->timer.expires = 1 + jiffies;
|
||||
add_timer(&chip->timer);
|
||||
mod_timer(&chip->timer, 1 + jiffies);
|
||||
}
|
||||
|
||||
/* spinlock held! */
|
||||
|
@ -704,15 +702,13 @@ static int snd_mtpav_probe(struct platform_device *dev)
|
|||
|
||||
mtp_card = card->private_data;
|
||||
spin_lock_init(&mtp_card->spinlock);
|
||||
init_timer(&mtp_card->timer);
|
||||
mtp_card->card = card;
|
||||
mtp_card->irq = -1;
|
||||
mtp_card->share_irq = 0;
|
||||
mtp_card->inmidistate = 0;
|
||||
mtp_card->outmidihwport = 0xffffffff;
|
||||
init_timer(&mtp_card->timer);
|
||||
mtp_card->timer.function = snd_mtpav_output_timer;
|
||||
mtp_card->timer.data = (unsigned long) mtp_card;
|
||||
setup_timer(&mtp_card->timer, snd_mtpav_output_timer,
|
||||
(unsigned long) mtp_card);
|
||||
|
||||
card->private_free = snd_mtpav_free;
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
*/
|
||||
|
||||
#include <sound/opl3.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
|
|
@ -258,12 +258,10 @@ void snd_opl3_timer_func(unsigned long data)
|
|||
spin_unlock_irqrestore(&opl3->voice_lock, flags);
|
||||
|
||||
spin_lock_irqsave(&opl3->sys_timer_lock, flags);
|
||||
if (again) {
|
||||
opl3->tlist.expires = jiffies + 1; /* invoke again */
|
||||
add_timer(&opl3->tlist);
|
||||
} else {
|
||||
if (again)
|
||||
mod_timer(&opl3->tlist, jiffies + 1); /* invoke again */
|
||||
else
|
||||
opl3->sys_timer_status = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);
|
||||
}
|
||||
|
||||
|
@ -275,8 +273,7 @@ static void snd_opl3_start_timer(struct snd_opl3 *opl3)
|
|||
unsigned long flags;
|
||||
spin_lock_irqsave(&opl3->sys_timer_lock, flags);
|
||||
if (! opl3->sys_timer_status) {
|
||||
opl3->tlist.expires = jiffies + 1;
|
||||
add_timer(&opl3->tlist);
|
||||
mod_timer(&opl3->tlist, jiffies + 1);
|
||||
opl3->sys_timer_status = 1;
|
||||
}
|
||||
spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);
|
||||
|
|
|
@ -247,9 +247,7 @@ static int snd_opl3_seq_new_device(struct snd_seq_device *dev)
|
|||
}
|
||||
|
||||
/* setup system timer */
|
||||
init_timer(&opl3->tlist);
|
||||
opl3->tlist.function = snd_opl3_timer_func;
|
||||
opl3->tlist.data = (unsigned long) opl3;
|
||||
setup_timer(&opl3->tlist, snd_opl3_timer_func, (unsigned long) opl3);
|
||||
spin_lock_init(&opl3->sys_timer_lock);
|
||||
opl3->sys_timer_status = 0;
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
|
||||
MODULE_DESCRIPTION("OPL4 driver");
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
#include "opl4_local.h"
|
||||
#include <linux/delay.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/io.h>
|
||||
#include <sound/asoundef.h>
|
||||
|
||||
/* GM2 controllers */
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue