Commit 021f163d authored by Linus Torvalds's avatar Linus Torvalds

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

Pull sound updates from Takashi Iwai:
 "After a heavy storm by syzkaller in 4.5 cycle, we have relatively few
  changes in the core at this time while a lot of changes are found in
  the driver side, unsurprisingly.  Below are some highlights:

  ALSA core:
   - A few more hardening in ALSA timer codes
   - An extension of sequencer API for advertising the card / pid
   - Small fixes in compress-offload and jack layers

  HD-audio:
   - Dynamic PCM assignment in HDMI/DP codec; preparation for upcoming
     DP-MST support
   - Lots of code refactoring for sharing with ASoC SKL driver
   - Regression fixes for Intel HDMI/DP
   - Fixups for CX20724 codec, Lenovo AiO

  USB-audio:
   - Add quirk_alias option to make quirk debugging easier
   - Fixes for possible Oops by malformed firmware

  Firewire:
   - Add support for FW-1804 in tascam driver
   - Improvements / changes in card registration, multi stream handling,
     etc for DICE
   - Lots of code refactoring

  ASoC:
   - Enhancements of still ongoing topology API
   - Lots of commits for Intel Skylake support including HDMI support
   - A few Intel Atom driver updates for recent devices
   - Lots of improvements to the Renesas drivers
   - Capture support for Qualcomm drivers
   - Support for TI DaVinci DRA7xxx devices
   - New machine drivers for Freescale systems with Cirrus CODECs,
     Mediatek systems with RT5650 CODECs
   - New CPU drivers for Allwinner S/PDIF controllers
   - New CODEC drivers for Maxim MAX9867 and MAX98926 and Realtek RT5514"

* tag 'sound-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (291 commits)
  ALSA: hda - Fix mutex deadlock at HDMI/DP hotplug
  ALSA: ctl: change return value in compatibility layer so that it's the same value in core implementation
  ALSA: mixart: silence an uninitialized variable warning
  ALSA: usb-audio: Add sanity checks for endpoint accesses
  ALSA: usb-audio: Minor code cleanup in create_fixed_stream_quirk()
  ALSA: usb-audio: Fix NULL dereference in create_fixed_stream_quirk()
  ALSA: hda - Limit i915 HDMI binding only for HSW and later
  ALSA: hda - Fix unconditional GPIO toggle via automute
  ALSA: mixart: silence unitialized variable warnings
  ALSA: hda - Fixes double fault in nvhdmi_chmap_cea_alloc_validate_get_type
  ALSA: intel8x0: Add clock quirk entry for AD1981B on IBM ThinkPad X41.
  ALSA: hda - Add new GPU codec ID 0x10de0082 to snd-hda
  ASoC: rsnd: add simplified module explanation
  ASoC: hdac_hdmi: Add broxton device ID
  ASoC: Intel: Bxtn: Add Broxton PCI ID
  ASoC: Intel: Skylake: Move Skylake dsp ops & loader ops
  ASoC: Intel: add dmabuffer to common sst_dsp
  ASoC: Intel: Skylake: Unstatify skl_dsp_enable_core
  ASoC: Intel: Skylake: Fix whitepsace issues
  ASoC: Intel: Skylake: Move module id defines
  ...
parents 9ea44635 222bde03
Analog Devices ADAU1361/ADAU1461/ADAU1761/ADAU1961/ADAU1381/ADAU1781
Required properties:
- compatible: Should contain one of the following:
"adi,adau1361"
"adi,adau1461"
"adi,adau1761"
"adi,adau1961"
"adi,adau1381"
"adi,adau1781"
- reg: The i2c address. Value depends on the state of ADDR0
and ADDR1, as wired in hardware.
Examples:
#include <dt-bindings/sound/adau17x1.h>
i2c_bus {
adau1361@38 {
compatible = "adi,adau1761";
reg = <0x38>;
};
};
......@@ -24,6 +24,9 @@ The compatible list for this generic sound card currently:
"fsl,imx-audio-cs42888"
"fsl,imx-audio-cs427x"
(compatible with CS4271 and CS4272)
"fsl,imx-audio-wm8962"
(compatible with Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt)
......@@ -63,6 +66,12 @@ Optional properties:
- audio-asrc : The phandle of ASRC. It can be absent if there's no
need to add ASRC support via DPCM.
Optional unless SSI is selected as a CPU DAI:
- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
- mux-ext-port : The external port of the i.MX audio muxer
Example:
sound-cs42888 {
compatible = "fsl,imx-audio-cs42888";
......
max9867 codec
This device supports I2C mode only.
Required properties:
- compatible : "maxim,max9867"
- reg : The chip select number on the I2C bus
Example:
&i2c {
max9867: max9867@0x18 {
compatible = "maxim,max9867";
reg = <0x18>;
};
};
max98926 audio CODEC
This device supports I2C.
Required properties:
- compatible : "maxim,max98926"
- vmon-slot-no : slot number used to send voltage information
or in inteleave mode this will be used as
interleave slot.
- imon-slot-no : slot number used to send current information
- interleave-mode : When using two MAX98926 in a system it is
possible to create ADC data that that will
overflow the frame size. Digital Audio Interleave
mode provides a means to output VMON and IMON data
from two devices on a single DOUT line when running
smaller frames sizes such as 32 BCLKS per LRCLK or
48 BCLKS per LRCLK.
- reg : the I2C address of the device for I2C
Example:
codec: max98926@1a {
compatible = "maxim,max98926";
vmon-slot-no = <0>;
imon-slot-no = <2>;
reg = <0x1a>;
};
MT8173 with RT5650 RT5514 CODECS
Required properties:
- compatible : "mediatek,mt8173-rt5650-rt5514"
- mediatek,audio-codec: the phandles of rt5650 and rt5514 codecs
- mediatek,platform: the phandle of MT8173 ASoC platform
Example:
sound {
compatible = "mediatek,mt8173-rt5650-rt5514";
mediatek,audio-codec = <&rt5650 &rt5514>;
mediatek,platform = <&afe>;
};
MT8173 with RT5650 CODECS
Required properties:
- compatible : "mediatek,mt8173-rt5650"
- mediatek,audio-codec: the phandles of rt5650 codecs
- mediatek,platform: the phandle of MT8173 ASoC platform
Example:
sound {
compatible = "mediatek,mt8173-rt5650";
mediatek,audio-codec = <&rt5650>;
mediatek,platform = <&afe>;
};
Texas Instruments pcm179x DT bindings
This driver supports the SPI bus.
This driver supports both the I2C and SPI bus.
Required properties:
......@@ -9,6 +9,11 @@ Required properties:
For required properties on SPI, please consult
Documentation/devicetree/bindings/spi/spi-bus.txt
Required properties on I2C:
- reg: the I2C address
Examples:
codec_spi: 1792a@0 {
......@@ -16,3 +21,7 @@ Examples:
spi-max-frequency = <600000>;
};
codec_i2c: 1792a@4c {
compatible = "ti,pcm1792a";
reg = <0x4c>;
};
Renesas R-Car sound
=============================================
* Modules
=============================================
Renesas R-Car sound is constructed from below modules
(for Gen2 or later)
SCU : Sampling Rate Converter Unit
- SRC : Sampling Rate Converter
- CMD
- CTU : Channel Transfer Unit
- MIX : Mixer
- DVC : Digital Volume and Mute Function
SSIU : Serial Sound Interface Unit
SSI : Serial Sound Interface
See detail of each module's channels, connection, limitation on datasheet
=============================================
* Multi channel
=============================================
Multi channel is supported by Multi-SSI, or TDM-SSI.
Multi-SSI : 6ch case, you can use stereo x 3 SSI
TDM-SSI : 6ch case, you can use TDM
=============================================
* Enable/Disable each modules
=============================================
See datasheet to check SRC/CTU/MIX/DVC connect-limitation.
DT controls enabling/disabling module.
${LINUX}/arch/arm/boot/dts/r8a7790-lager.dts can be good example.
This is example of
Playback: [MEM] -> [SRC2] -> [DVC0] -> [SSIU0/SSI0] -> [codec]
Capture: [MEM] <- [DVC1] <- [SRC3] <- [SSIU1/SSI1] <- [codec]
&rcar_sound {
...
rcar_sound,dai {
dai0 {
playback = <&ssi0 &src2 &dvc0>;
capture = <&ssi1 &src3 &dvc1>;
};
};
};
You can use below.
${LINUX}/arch/arm/boot/dts/r8a7790.dts can be good example.
&src0 &ctu00 &mix0 &dvc0 &ssi0
&src1 &ctu01 &mix1 &dvc1 &ssi1
&src2 &ctu02 &ssi2
&src3 &ctu03 &ssi3
&src4 &ssi4
&src5 &ctu10 &ssi5
&src6 &ctu11 &ssi6
&src7 &ctu12 &ssi7
&src8 &ctu13 &ssi8
&src9 &ssi9
=============================================
* SRC (Sampling Rate Converter)
=============================================
[xx]Hz [yy]Hz
------> [SRC] ------>
SRC can convert [xx]Hz to [yy]Hz. Then, it has below 2 modes
Asynchronous mode: input data / output data are based on different clocks.
you can use this mode on Playback / Capture
Synchronous mode: input data / output data are based on same clocks.
This mode will be used if system doesn't have its input clock,
for example digital TV case.
you can use this mode on Playback
------------------
** Asynchronous mode
------------------
You need to use "renesas,rsrc-card" sound card for it.
example)
sound {
compatible = "renesas,rsrc-card";
...
/*
* SRC Asynchronous mode setting
* Playback:
* All input data will be converted to 48kHz
* Capture:
* Inputed 48kHz data will be converted to
* system specified Hz
*/
convert-rate = <48000>;
...
cpu {
sound-dai = <&rcar_sound>;
};
codec {
...
};
};
------------------
** Synchronous mode
------------------
> amixer set "SRC Out Rate" on
> aplay xxxx.wav
> amixer set "SRC Out Rate" 48000
> amixer set "SRC Out Rate" 44100
=============================================
* CTU (Channel Transfer Unit)
=============================================
[xx]ch [yy]ch
------> [CTU] -------->
CTU can convert [xx]ch to [yy]ch, or exchange outputed channel.
CTU conversion needs matrix settings.
For more detail information, see below
Renesas R-Car datasheet
- Sampling Rate Converter Unit (SCU)
- SCU Operation
- CMD Block
- Functional Blocks in CMD
Renesas R-Car datasheet
- Sampling Rate Converter Unit (SCU)
- Register Description
- CTUn Scale Value exx Register (CTUn_SVxxR)
${LINUX}/sound/soc/sh/rcar/ctu.c
- comment of header
You need to use "renesas,rsrc-card" sound card for it.
example)
sound {
compatible = "renesas,rsrc-card";
...
/*
* CTU setting
* All input data will be converted to 2ch
* as output data
*/
convert-channels = <2>;
...
cpu {
sound-dai = <&rcar_sound>;
};
codec {
...
};
};
Ex) Exchange output channel
Input -> Output
1ch -> 0ch
0ch -> 1ch
example of using matrix
output 0ch = (input 0ch x 0) + (input 1ch x 1)
output 1ch = (input 0ch x 1) + (input 1ch x 0)
amixer set "CTU Reset" on
amixer set "CTU Pass" 9,10
amixer set "CTU SV0" 0,4194304
amixer set "CTU SV1" 4194304,0
example of changing connection
amixer set "CTU Reset" on
amixer set "CTU Pass" 2,1
=============================================
* MIX (Mixer)
=============================================
MIX merges 2 sounds path. You can see 2 sound interface on system,
and these sounds will be merged by MIX.
aplay -D plughw:0,0 xxxx.wav &
aplay -D plughw:0,1 yyyy.wav
You need to use "renesas,rsrc-card" sound card for it.
Ex)
[MEM] -> [SRC1] -> [CTU02] -+-> [MIX0] -> [DVC0] -> [SSI0]
|
[MEM] -> [SRC2] -> [CTU03] -+
sound {
compatible = "renesas,rsrc-card";
...
cpu@0 {
sound-dai = <&rcar_sound 0>;
};
cpu@1 {
sound-dai = <&rcar_sound 1>;
};
codec {
...
};
};
&rcar_sound {
...
rcar_sound,dai {
dai0 {
playback = <&src1 &ctu02 &mix0 &dvc0 &ssi0>;
};
dai1 {
playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
};
};
};
=============================================
* DVC (Digital Volume and Mute Function)
=============================================
DVC controls Playback/Capture volume.
Playback Volume
amixer set "DVC Out" 100%
Capture Volume
amixer set "DVC In" 100%
Playback Mute
amixer set "DVC Out Mute" on
Capture Mute
amixer set "DVC In Mute" on
Volume Ramp
amixer set "DVC Out Ramp Up Rate" "0.125 dB/64 steps"
amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps"
amixer set "DVC Out Ramp" on
aplay xxx.wav &
amixer set "DVC Out" 80% // Volume Down
amixer set "DVC Out" 100% // Volume Up
=============================================
* SSIU (Serial Sound Interface Unit)
=============================================
There is no DT settings for SSIU, because SSIU will be automatically
selected via SSI.
SSIU can avoid some under/over run error, because it has some buffer.
But you can't use it if SSI was PIO mode.
In DMA mode, you can select not to use SSIU by using "no-busif" on DT.
&ssi0 {
no-busif;
};
=============================================
* SSI (Serial Sound Interface)
=============================================
** PIO mode
You can use PIO mode which is for connection check by using.
Note: The system will drop non-SSI modules in PIO mode
even though if DT is selecting other modules.
&ssi0 {
pio-transfer
};
** DMA mode without SSIU
You can use DMA without SSIU.
Note: under/over run, or noise are likely to occur
&ssi0 {
no-busif;
};
** PIN sharing
Each SSI can share WS pin. It is based on platform.
This is example if SSI1 want to share WS pin with SSI0
&ssi1 {
shared-pin;
};
** Multi-SSI
You can use Multi-SSI.
This is example of SSI0/SSI1/SSI2 (= for 6ch)
&rcar_sound {
...
rcar_sound,dai {
dai0 {
playback = <&ssi0 &ssi1 &ssi2 &src0 &dvc0>;
};
};
};
** TDM-SSI
You can use TDM with SSI.
This is example of TDM 6ch.
Driver can automatically switches TDM <-> stereo mode in this case.
rsnd_tdm: sound {
compatible = "simple-audio-card";
...
simple-audio-card,cpu {
/* system can use TDM 6ch */
dai-tdm-slot-num = <6>;
sound-dai = <&rcar_sound>;
};
simple-audio-card,codec {
...
};
};
=============================================
Required properties:
=============================================
- compatible : "renesas,rcar_sound-<soctype>", fallbacks
"renesas,rcar_sound-gen1" if generation1, and
"renesas,rcar_sound-gen2" if generation2
......@@ -64,7 +395,10 @@ DAI subnode properties:
- playback : list of playback modules
- capture : list of capture modules
=============================================
Example:
=============================================
rcar_sound: sound@ec500000 {
#sound-dai-cells = <1>;
......@@ -250,7 +584,9 @@ rcar_sound: sound@ec500000 {
};
};
=============================================
Example: simple sound card
=============================================
rsnd_ak4643: sound {
compatible = "simple-audio-card";
......@@ -290,7 +626,9 @@ Example: simple sound card
shared-pin;
};
=============================================
Example: simple sound card for TDM
=============================================
rsnd_tdm: sound {
compatible = "simple-audio-card";
......@@ -309,7 +647,9 @@ Example: simple sound card for TDM
};
};
=============================================
Example: simple sound card for Multi channel
=============================================
&rcar_sound {
pinctrl-0 = <&sound_pins &sound_clk_pins>;
......
......@@ -30,6 +30,7 @@ Optional subnode properties:
- frame-inversion : bool property. Add this if the
dai-link uses frame clock inversion.
- convert-rate : platform specified sampling rate convert
- convert-channels : platform specified converted channel size (2 - 8 ch)
- audio-prefix : see audio-routing
- audio-routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the connection's sink,
......
......@@ -9,6 +9,7 @@ Required properties:
- "rockchip,rk3066-i2s": for rk3066
- "rockchip,rk3188-i2s", "rockchip,rk3066-i2s": for rk3188
- "rockchip,rk3288-i2s", "rockchip,rk3066-i2s": for rk3288
- "rockchip,rk3399-i2s", "rockchip,rk3066-i2s": for rk3399
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: should contain the I2S interrupt.
......
......@@ -7,8 +7,12 @@ a fibre cable.
Required properties:
- compatible: should be one of the following:
- "rockchip,rk3288-spdif", "rockchip,rk3188-spdif" or
"rockchip,rk3066-spdif"
- "rockchip,rk3066-spdif"
- "rockchip,rk3188-spdif"
- "rockchip,rk3288-spdif"
- "rockchip,rk3366-spdif"
- "rockchip,rk3368-spdif"
- "rockchip,rk3399-spdif"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: should contain the SPDIF interrupt.
......
RT5514 audio CODEC
This device supports I2C only.
Required properties:
- compatible : "realtek,rt5514".
- reg : The I2C address of the device.
Pins on the device (for linking into audio routes) for RT5514:
* DMIC1L
* DMIC1R
* DMIC2L
* DMIC2R
* AMICL
* AMICR
Example:
codec: rt5514@57 {
compatible = "realtek,rt5514";
reg = <0x57>;
};
......@@ -8,6 +8,12 @@ Required properties:
- reg : The I2C address of the device.
Optional properties:
- clocks: The phandle of the master clock to the CODEC.
- clock-names: Should be "mclk".
Pins on the device (for linking into audio routes) for RT5616:
* IN1P
......
......@@ -12,6 +12,9 @@ Required properties:
Optional properties:
- clocks: The phandle of the master clock to the CODEC
- clock-names: Should be "mclk"
- realtek,in1-differential
- realtek,in2-differential
- realtek,in3-differential
......
Allwinner Sony/Philips Digital Interface Format (S/PDIF) Controller
The Allwinner S/PDIF audio block is a transceiver that allows the
processor to receive and transmit digital audio via an coaxial cable or
a fibre cable.
For now only playback is supported.
Required properties:
- compatible : should be one of the following:
- "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC
- reg : Offset and length of the register set for the device.
- interrupts : Contains the spdif interrupt.
- dmas : Generic dma devicetree binding as described in
Documentation/devicetree/bindings/dma/dma.txt.
- dma-names : Two dmas have to be defined, "tx" and "rx".
- clocks : Contains an entry for each entry in clock-names.
- clock-names : Includes the following entries:
"apb" clock for the spdif bus.
"spdif" clock for spdif controller.
Example:
spdif: spdif@01c21000 {
compatible = "allwinner,sun4i-a10-spdif";
reg = <0x01c21000 0x40>;
interrupts = <13>;
clocks = <&apb0_gates 1>, <&spdif_clk>;
clock-names = "apb", "spdif";
dmas = <&dma 0 2>, <&dma 0 2>;
dma-names = "rx", "tx";
status = "okay";
};
Texas Intstruments ADS117x ADC
Required properties:
- compatible : "ti,ads1174" or "ti,ads1178"
Example:
ads1178 {
compatible = "ti,ads1178";
};
......@@ -1910,6 +1910,12 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
- Default: 0x0000
ignore_ctl_error - Ignore any USB-controller regarding mixer
interface (default: no)
autoclock - Enable auto-clock selection for UAC2 devices
(default: yes)
quirk_alias - Quirk alias list, pass strings like
"0123abcd:5678beef", which applies the existing
quirk for the device 5678:beef to a new device
0123:abcd.
This module supports multiple devices, autoprobe and hotplugging.
......@@ -1919,6 +1925,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
NB: ignore_ctl_error=1 may help when you get an error at accessing
the mixer element such as URB error -22. This happens on some
buggy USB device or the controller.
NB: quirk_alias option is provided only for testing / development.
If you want to have a proper support, contact to upstream for
adding the matching quirk in the driver code statically.
Module snd-usb-caiaq
--------------------
......
To support DP MST audio, HD Audio hdmi codec driver introduces virtual pin
and dynamic pcm assignment.
Virtual pin is an extension of per_pin. The most difference of DP MST
from legacy is that DP MST introduces device entry. Each pin can contain
several device entries. Each device entry behaves as a pin.
As each pin may contain several device entries and each codec may contain
several pins, if we use one pcm per per_pin, there will be many PCMs.
The new solution is to create a few PCMs and to dynamically bind pcm to
per_pin. Driver uses spec->dyn_pcm_assign flag to indicate whether to use
the new solution.
PCM
===
To be added
Jack
====
Presume:
- MST must be dyn_pcm_assign, and it is acomp (for Intel scenario);
- NON-MST may or may not be dyn_pcm_assign, it can be acomp or !acomp;
So there are the following scenarios:
a. MST (&& dyn_pcm_assign && acomp)
b. NON-MST && dyn_pcm_assign && acomp
c. NON-MST && !dyn_pcm_assign && !acomp
Below discussion will ignore MST and NON-MST difference as it doesn't
impact on jack handling too much.
Driver uses struct hdmi_pcm pcm[] array in hdmi_spec and snd_jack is
a member of hdmi_pcm. Each pin has one struct hdmi_pcm * pcm pointer.
For !dyn_pcm_assign, per_pin->pcm will assigned to spec->pcm[n] statically.
For dyn_pcm_assign, per_pin->pcm will assigned to spec->pcm[n]
when monitor is hotplugged.
Build Jack
----------
- dyn_pcm_assign
Will not use hda_jack but use snd_jack in spec->pcm_rec[pcm_idx].jack directly.
- !dyn_pcm_assign
Use hda_jack and assign spec->pcm_rec[pcm_idx].jack = jack->jack statically.
Unsolicited Event Enabling
--------------------------
Enable unsolicited event if !acomp.
Monitor Hotplug Event Handling
------------------------------
- acomp
pin_eld_notify() -> check_presence_and_report() -> hdmi_present_sense() ->
sync_eld_via_acomp().
Use directly snd_jack_report() on spec->pcm_rec[pcm_idx].jack for
both dyn_pcm_assign and !dyn_pcm_assign
- !acomp
Hdmi_unsol_event() -> hdmi_intrinsic_event() -> check_presence_and_report() ->
hdmi_present_sense() -> hdmi_prepsent_sense_via_verbs()
Use directly snd_jack_report() on spec->pcm_rec[pcm_idx].jack for dyn_pcm_assign.
Use hda_jack mechanism to handle jack events.
Others to be added later
========================
......@@ -34,6 +34,7 @@ struct ssc_device *ssc_request(unsigned int ssc_num)
if (ssc->pdev->dev.of_node) {
if (of_alias_get_id(ssc->pdev->dev.of_node, "ssc")
== ssc_num) {
ssc->pdev->id = ssc_num;
ssc_valid = 1;
break;
}
......
......@@ -403,6 +403,18 @@ static inline int drm_eld_size(const uint8_t *eld)
return DRM_ELD_HEADER_BLOCK_SIZE + eld[DRM_ELD_BASELINE_ELD_LEN] * 4;
}
/**
* drm_eld_get_conn_type - Get device type hdmi/dp connected
* @eld: pointer to an ELD memory structure
*
* The caller need to use %DRM_ELD_CONN_TYPE_HDMI or %DRM_ELD_CONN_TYPE_DP to
* identify the display type connected.
*/
static inline u8 drm_eld_get_conn_type(const uint8_t *eld)
{
return eld[DRM_ELD_SAD_COUNT_CONN_TYPE] & DRM_ELD_CONN_TYPE_MASK;
}
struct edid *drm_do_get_edid(struct drm_connector *connector,
int (*get_edid_block)(void *data, u8 *buf, unsigned int block,
size_t len),
......
/*
* Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961/ADAU1781/ADAU1781 codecs
* Driver for ADAU1361/ADAU1461/ADAU1761/ADAU1961/ADAU1381/ADAU1781 codecs
*
* Copyright 2011-2014 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
......
/*
* For multichannel support
*/
#ifndef __SOUND_HDA_CHMAP_H
#define __SOUND_HDA_CHMAP_H
#include <sound/pcm.h>
#include <sound/hdaudio.h>
#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80
struct hdac_cea_channel_speaker_allocation {
int ca_index;
int speakers[8];
/* derived values, just for convenience */
int channels;
int spk_mask;
};
struct hdac_chmap;
struct hdac_chmap_ops {
/*
* Helpers for producing the channel map TLVs. These can be overridden
* for devices that have non-standard mapping requirements.
*/
int (*chmap_cea_alloc_validate_get_type)(struct hdac_chmap *chmap,
struct hdac_cea_channel_speaker_allocation *cap, int channels);
void (*cea_alloc_to_tlv_chmap)(struct hdac_chmap *hchmap,
struct hdac_cea_channel_speaker_allocation *cap,
unsigned int *chmap, int channels);
/* check that the user-given chmap is supported */
int (*chmap_validate)(struct hdac_chmap *hchmap, int ca,
int channels, unsigned char *chmap);
void (*get_chmap)(struct hdac_device *hdac, int pcm_idx,
unsigned char *chmap);
void (*set_chmap)(struct hdac_device *hdac, int pcm_idx,
unsigned char *chmap, int prepared);
bool (*is_pcm_attached)(struct hdac_device *hdac, int pcm_idx);
/* get and set channel assigned to each HDMI ASP (audio sample packet) slot */
int (*pin_get_slot_channel)(struct hdac_device *codec,
hda_nid_t pin_nid, int asp_slot);
int (*pin_set_slot_channel)(struct hdac_device *codec,
hda_nid_t pin_nid, int asp_slot, int channel);
void (*set_channel_count)(struct hdac_device *codec,
hda_nid_t cvt_nid, int chs);
};
struct hdac_chmap {
unsigned int channels_max; /* max over all cvts */
struct hdac_chmap_ops ops;
struct hdac_device *hdac;
};
void snd_hdac_register_chmap_ops(struct hdac_device *hdac,
struct hdac_chmap *chmap);
int snd_hdac_channel_allocation(struct hdac_device *hdac, int spk_alloc,
int channels, bool chmap_set,
bool non_pcm, unsigned char *map);
int snd_hdac_get_active_channels(int ca);
void snd_hdac_setup_channel_mapping(struct hdac_chmap *chmap,
hda_nid_t pin_nid, bool non_pcm, int ca,
int channels, unsigned char *map,
bool chmap_set);
void snd_hdac_print_channel_allocation(int spk_alloc, char *buf, int buflen);
struct hdac_cea_channel_speaker_allocation *snd_hdac_get_ch_alloc_from_ca(int ca);
int snd_hdac_chmap_to_spk_mask(unsigned char c);
int snd_hdac_spk_to_chmap(int spk);
int snd_hdac_add_chmap_ctls(struct snd_pcm *pcm, int pcm_idx,
struct hdac_chmap *chmap);
#endif /* __SOUND_HDA_CHMAP_H */
......@@ -168,11 +168,13 @@ int snd_hdac_power_up(struct hdac_device *codec);
int snd_hdac_power_down(struct hdac_device *codec);
int snd_hdac_power_up_pm(struct hdac_device *codec);
int snd_hdac_power_down_pm(struct hdac_device *codec);
int snd_hdac_keep_power_up(struct hdac_device *codec);
#else
static inline int snd_hdac_power_up(struct hdac_device *codec) { return 0; }
static inline int snd_hdac_power_down(struct hdac_device *codec) { return 0; }
static inline int snd_hdac_power_up_pm(struct hdac_device *codec) { return 0; }
static inline int snd_hdac_power_down_pm(struct hdac_device *codec) { return 0; }
static inline int snd_hdac_keep_power_up(struct hdac_device *codec) { return 0; }
#endif
/*
......
......@@ -72,14 +72,16 @@ enum snd_jack_types {
#define SND_JACK_SWITCH_TYPES 6
struct snd_jack {
struct input_dev *input_dev;
struct list_head kctl_list;
struct snd_card *card;
const char *id;
#ifdef CONFIG_SND_JACK_INPUT_DEV
struct input_dev *input_dev;
int registered;
int type;
const char *id;
char name[100];
unsigned int key[6]; /* Keep in sync with definitions above */
#endif /* CONFIG_SND_JACK_INPUT_DEV */
void *private_data;
void (*private_free)(struct snd_jack *);
};
......@@ -89,10 +91,11 @@ struct snd_jack {
int snd_jack_new(struct snd_card *card, const char *id, int type,
struct snd_jack **jack, bool initial_kctl, bool phantom_jack);
int snd_jack_add_new_kctl(struct snd_jack *jack, const char * name, int mask);
#ifdef CONFIG_SND_JACK_INPUT_DEV
void snd_jack_set_parent(struct snd_jack *jack, struct device *parent);
int snd_jack_set_key(struct snd_jack *jack, enum snd_jack_types type,
int keytype);
#endif
void snd_jack_report(struct snd_jack *jack, int status);
#else
......@@ -107,6 +110,13 @@ static inline int snd_jack_add_new_kctl(struct snd_jack *jack, const char * name
return 0;
}
static inline void snd_jack_report(struct snd_jack *jack, int status)
{
}
#endif
#if !defined(CONFIG_SND_JACK) || !defined(CONFIG_SND_JACK_INPUT_DEV)
static inline void snd_jack_set_parent(struct snd_jack *jack,
struct device *parent)
{
......@@ -118,11 +128,6 @@ static inline int snd_jack_set_key(struct snd_jack *jack,
{
return 0;
}
static inline void snd_jack_report(struct snd_jack *jack, int status)
{
}
#endif
#endif /* !CONFIG_SND_JACK || !CONFIG_SND_JACK_INPUT_DEV */
#endif
......@@ -1093,6 +1093,8 @@ unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate);
unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit);
unsigned int snd_pcm_rate_mask_intersect(unsigned int rates_a,
unsigned int rates_b);
unsigned int snd_pcm_rate_range_to_bits(unsigned int rate_min,
unsigned int rate_max);
/**
* snd_pcm_set_runtime_buffer - Set the PCM runtime buffer
......
......@@ -56,12 +56,6 @@ struct snd_soc_dobj_widget {
unsigned int kcontrol_enum:1; /* this widget is an enum kcontrol */
};
/* dynamic PCM DAI object */
struct snd_soc_dobj_pcm_dai {
struct snd_soc_tplg_pcm_dai *pd;
unsigned int count;
};
/* generic dynamic object - all dynamic objects belong to this struct */
struct snd_soc_dobj {
enum snd_soc_dobj_type type;
......@@ -71,7 +65,6 @@ struct snd_soc_dobj {
union {
struct snd_soc_dobj_control control;
struct snd_soc_dobj_widget widget;
struct snd_soc_dobj_pcm_dai pcm_dai;
};
void *private; /* core does not touch this */
};
......@@ -126,10 +119,16 @@ struct snd_soc_tplg_ops {
int (*widget_unload)(struct snd_soc_component *,
struct snd_soc_dobj *);
/* FE - used for any driver specific init */
int (*pcm_dai_load)(struct snd_soc_component *,
struct snd_soc_tplg_pcm_dai *pcm_dai, int num_fe);
int (*pcm_dai_unload)(struct snd_soc_component *,
/* FE DAI - used for any driver specific init */
int (*dai_load)(struct snd_soc_component *,
struct snd_soc_dai_driver *dai_drv);
int (*dai_unload)(struct snd_soc_component *,
struct snd_soc_dobj *);
/* DAI link - used for any driver specific init */
int (*link_load)(struct snd_soc_component *,
struct snd_soc_dai_link *link);
int (*link_unload)(struct snd_soc_component *,
struct snd_soc_dobj *);
/* callback to handle vendor bespoke data */
......
......@@ -27,7 +27,6 @@
#include <sound/compress_driver.h>
#include <sound/control.h>
#include <sound/ac97_codec.h>
#include <sound/soc-topology.h>
/*
* Convenience kcontrol builders
......@@ -404,6 +403,7 @@ struct snd_soc_jack_zone;
struct snd_soc_jack_pin;
#include <sound/soc-dapm.h>
#include <sound/soc-dpcm.h>
#include <sound/soc-topology.h>
struct snd_soc_jack_gpio;
......
......@@ -25,7 +25,7 @@
#include <sound/asound.h>
/** version of the sequencer */
#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION (1, 0, 1)
#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 2)
/**
* definition of sequencer event types
......@@ -357,7 +357,9 @@ struct snd_seq_client_info {
unsigned char event_filter[32]; /* event filter bitmap */
int num_ports; /* RO: number of ports */
int event_lost; /* number of lost events */
char reserved[64]; /* for future use */
int card; /* RO: card number[kernel] */
int pid; /* RO: pid[user] */
char reserved[56]; /* for future use */
};
......@@ -594,14 +596,8 @@ struct snd_seq_query_subs {
#define SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS _IOWR('S', 0x40, struct snd_seq_queue_status)
#define SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO _IOWR('S', 0x41, struct snd_seq_queue_tempo)
#define SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO _IOW ('S', 0x42, struct snd_seq_queue_tempo)
#define SNDRV_SEQ_IOCTL_GET_QUEUE_OWNER _IOWR('S', 0x43, struct snd_seq_queue_owner)
#define SNDRV_SEQ_IOCTL_SET_QUEUE_OWNER _IOW ('S', 0x44, struct snd_seq_queue_owner)
#define SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER _IOWR('S', 0x45, struct snd_seq_queue_timer)
#define SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER _IOW ('S', 0x46, struct snd_seq_queue_timer)
/* XXX
#define SNDRV_SEQ_IOCTL_GET_QUEUE_SYNC _IOWR('S', 0x53, struct snd_seq_queue_sync)
#define SNDRV_SEQ_IOCTL_SET_QUEUE_SYNC _IOW ('S', 0x54, struct snd_seq_queue_sync)
*/
#define SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT _IOWR('S', 0x49, struct snd_seq_queue_client)
#define SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT _IOW ('S', 0x4a, struct snd_seq_queue_client)
#define SNDRV_SEQ_IOCTL_GET_CLIENT_POOL _IOWR('S', 0x4b, struct snd_seq_client_pool)
......
......@@ -23,7 +23,11 @@
#ifndef _UAPI__SOUND_ASOUND_H
#define _UAPI__SOUND_ASOUND_H
#if defined(__KERNEL__) || defined(__linux__)
#include <linux/types.h>
#else
#include <sys/ioctl.h>
#endif
#ifndef __KERNEL__
#include <stdlib.h>
......
......@@ -24,12 +24,15 @@ config SND_RAWMIDI
config SND_COMPRESS_OFFLOAD
tristate
# To be effective this also requires INPUT - users should say:
# select SND_JACK if INPUT=y || INPUT=SND
# to avoid having to force INPUT on.
config SND_JACK
bool
# enable input device support in jack layer
config SND_JACK_INPUT_DEV
bool
depends on SND_JACK
default y if INPUT=y || INPUT=SND
config SND_SEQUENCER
tristate "Sequencer support"
select SND_TIMER
......
......@@ -69,11 +69,14 @@ struct snd_compr_file {
/*
* a note on stream states used:
* we use follwing states in the compressed core
* we use following states in the compressed core
* SNDRV_PCM_STATE_OPEN: When stream has been opened.
* SNDRV_PCM_STATE_SETUP: When stream has been initialized. This is done by
* calling SNDRV_COMPRESS_SET_PARAMS. running streams will come to this
* calling SNDRV_COMPRESS_SET_PARAMS. Running streams will come to this
* state at stop by calling SNDRV_COMPRESS_STOP, or at end of drain.
* SNDRV_PCM_STATE_PREPARED: When a stream has been written to (for
* playback only). User after setting up stream writes the data buffer
* before starting the stream.
* SNDRV_PCM_STATE_RUNNING: When stream has been started and is
* decoding/encoding and rendering/capturing data.
* SNDRV_PCM_STATE_DRAINING: When stream is draining current data. This is done
......@@ -286,6 +289,7 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf,
mutex_lock(&stream->device->lock);
/* write is allowed when stream is running or has been steup */
if (stream->runtime->state != SNDRV_PCM_STATE_SETUP &&
stream->runtime->state != SNDRV_PCM_STATE_PREPARED &&
stream->runtime->state != SNDRV_PCM_STATE_RUNNING) {
mutex_unlock(&stream->device->lock);
return -EBADFD;
......@@ -700,7 +704,7 @@ static int snd_compress_wait_for_drain(struct snd_compr_stream *stream)
/*
* We are called with lock held. So drop the lock while we wait for
* drain complete notfication from the driver
* drain complete notification from the driver
*
* It is expected that driver will notify the drain completion and then
* stream will be moved to SETUP state, even if draining resulted in an
......@@ -755,7 +759,7 @@ static int snd_compr_next_track(struct snd_compr_stream *stream)
if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
return -EPERM;
/* you can signal next track isf this is intended to be a gapless stream
/* you can signal next track if this is intended to be a gapless stream
* and current track metadata is set
*/
if (stream->metadata_set == false)
......
......@@ -196,7 +196,7 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
kctl = snd_ctl_find_id(card, id);
if (! kctl) {
up_read(&card->controls_rwsem);
return -ENXIO;
return -ENOENT;
}
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (info == NULL) {
......
......@@ -32,6 +32,7 @@ struct snd_jack_kctl {
unsigned int mask_bits; /* only masked status bits are reported via kctl */
};
#ifdef CONFIG_SND_JACK_INPUT_DEV
static int jack_switch_types[SND_JACK_SWITCH_TYPES] = {
SW_HEADPHONE_INSERT,
SW_MICROPHONE_INSERT,
......@@ -40,9 +41,11 @@ static int jack_switch_types[SND_JACK_SWITCH_TYPES] = {
SW_VIDEOOUT_INSERT,
SW_LINEIN_INSERT,
};
#endif /* CONFIG_SND_JACK_INPUT_DEV */
static int snd_jack_dev_disconnect(struct snd_device *device)
{
#ifdef CONFIG_SND_JACK_INPUT_DEV
struct snd_jack *jack = device->device_data;
if (!jack->input_dev)
......@@ -55,6 +58,7 @@ static int snd_jack_dev_disconnect(struct snd_device *device)
else
input_free_device(jack->input_dev);
jack->input_dev = NULL;
#endif /* CONFIG_SND_JACK_INPUT_DEV */
return 0;
}
......@@ -79,6 +83,7 @@ static int snd_jack_dev_free(struct snd_device *device)
return 0;
}
#ifdef CONFIG_SND_JACK_INPUT_DEV
static int snd_jack_dev_register(struct snd_device *device)
{
struct snd_jack *jack = device->device_data;
......@@ -116,6 +121,7 @@ static int snd_jack_dev_register(struct snd_device *device)
return err;
}
#endif /* CONFIG_SND_JACK_INPUT_DEV */
static void snd_jack_kctl_private_free(struct snd_kcontrol *kctl)
{
......@@ -209,11 +215,12 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
struct snd_jack *jack;
struct snd_jack_kctl *jack_kctl = NULL;
int err;
int i;
static struct snd_device_ops ops = {
.dev_free = snd_jack_dev_free,
#ifdef CONFIG_SND_JACK_INPUT_DEV
.dev_register = snd_jack_dev_register,
.dev_disconnect = snd_jack_dev_disconnect,
#endif /* CONFIG_SND_JACK_INPUT_DEV */
};
if (initial_kctl) {
......@@ -230,6 +237,9 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
/* don't creat input device for phantom jack */
if (!phantom_jack) {
#ifdef CONFIG_SND_JACK_INPUT_DEV
int i;
jack->input_dev = input_allocate_device();
if (jack->input_dev == NULL) {
err = -ENOMEM;
......@@ -245,6 +255,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
input_set_capability(jack->input_dev, EV_SW,
jack_switch_types[i]);
#endif /* CONFIG_SND_JACK_INPUT_DEV */
}
err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops);
......@@ -262,13 +273,16 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
return 0;
fail_input:
#ifdef CONFIG_SND_JACK_INPUT_DEV
input_free_device(jack->input_dev);
#endif
kfree(jack->id);
kfree(jack);
return err;
}
EXPORT_SYMBOL(snd_jack_new);
#ifdef CONFIG_SND_JACK_INPUT_DEV
/**
* snd_jack_set_parent - Set the parent device for a jack
*
......@@ -326,10 +340,10 @@ int snd_jack_set_key(struct snd_jack *jack, enum snd_jack_types type,
jack->type |= type;
jack->key[key] = keytype;
return 0;
}
EXPORT_SYMBOL(snd_jack_set_key);
#endif /* CONFIG_SND_JACK_INPUT_DEV */
/**
* snd_jack_report - Report the current status of a jack
......@@ -340,7 +354,9 @@ EXPORT_SYMBOL(snd_jack_set_key);
void snd_jack_report(struct snd_jack *jack, int status)
{
struct snd_jack_kctl *jack_kctl;
#ifdef CONFIG_SND_JACK_INPUT_DEV
int i;
#endif
if (!jack)
return;
......@@ -349,6 +365,7 @@ void snd_jack_report(struct snd_jack *jack, int status)
snd_kctl_jack_report(jack->card, jack_kctl->kctl,
status & jack_kctl->mask_bits);
#ifdef CONFIG_SND_JACK_INPUT_DEV
if (!jack->input_dev)
return;
......@@ -369,6 +386,6 @@ void snd_jack_report(struct snd_jack *jack, int status)
}
input_sync(jack->input_dev);
#endif /* CONFIG_SND_JACK_INPUT_DEV */
}
EXPORT_SYMBOL(snd_jack_report);
......@@ -322,7 +322,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
char name[16];
snd_pcm_debug_name(substream, name, sizeof(name));
pcm_err(substream->pcm,
"BUG: %s, pos = %ld, buffer size = %ld, period size = %ld\n",
"invalid position: %s, pos = %ld, buffer size = %ld, period size = %ld\n",
name, pos, runtime->buffer_size,
runtime->period_size);
}
......
......@@ -565,3 +565,33 @@ unsigned int snd_pcm_rate_mask_intersect(unsigned int rates_a,
return rates_a & rates_b;
}
EXPORT_SYMBOL_GPL(snd_pcm_rate_mask_intersect);
/**
* snd_pcm_rate_range_to_bits - converts rate range to SNDRV_PCM_RATE_xxx bit
* @rate_min: the minimum sample rate
* @rate_max: the maximum sample rate
*
* This function has an implicit assumption: the rates in the given range have
* only the pre-defined rates like 44100 or 16000.
*
* Return: The SNDRV_PCM_RATE_xxx flag that corresponds to the given rate range,
* or SNDRV_PCM_RATE_KNOT for an unknown range.
*/
unsigned int snd_pcm_rate_range_to_bits(unsigned int rate_min,
unsigned int rate_max)
{
unsigned int rates = 0;
int i;
for (i = 0; i < snd_pcm_known_rates.count; i++) {
if (snd_pcm_known_rates.list[i] >= rate_min
&& snd_pcm_known_rates.list[i] <= rate_max)
rates |= 1 << i;
}
if (!rates)
rates = SNDRV_PCM_RATE_KNOT;
return rates;
}
EXPORT_SYMBOL_GPL(snd_pcm_rate_range_to_bits);
......@@ -364,6 +364,7 @@ static int snd_seq_open(struct inode *inode, struct file *file)
/* fill client data */
user->file = file;
sprintf(client->name, "Client-%d", c);
client->data.user.owner = get_pid(task_pid(current));
/* make others aware this new client */
snd_seq_system_client_ev_client_start(c);
......@@ -380,6 +381,7 @@ static int snd_seq_release(struct inode *inode, struct file *file)
seq_free_client(client);
if (client->data.user.fifo)
snd_seq_fifo_delete(&client->data.user.fifo);
put_pid(client->data.user.owner);
kfree(client);
}
......@@ -1197,6 +1199,17 @@ static void get_client_info(struct snd_seq_client *cptr,
info->event_lost = cptr->event_lost;
memcpy(info->event_filter, cptr->event_filter, 32);
info->num_ports = cptr->num_ports;
if (cptr->type == USER_CLIENT)
info->pid = pid_vnr(cptr->data.user.owner);
else
info->pid = -1;
if (cptr->type == KERNEL_CLIENT)
info->card = cptr->data.kernel.card ? cptr->data.kernel.card->number : -1;
else
info->card = -1;
memset(info->reserved, 0, sizeof(info->reserved));
}
......@@ -2271,6 +2284,7 @@ int snd_seq_create_kernel_client(struct snd_card *card, int client_index,
client->accept_input = 1;
client->accept_output = 1;
client->data.kernel.card = card;
va_start(args, name_fmt);
vsnprintf(client->name, sizeof(client->name), name_fmt, args);
......
......@@ -33,6 +33,7 @@
struct snd_seq_user_client {
struct file *file; /* file struct of client */
/* ... */
struct pid *owner;
/* fifo */
struct snd_seq_fifo *fifo; /* queue for incoming events */
......@@ -41,6 +42,7 @@ struct snd_seq_user_client {
struct snd_seq_kernel_client {
/* ... */
struct snd_card *card;
};
......
This diff is collapsed.
......@@ -65,8 +65,6 @@ struct mts64 {
struct snd_card *card;
struct snd_rawmidi *rmidi;
struct pardevice *pardev;
int pardev_claimed;
int open_count;
int current_midi_output_port;
int current_midi_input_port;
......@@ -850,30 +848,6 @@ static void snd_mts64_interrupt(void *private)
spin_unlock(&mts->lock);
}
static int snd_mts64_probe_port(struct parport *p)
{
struct pardevice *pardev;
int res;
pardev = parport_register_device(p, DRIVER_NAME,
NULL, NULL, NULL,
0, NULL);
if (!pardev)
return -EIO;
if (parport_claim(pardev)) {
parport_unregister_device(pardev);
return -EIO;
}
res = mts64_probe(p);
parport_release(pardev);
parport_unregister_device(pardev);
return res;
}
static void snd_mts64_attach(struct parport *p)
{
struct platform_device *device;
......@@ -907,10 +881,20 @@ static void snd_mts64_detach(struct parport *p)
/* nothing to do here */
}
static int snd_mts64_dev_probe(struct pardevice *pardev)
{
if (strcmp(pardev->name, DRIVER_NAME))
return -ENODEV;
return 0;
}
static struct parport_driver mts64_parport_driver = {
.name = "mts64",
.attach = snd_mts64_attach,
.detach = snd_mts64_detach
.name = "mts64",
.probe = snd_mts64_dev_probe,
.match_port = snd_mts64_attach,
.detach = snd_mts64_detach,
.devmodel = true,
};
/*********************************************************************
......@@ -922,8 +906,7 @@ static void snd_mts64_card_private_free(struct snd_card *card)
struct pardevice *pardev = mts->pardev;
if (pardev) {
if (mts->pardev_claimed)
parport_release(pardev);
parport_release(pardev);
parport_unregister_device(pardev);
}
......@@ -938,6 +921,12 @@ static int snd_mts64_probe(struct platform_device *pdev)
struct snd_card *card = NULL;
struct mts64 *mts = NULL;
int err;
struct pardev_cb mts64_cb = {
.preempt = NULL,
.wakeup = NULL,
.irq_func = snd_mts64_interrupt, /* ISR */
.flags = PARPORT_DEV_EXCL, /* flags */
};
p = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
......@@ -946,8 +935,6 @@ static int snd_mts64_probe(struct platform_device *pdev)
return -ENODEV;
if (!enable[dev])
return -ENOENT;
if ((err = snd_mts64_probe_port(p)) < 0)
return err;
err = snd_card_new(&pdev->dev, index[dev], id[dev], THIS_MODULE,
0, &card);
......@@ -960,40 +947,42 @@ static int snd_mts64_probe(struct platform_device *pdev)
sprintf(card->longname, "%s at 0x%lx, irq %i",
card->shortname, p->base, p->irq);
pardev = parport_register_device(p, /* port */
DRIVER_NAME, /* name */
NULL, /* preempt */
NULL, /* wakeup */
snd_mts64_interrupt, /* ISR */
PARPORT_DEV_EXCL, /* flags */
(void *)card); /* private */
if (pardev == NULL) {
mts64_cb.private = card; /* private */
pardev = parport_register_dev_model(p, /* port */
DRIVER_NAME, /* name */
&mts64_cb, /* callbacks */
pdev->id); /* device number */
if (!pardev) {
snd_printd("Cannot register pardevice\n");
err = -EIO;
goto __err;
}
/* claim parport */
if (parport_claim(pardev)) {
snd_printd("Cannot claim parport 0x%lx\n", pardev->port->base);
err = -EIO;
goto free_pardev;
}
if ((err = snd_mts64_create(card, pardev, &mts)) < 0) {
snd_printd("Cannot create main component\n");
parport_unregister_device(pardev);
goto __err;
goto release_pardev;
}
card->private_data = mts;
card->private_free = snd_mts64_card_private_free;
err = mts64_probe(p);
if (err) {
err = -EIO;
goto __err;
}
if ((err = snd_mts64_rawmidi_create(card)) < 0) {
snd_printd("Creating Rawmidi component failed\n");
goto __err;
}
/* claim parport */
if (parport_claim(pardev)) {
snd_printd("Cannot claim parport 0x%lx\n", pardev->port->base);
err = -EIO;
goto __err;
}
mts->pardev_claimed = 1;
/* init device */
if ((err = mts64_device_init(p)) < 0)
goto __err;
......@@ -1009,6 +998,10 @@ static int snd_mts64_probe(struct platform_device *pdev)
snd_printk(KERN_INFO "ESI Miditerminal 4140 on 0x%lx\n", p->base);
return 0;
release_pardev:
parport_release(pardev);
free_pardev:
parport_unregister_device(pardev);
__err:
snd_card_free(card);
return err;
......@@ -1024,7 +1017,6 @@ static int snd_mts64_remove(struct platform_device *pdev)
return 0;
}
static struct platform_driver snd_mts64_driver = {
.probe = snd_mts64_probe,
.remove = snd_mts64_remove,
......
......@@ -83,8 +83,6 @@ struct portman {
struct snd_card *card;
struct snd_rawmidi *rmidi;
struct pardevice *pardev;
int pardev_claimed;
int open_count;
int mode[PORTMAN_NUM_INPUT_PORTS];
struct snd_rawmidi_substream *midi_input[PORTMAN_NUM_INPUT_PORTS];
......@@ -648,30 +646,6 @@ static void snd_portman_interrupt(void *userdata)
spin_unlock(&pm->reg_lock);
}
static int snd_portman_probe_port(struct parport *p)
{
struct pardevice *pardev;
int res;
pardev = parport_register_device(p, DRIVER_NAME,
NULL, NULL, NULL,
0, NULL);
if (!pardev)
return -EIO;
if (parport_claim(pardev)) {
parport_unregister_device(pardev);
return -EIO;
}
res = portman_probe(p);
parport_release(pardev);
parport_unregister_device(pardev);
return res ? -EIO : 0;
}
static void snd_portman_attach(struct parport *p)
{
struct platform_device *device;
......@@ -705,10 +679,20 @@ static void snd_portman_detach(struct parport *p)
/* nothing to do here */
}
static int snd_portman_dev_probe(struct pardevice *pardev)
{
if (strcmp(pardev->name, DRIVER_NAME))
return -ENODEV;
return 0;
}
static struct parport_driver portman_parport_driver = {
.name = "portman2x4",
.attach = snd_portman_attach,
.detach = snd_portman_detach
.name = "portman2x4",
.probe = snd_portman_dev_probe,
.match_port = snd_portman_attach,
.detach = snd_portman_detach,
.devmodel = true,
};
/*********************************************************************
......@@ -720,8 +704,7 @@ static void snd_portman_card_private_free(struct snd_card *card)
struct pardevice *pardev = pm->pardev;
if (pardev) {
if (pm->pardev_claimed)
parport_release(pardev);
parport_release(pardev);
parport_unregister_device(pardev);
}
......@@ -736,6 +719,12 @@ static int snd_portman_probe(struct platform_device *pdev)
struct snd_card *card = NULL;
struct portman *pm = NULL;
int err;
struct pardev_cb portman_cb = {
.preempt = NULL,
.wakeup = NULL,
.irq_func = snd_portman_interrupt, /* ISR */
.flags = PARPORT_DEV_EXCL, /* flags */
};
p = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
......@@ -745,9 +734,6 @@ static int snd_portman_probe(struct platform_device *pdev)
if (!enable[dev])
return -ENOENT;
if ((err = snd_portman_probe_port(p)) < 0)
return err;
err = snd_card_new(&pdev->dev, index[dev], id[dev], THIS_MODULE,
0, &card);
if (err < 0) {
......@@ -759,40 +745,42 @@ static int snd_portman_probe(struct platform_device *pdev)
sprintf(card->longname, "%s at 0x%lx, irq %i",
card->shortname, p->base, p->irq);
pardev = parport_register_device(p, /* port */
DRIVER_NAME, /* name */
NULL, /* preempt */
NULL, /* wakeup */
snd_portman_interrupt, /* ISR */
PARPORT_DEV_EXCL, /* flags */
(void *)card); /* private */
portman_cb.private = card; /* private */
pardev = parport_register_dev_model(p, /* port */
DRIVER_NAME, /* name */
&portman_cb, /* callbacks */
pdev->id); /* device number */
if (pardev == NULL) {
snd_printd("Cannot register pardevice\n");
err = -EIO;
goto __err;
}
/* claim parport */
if (parport_claim(pardev)) {
snd_printd("Cannot claim parport 0x%lx\n", pardev->port->base);
err = -EIO;
goto free_pardev;
}
if ((err = portman_create(card, pardev, &pm)) < 0) {
snd_printd("Cannot create main component\n");
parport_unregister_device(pardev);
goto __err;
goto release_pardev;
}
card->private_data = pm;
card->private_free = snd_portman_card_private_free;
err = portman_probe(p);
if (err) {
err = -EIO;
goto __err;
}
if ((err = snd_portman_rawmidi_create(card)) < 0) {
snd_printd("Creating Rawmidi component failed\n");
goto __err;
}
/* claim parport */
if (parport_claim(pardev)) {
snd_printd("Cannot claim parport 0x%lx\n", pardev->port->base);
err = -EIO;
goto __err;
}
pm->pardev_claimed = 1;
/* init device */
if ((err = portman_device_init(pm)) < 0)
goto __err;
......@@ -808,6 +796,10 @@ static int snd_portman_probe(struct platform_device *pdev)
snd_printk(KERN_INFO "Portman 2x4 on 0x%lx\n", p->base);
return 0;
release_pardev:
parport_release(pardev);
free_pardev:
parport_unregister_device(pardev);
__err:
snd_card_free(card);
return err;
......
......@@ -300,6 +300,22 @@ bebob_probe(struct fw_unit *unit,
return err;
}
/*
* This driver doesn't update streams in bus reset handler.
*
* DM1000/ DM1100/DM1500 chipsets with BeBoB firmware transfer packets with
* discontinued counter at bus reset. This discontinuity is immediately
* detected in packet streaming layer, then it sets XRUN to PCM substream.
*
* ALSA PCM applications can know the XRUN by getting -EPIPE from PCM operation.
* Then, they can recover the PCM substream by executing ioctl(2) with
* SNDRV_PCM_IOCTL_PREPARE. 'struct snd_pcm_ops.prepare' is called and drivers
* restart packet streaming.
*
* The above processing may be executed before this bus-reset handler is
* executed. When this handler updates streams with current isochronous
* channels, the streams already have the current ones.
*/
static void
bebob_update(struct fw_unit *unit)
{
......@@ -309,7 +325,6 @@ bebob_update(struct fw_unit *unit)
return;
fcp_bus_reset(bebob->unit);
snd_bebob_stream_update_duplex(bebob);
if (bebob->deferred_registration) {
if (snd_card_register(bebob->card) < 0) {
......@@ -327,10 +342,6 @@ static void bebob_remove(struct fw_unit *unit)
if (bebob == NULL)
return;
/* Awake bus-reset waiters. */
if (!completion_done(&bebob->bus_reset))
complete_all(&bebob->bus_reset);
/* No need to wait for releasing card object in this context. */
snd_card_free_when_closed(bebob->card);
}
......
......@@ -88,8 +88,6 @@ struct snd_bebob {
unsigned int midi_input_ports;
unsigned int midi_output_ports;
/* for bus reset quirk */
struct completion bus_reset;
bool connected;
struct amdtp_stream *master;
......@@ -97,7 +95,7 @@ struct snd_bebob {
struct amdtp_stream rx_stream;
struct cmp_connection out_conn;
struct cmp_connection in_conn;
atomic_t substreams_counter;
unsigned int substreams_counter;
struct snd_bebob_stream_formation
tx_stream_formations[SND_BEBOB_STRM_FMT_ENTRIES];
......@@ -219,7 +217,6 @@ int snd_bebob_stream_discover(struct snd_bebob *bebob);
int snd_bebob_stream_init_duplex(struct snd_bebob *bebob);
int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate);
void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob);
void snd_bebob_stream_update_duplex(struct snd_bebob *bebob);
void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob);
void snd_bebob_stream_lock_changed(struct snd_bebob *bebob);
......
......@@ -17,8 +17,10 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream)
if (err < 0)
goto end;
atomic_inc(&bebob->substreams_counter);
mutex_lock(&bebob->mutex);
bebob->substreams_counter++;
err = snd_bebob_stream_start_duplex(bebob, 0);
mutex_unlock(&bebob->mutex);
if (err < 0)
snd_bebob_stream_lock_release(bebob);
end:
......@@ -34,8 +36,10 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream)
if (err < 0)
goto end;
atomic_inc(&bebob->substreams_counter);
mutex_lock(&bebob->mutex);
bebob->substreams_counter++;
err = snd_bebob_stream_start_duplex(bebob, 0);
mutex_unlock(&bebob->mutex);
if (err < 0)
snd_bebob_stream_lock_release(bebob);
end:
......@@ -46,8 +50,10 @@ static int midi_capture_close(struct snd_rawmidi_substream *substream)
{
struct snd_bebob *bebob = substream->rmidi->private_data;
atomic_dec(&bebob->substreams_counter);
mutex_lock(&bebob->mutex);
bebob->substreams_counter--;
snd_bebob_stream_stop_duplex(bebob);
mutex_unlock(&bebob->mutex);
snd_bebob_stream_lock_release(bebob);
return 0;
......@@ -57,8 +63,10 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream)
{
struct snd_bebob *bebob = substream->rmidi->private_data;
atomic_dec(&bebob->substreams_counter);
mutex_lock(&bebob->mutex);
bebob->substreams_counter--;
snd_bebob_stream_stop_duplex(bebob);
mutex_unlock(&bebob->mutex);
snd_bebob_stream_lock_release(bebob);
return 0;
......
......@@ -218,8 +218,11 @@ pcm_capture_hw_params(struct snd_pcm_substream *substream,
if (err < 0)
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
atomic_inc(&bebob->substreams_counter);
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
mutex_lock(&bebob->mutex);
bebob->substreams_counter++;
mutex_unlock(&bebob->mutex);
}
amdtp_am824_set_pcm_format(&bebob->tx_stream, params_format(hw_params));
......@@ -237,8 +240,11 @@ pcm_playback_hw_params(struct snd_pcm_substream *substream,
if (err < 0)
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
atomic_inc(&bebob->substreams_counter);
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
mutex_lock(&bebob->mutex);
bebob->substreams_counter++;
mutex_unlock(&bebob->mutex);
}
amdtp_am824_set_pcm_format(&bebob->rx_stream, params_format(hw_params));
......@@ -250,8 +256,11 @@ pcm_capture_hw_free(struct snd_pcm_substream *substream)
{
struct snd_bebob *bebob = substream->private_data;
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
atomic_dec(&bebob->substreams_counter);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) {
mutex_lock(&bebob->mutex);
bebob->substreams_counter--;
mutex_unlock(&bebob->mutex);
}
snd_bebob_stream_stop_duplex(bebob);
......@@ -262,8 +271,11 @@ pcm_playback_hw_free(struct snd_pcm_substream *substream)
{
struct snd_bebob *bebob = substream->private_data;
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
atomic_dec(&bebob->substreams_counter);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) {
mutex_lock(&bebob->mutex);
bebob->substreams_counter--;
mutex_unlock(&bebob->mutex);
}
snd_bebob_stream_stop_duplex(bebob);
......
......@@ -549,8 +549,7 @@ int snd_bebob_stream_init_duplex(struct snd_bebob *bebob)
destroy_both_connections(bebob);
goto end;
}
/* See comments in next function */
init_completion(&bebob->bus_reset);
bebob->tx_stream.flags |= CIP_SKIP_INIT_DBC_CHECK;
/*
......@@ -588,29 +587,10 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate)
struct amdtp_stream *master, *slave;
enum cip_flags sync_mode;
unsigned int curr_rate;
bool updated = false;
int err = 0;
/*
* Normal BeBoB firmware has a quirk at bus reset to transmits packets
* with discontinuous value in dbc field.
*
* This 'struct completion' is used to call .update() at first to update
* connections/streams. Next following codes handle streaming error.
*/
if (amdtp_streaming_error(&bebob->tx_stream)) {
if (completion_done(&bebob->bus_reset))
reinit_completion(&bebob->bus_reset);
updated = (wait_for_completion_interruptible_timeout(
&bebob->bus_reset,
msecs_to_jiffies(FW_ISO_RESOURCE_DELAY)) > 0);
}
mutex_lock(&bebob->mutex);
/* Need no substreams */
if (atomic_read(&bebob->substreams_counter) == 0)
if (bebob->substreams_counter == 0)
goto end;
err = get_sync_mode(bebob, &sync_mode);
......@@ -642,8 +622,7 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate)
amdtp_stream_stop(master);
if (amdtp_streaming_error(slave))
amdtp_stream_stop(slave);
if (!updated &&
!amdtp_stream_running(master) && !amdtp_stream_running(slave))
if (!amdtp_stream_running(master) && !amdtp_stream_running(slave))
break_both_connections(bebob);
/* stop streams if rate is different */
......@@ -741,7 +720,6 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate)
}
}
end:
mutex_unlock(&bebob->mutex);
return err;
}
......@@ -757,9 +735,7 @@ void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob)
master = &bebob->tx_stream;
}
mutex_lock(&bebob->mutex);
if (atomic_read(&bebob->substreams_counter) == 0) {
if (bebob->substreams_counter == 0) {
amdtp_stream_pcm_abort(master);
amdtp_stream_stop(master);
......@@ -768,32 +744,6 @@ void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob)
break_both_connections(bebob);
}
mutex_unlock(&bebob->mutex);
}
void snd_bebob_stream_update_duplex(struct snd_bebob *bebob)
{
/* vs. XRUN recovery due to discontinuity at bus reset */
mutex_lock(&bebob->mutex);
if ((cmp_connection_update(&bebob->in_conn) < 0) ||
(cmp_connection_update(&bebob->out_conn) < 0)) {
amdtp_stream_pcm_abort(&bebob->rx_stream);
amdtp_stream_pcm_abort(&bebob->tx_stream);
amdtp_stream_stop(&bebob->rx_stream);
amdtp_stream_stop(&bebob->tx_stream);
break_both_connections(bebob);
} else {
amdtp_stream_update(&bebob->rx_stream);
amdtp_stream_update(&bebob->tx_stream);
}
/* wake up stream_start_duplex() */
if (!completion_done(&bebob->bus_reset))
complete_all(&bebob->bus_reset);
mutex_unlock(&bebob->mutex);
}
/*
......
......@@ -52,10 +52,10 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
spin_lock_irqsave(&dice->lock, flags);
if (up)
amdtp_am824_midi_trigger(&dice->tx_stream,
amdtp_am824_midi_trigger(&dice->tx_stream[0],
substrm->number, substrm);
else
amdtp_am824_midi_trigger(&dice->tx_stream,
amdtp_am824_midi_trigger(&dice->tx_stream[0],
substrm->number, NULL);
spin_unlock_irqrestore(&dice->lock, flags);
......@@ -69,10 +69,10 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
spin_lock_irqsave(&dice->lock, flags);
if (up)
amdtp_am824_midi_trigger(&dice->rx_stream,
amdtp_am824_midi_trigger(&dice->rx_stream[0],
substrm->number, substrm);
else
amdtp_am824_midi_trigger(&dice->rx_stream,
amdtp_am824_midi_trigger(&dice->rx_stream[0],
substrm->number, NULL);
spin_unlock_irqrestore(&dice->lock, flags);
......@@ -103,16 +103,27 @@ static void set_midi_substream_names(struct snd_dice *dice,
int snd_dice_create_midi(struct snd_dice *dice)
{
__be32 reg;
struct snd_rawmidi *rmidi;
struct snd_rawmidi_str *str;
unsigned int i, midi_in_ports, midi_out_ports;
unsigned int midi_in_ports, midi_out_ports;
int err;
midi_in_ports = midi_out_ports = 0;
for (i = 0; i < 3; i++) {
midi_in_ports = max(dice->tx_midi_ports[i], midi_in_ports);
midi_out_ports = max(dice->rx_midi_ports[i], midi_out_ports);
}
/*
* Use the number of MIDI conformant data channel at current sampling
* transfer frequency.
*/
err = snd_dice_transaction_read_tx(dice, TX_NUMBER_MIDI,
&reg, sizeof(reg));
if (err < 0)
return err;
midi_in_ports = be32_to_cpu(reg);
err = snd_dice_transaction_read_rx(dice, RX_NUMBER_MIDI,
&reg, sizeof(reg));
if (err < 0)
return err;
midi_out_ports = be32_to_cpu(reg);
if (midi_in_ports + midi_out_ports == 0)
return 0;
......
This diff is collapsed.
This diff is collapsed.
......@@ -9,8 +9,6 @@
#include "dice.h"
#define NOTIFICATION_TIMEOUT_MS (2 * MSEC_PER_SEC)
static u64 get_subaddr(struct snd_dice *dice, enum snd_dice_addr_type type,
u64 offset)
{
......@@ -62,54 +60,6 @@ static unsigned int get_clock_info(struct snd_dice *dice, __be32 *info)
info, 4);
}
static int set_clock_info(struct snd_dice *dice,
unsigned int rate, unsigned int source)
{
unsigned int i;
__be32 info;
u32 mask;
u32 clock;
int err;
err = get_clock_info(dice, &info);
if (err < 0)
return err;
clock = be32_to_cpu(info);
if (source != UINT_MAX) {
mask = CLOCK_SOURCE_MASK;
clock &= ~mask;
clock |= source;
}
if (rate != UINT_MAX) {
for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) {
if (snd_dice_rates[i] == rate)
break;
}
if (i == ARRAY_SIZE(snd_dice_rates))
return -EINVAL;
mask = CLOCK_RATE_MASK;
clock &= ~mask;
clock |= i << CLOCK_RATE_SHIFT;
}
info = cpu_to_be32(clock);
if (completion_done(&dice->clock_accepted))
reinit_completion(&dice->clock_accepted);
err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT,
&info, 4);
if (err < 0)
return err;
if (wait_for_completion_timeout(&dice->clock_accepted,
msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0)
return -ETIMEDOUT;
return 0;
}
int snd_dice_transaction_get_clock_source(struct snd_dice *dice,
unsigned int *source)
{
......@@ -143,10 +93,6 @@ int snd_dice_transaction_get_rate(struct snd_dice *dice, unsigned int *rate)
end:
return err;
}
int snd_dice_transaction_set_rate(struct snd_dice *dice, unsigned int rate)
{
return set_clock_info(dice, rate, UINT_MAX);
}
int snd_dice_transaction_set_enable(struct snd_dice *dice)
{
......@@ -210,7 +156,7 @@ static void dice_notification(struct fw_card *card, struct fw_request *request,
fw_send_response(card, request, RCODE_COMPLETE);
if (bits & NOTIFY_CLOCK_ACCEPTED)
if (bits & NOTIFY_LOCK_CHG)
complete(&dice->clock_accepted);
wake_up(&dice->hwdep_wait);
}
......
......@@ -13,6 +13,8 @@ MODULE_LICENSE("GPL v2");
#define OUI_WEISS 0x001c6a
#define OUI_LOUD 0x000ff2
#define OUI_FOCUSRITE 0x00130e
#define OUI_TCELECTRONIC 0x001486
#define DICE_CATEGORY_ID 0x04
#define WEISS_CATEGORY_ID 0x00
......@@ -20,6 +22,36 @@ MODULE_LICENSE("GPL v2");
#define PROBE_DELAY_MS (2 * MSEC_PER_SEC)
/*
* Some models support several isochronous channels, while these streams are not
* always available. In this case, add the model name to this list.
*/
static bool force_two_pcm_support(struct fw_unit *unit)
{
const char *const models[] = {
/* TC Electronic models. */
"StudioKonnekt48",
/* Focusrite models. */
"SAFFIRE_PRO_40",
"LIQUID_SAFFIRE_56",
"SAFFIRE_PRO_40_1",
};
char model[32];
unsigned int i;
int err;
err = fw_csr_string(unit->directory, CSR_MODEL, model, sizeof(model));
if (err < 0)
return false;
for (i = 0; i < ARRAY_SIZE(models); i++) {
if (strcmp(models[i], model) == 0)
break;
}
return i < ARRAY_SIZE(models);
}
static int check_dice_category(struct fw_unit *unit)
{
struct fw_device *device = fw_parent_device(unit);
......@@ -44,6 +76,12 @@ static int check_dice_category(struct fw_unit *unit)
break;
}
}
if (vendor == OUI_FOCUSRITE || vendor == OUI_TCELECTRONIC) {
if (force_two_pcm_support(unit))
return 0;
}
if (vendor == OUI_WEISS)
category = WEISS_CATEGORY_ID;
else if (vendor == OUI_LOUD)
......@@ -57,65 +95,10 @@ static int check_dice_category(struct fw_unit *unit)
return 0;
}
static int highest_supported_mode_rate(struct snd_dice *dice,
unsigned int mode, unsigned int *rate)
{
unsigned int i, m;
for (i = ARRAY_SIZE(snd_dice_rates); i > 0; i--) {
*rate = snd_dice_rates[i - 1];
if (snd_dice_stream_get_rate_mode(dice, *rate, &m) < 0)
continue;
if (mode == m)
break;
}
if (i == 0)
return -EINVAL;
return 0;
}
static int dice_read_mode_params(struct snd_dice *dice, unsigned int mode)
{
__be32 values[2];
unsigned int rate;
int err;
if (highest_supported_mode_rate(dice, mode, &rate) < 0) {
dice->tx_channels[mode] = 0;
dice->tx_midi_ports[mode] = 0;
dice->rx_channels[mode] = 0;
dice->rx_midi_ports[mode] = 0;
return 0;
}
err = snd_dice_transaction_set_rate(dice, rate);
if (err < 0)
return err;
err = snd_dice_transaction_read_tx(dice, TX_NUMBER_AUDIO,
values, sizeof(values));
if (err < 0)
return err;
dice->tx_channels[mode] = be32_to_cpu(values[0]);
dice->tx_midi_ports[mode] = be32_to_cpu(values[1]);
err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO,
values, sizeof(values));
if (err < 0)
return err;
dice->rx_channels[mode] = be32_to_cpu(values[0]);
dice->rx_midi_ports[mode] = be32_to_cpu(values[1]);
return 0;
}
static int dice_read_params(struct snd_dice *dice)
static int check_clock_caps(struct snd_dice *dice)
{
__be32 value;
int mode, err;
int err;
/* some very old firmwares don't tell about their clock support */
if (dice->clock_caps > 0) {
......@@ -133,12 +116,6 @@ static int dice_read_params(struct snd_dice *dice)
CLOCK_CAP_SOURCE_INTERNAL;
}
for (mode = 2; mode >= 0; --mode) {
err = dice_read_mode_params(dice, mode);
if (err < 0)
return err;
}
return 0;
}
......@@ -211,11 +188,14 @@ static void do_registration(struct work_struct *work)
if (err < 0)
return;
if (force_two_pcm_support(dice->unit))
dice->force_two_pcms = true;
err = snd_dice_transaction_init(dice);
if (err < 0)
goto error;
err = dice_read_params(dice);
err = check_clock_caps(dice);
if (err < 0)
goto error;
......
......@@ -39,6 +39,29 @@
#include "../lib.h"
#include "dice-interface.h"
/*
* This module support maximum 2 pairs of tx/rx isochronous streams for
* our convinience.
*
* In documents for ASICs called with a name of 'DICE':
* - ASIC for DICE II:
* - Maximum 2 tx and 4 rx are supported.
* - A packet supports maximum 16 data channels.
* - TCD2210/2210-E (so-called 'Dice Mini'):
* - Maximum 2 tx and 2 rx are supported.
* - A packet supports maximum 16 data channels.
* - TCD2220/2220-E (so-called 'Dice Jr.')
* - 2 tx and 2 rx are supported.
* - A packet supports maximum 16 data channels.
* - TCD3070-CH (so-called 'Dice III')
* - Maximum 2 tx and 2 rx are supported.
* - A packet supports maximum 32 data channels.
*
* For the above, MIDI conformant data channel is just on the first isochronous
* stream.
*/
#define MAX_STREAMS 2
struct snd_dice {
struct snd_card *card;
struct fw_unit *unit;
......@@ -56,10 +79,6 @@ struct snd_dice {
unsigned int rsrv_offset;
unsigned int clock_caps;
unsigned int tx_channels[3];
unsigned int rx_channels[3];
unsigned int tx_midi_ports[3];
unsigned int rx_midi_ports[3];
struct fw_address_handler notification_handler;
int owner_generation;
......@@ -71,13 +90,15 @@ struct snd_dice {
wait_queue_head_t hwdep_wait;
/* For streaming */
struct fw_iso_resources tx_resources;
struct fw_iso_resources rx_resources;
struct amdtp_stream tx_stream;
struct amdtp_stream rx_stream;
struct fw_iso_resources tx_resources[MAX_STREAMS];
struct fw_iso_resources rx_resources[MAX_STREAMS];
struct amdtp_stream tx_stream[MAX_STREAMS];
struct amdtp_stream rx_stream[MAX_STREAMS];
bool global_enabled;
struct completion clock_accepted;
unsigned int substreams_counter;
bool force_two_pcms;
};
enum snd_dice_addr_type {
......@@ -158,7 +179,6 @@ static inline int snd_dice_transaction_read_sync(struct snd_dice *dice,
int snd_dice_transaction_get_clock_source(struct snd_dice *dice,
unsigned int *source);
int snd_dice_transaction_set_rate(struct snd_dice *dice, unsigned int rate);
int snd_dice_transaction_get_rate(struct snd_dice *dice, unsigned int *rate);
int snd_dice_transaction_set_enable(struct snd_dice *dice);
void snd_dice_transaction_clear_enable(struct snd_dice *dice);
......@@ -169,9 +189,6 @@ void snd_dice_transaction_destroy(struct snd_dice *dice);
#define SND_DICE_RATES_COUNT 7
extern const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT];
int snd_dice_stream_get_rate_mode(struct snd_dice *dice,
unsigned int rate, unsigned int *mode);
int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate);
void snd_dice_stream_stop_duplex(struct snd_dice *dice);
int snd_dice_stream_init_duplex(struct snd_dice *dice);
......
......@@ -301,7 +301,10 @@ static void efw_update(struct fw_unit *unit)
struct snd_efw *efw = dev_get_drvdata(&unit->device);
snd_efw_transaction_bus_reset(efw->unit);
mutex_lock(&efw->mutex);
snd_efw_stream_update_duplex(efw);
mutex_unlock(&efw->mutex);
}
static void efw_remove(struct fw_unit *unit)
......
......@@ -313,12 +313,10 @@ void snd_efw_stream_stop_duplex(struct snd_efw *efw)
void snd_efw_stream_update_duplex(struct snd_efw *efw)
{
if ((cmp_connection_update(&efw->out_conn) < 0) ||
(cmp_connection_update(&efw->in_conn) < 0)) {
mutex_lock(&efw->mutex);
if (cmp_connection_update(&efw->out_conn) < 0 ||
cmp_connection_update(&efw->in_conn) < 0) {
stop_stream(efw, &efw->rx_stream);
stop_stream(efw, &efw->tx_stream);
mutex_unlock(&efw->mutex);
} else {
amdtp_stream_update(&efw->rx_stream);
amdtp_stream_update(&efw->tx_stream);
......
......@@ -26,11 +26,13 @@ struct fw_scs1x {
u8 output_bytes;
bool output_escaped;
bool output_escape_high_nibble;
struct tasklet_struct tasklet;
struct work_struct work;
wait_queue_head_t idle_wait;
u8 buffer[HSS1394_MAX_PACKET_SIZE];
bool transaction_running;
struct fw_transaction transaction;
unsigned int transaction_bytes;
bool error;
struct fw_device *fw_dev;
};
......@@ -125,11 +127,16 @@ static void scs_write_callback(struct fw_card *card, int rcode,
{
struct fw_scs1x *scs = callback_data;
if (rcode == RCODE_GENERATION)
; /* TODO: retry this packet */
if (!rcode_is_permanent_error(rcode)) {
/* Don't retry for this data. */
if (rcode == RCODE_COMPLETE)
scs->transaction_bytes = 0;
} else {
scs->error = true;
}
scs->transaction_running = false;
tasklet_schedule(&scs->tasklet);
schedule_work(&scs->work);
}
static bool is_valid_running_status(u8 status)
......@@ -165,9 +172,9 @@ static bool is_invalid_cmd(u8 status)
status == 0xfd;
}
static void scs_output_tasklet(unsigned long data)
static void scs_output_work(struct work_struct *work)
{
struct fw_scs1x *scs = (struct fw_scs1x *)data;
struct fw_scs1x *scs = container_of(work, struct fw_scs1x, work);
struct snd_rawmidi_substream *stream;
unsigned int i;
u8 byte;
......@@ -177,12 +184,15 @@ static void scs_output_tasklet(unsigned long data)
return;
stream = ACCESS_ONCE(scs->output);
if (!stream) {
if (!stream || scs->error) {
scs->output_idle = true;
wake_up(&scs->idle_wait);
return;
}
if (scs->transaction_bytes > 0)
goto retry;
i = scs->output_bytes;
for (;;) {
if (snd_rawmidi_transmit(stream, &byte, 1) != 1) {
......@@ -253,13 +263,16 @@ static void scs_output_tasklet(unsigned long data)
scs->output_bytes = 1;
scs->output_escaped = false;
scs->transaction_bytes = i;
retry:
scs->transaction_running = true;
generation = scs->fw_dev->generation;
smp_rmb(); /* node_id vs. generation */
fw_send_request(scs->fw_dev->card, &scs->transaction,
TCODE_WRITE_BLOCK_REQUEST, scs->fw_dev->node_id,
generation, scs->fw_dev->max_speed, HSS1394_ADDRESS,
scs->buffer, i, scs_write_callback, scs);
scs->buffer, scs->transaction_bytes,
scs_write_callback, scs);
}
static int midi_capture_open(struct snd_rawmidi_substream *stream)
......@@ -309,9 +322,11 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *stream, int up)
scs->output_bytes = 1;
scs->output_escaped = false;
scs->output_idle = false;
scs->transaction_bytes = 0;
scs->error = false;
ACCESS_ONCE(scs->output) = stream;
tasklet_schedule(&scs->tasklet);
schedule_work(&scs->work);
} else {
ACCESS_ONCE(scs->output) = NULL;
}
......@@ -395,7 +410,7 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw)
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
&midi_playback_ops);
tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs);
INIT_WORK(&scs->work, scs_output_work);
init_waitqueue_head(&scs->idle_wait);
scs->output_idle = true;
......
snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o \
hdac_regmap.o hdac_controller.o hdac_stream.o array.o
hdac_regmap.o hdac_controller.o hdac_stream.o array.o hdmi_chmap.o
snd-hda-core-objs += trace.o
CFLAGS_trace.o := -I$(src)
......
......@@ -611,6 +611,22 @@ int snd_hdac_power_up_pm(struct hdac_device *codec)
}
EXPORT_SYMBOL_GPL(snd_hdac_power_up_pm);
/* like snd_hdac_power_up_pm(), but only increment the pm count when
* already powered up. Returns -1 if not powered up, 1 if incremented
* or 0 if unchanged. Only used in hdac_regmap.c
*/
int snd_hdac_keep_power_up(struct hdac_device *codec)
{
if (!atomic_inc_not_zero(&codec->in_pm)) {
int ret = pm_runtime_get_if_in_use(&codec->dev);
if (!ret)
return -1;
if (ret < 0)
return 0;
}
return 1;
}
/**
* snd_hdac_power_down_pm - power down the codec
* @codec: the codec object
......
......@@ -126,6 +126,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_get_display_clk);
*/
static int pin2port(hda_nid_t pin_nid)
{
if (WARN_ON(pin_nid < 5 || pin_nid > 7))
return -1;
return pin_nid - 4;
}
......@@ -144,10 +146,14 @@ static int pin2port(hda_nid_t pin_nid)
int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid, int rate)
{
struct i915_audio_component *acomp = bus->audio_component;
int port;
if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate)
return -ENODEV;
return acomp->ops->sync_audio_rate(acomp->dev, pin2port(nid), rate);
port = pin2port(nid);
if (port < 0)
return -EINVAL;
return acomp->ops->sync_audio_rate(acomp->dev, port, rate);
}
EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
......@@ -175,11 +181,15 @@ int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid,
bool *audio_enabled, char *buffer, int max_bytes)
{
struct i915_audio_component *acomp = bus->audio_component;
int port;
if (!acomp || !acomp->ops || !acomp->ops->get_eld)
return -ENODEV;
return acomp->ops->get_eld(acomp->dev, pin2port(nid), audio_enabled,
port = pin2port(nid);
if (port < 0)
return -EINVAL;
return acomp->ops->get_eld(acomp->dev, port, audio_enabled,
buffer, max_bytes);
}
EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);
......
......@@ -21,13 +21,16 @@
#include <sound/hdaudio.h>
#include <sound/hda_regmap.h>
#ifdef CONFIG_PM
#define codec_is_running(codec) \
(atomic_read(&(codec)->in_pm) || \
!pm_runtime_suspended(&(codec)->dev))
#else
#define codec_is_running(codec) true
#endif
static int codec_pm_lock(struct hdac_device *codec)
{
return snd_hdac_keep_power_up(codec);
}
static void codec_pm_unlock(struct hdac_device *codec, int lock)
{
if (lock == 1)
snd_hdac_power_down_pm(codec);
}
#define get_verb(reg) (((reg) >> 8) & 0xfff)
......@@ -238,20 +241,28 @@ static int hda_reg_read(void *context, unsigned int reg, unsigned int *val)
struct hdac_device *codec = context;
int verb = get_verb(reg);
int err;
int pm_lock = 0;
if (!codec_is_running(codec) && verb != AC_VERB_GET_POWER_STATE)
return -EAGAIN;
if (verb != AC_VERB_GET_POWER_STATE) {
pm_lock = codec_pm_lock(codec);
if (pm_lock < 0)
return -EAGAIN;
}
reg |= (codec->addr << 28);
if (is_stereo_amp_verb(reg))
return hda_reg_read_stereo_amp(codec, reg, val);
if (verb == AC_VERB_GET_PROC_COEF)
return hda_reg_read_coef(codec, reg, val);
if (is_stereo_amp_verb(reg)) {
err = hda_reg_read_stereo_amp(codec, reg, val);
goto out;
}
if (verb == AC_VERB_GET_PROC_COEF) {
err = hda_reg_read_coef(codec, reg, val);
goto out;
}
if ((verb & 0x700) == AC_VERB_SET_AMP_GAIN_MUTE)
reg &= ~AC_AMP_FAKE_MUTE;
err = snd_hdac_exec_verb(codec, reg, 0, val);
if (err < 0)
return err;
goto out;
/* special handling for asymmetric reads */
if (verb == AC_VERB_GET_POWER_STATE) {
if (*val & AC_PWRST_ERROR)
......@@ -259,7 +270,9 @@ static int hda_reg_read(void *context, unsigned int reg, unsigned int *val)
else /* take only the actual state */
*val = (*val >> 4) & 0x0f;
}
return 0;
out:
codec_pm_unlock(codec, pm_lock);
return err;
}
static int hda_reg_write(void *context, unsigned int reg, unsigned int val)
......@@ -267,6 +280,7 @@ static int hda_reg_write(void *context, unsigned int reg, unsigned int val)
struct hdac_device *codec = context;
unsigned int verb;
int i, bytes, err;
int pm_lock = 0;
if (codec->caps_overwriting)
return 0;
......@@ -275,14 +289,21 @@ static int hda_reg_write(void *context, unsigned int reg, unsigned int val)
reg |= (codec->addr << 28);
verb = get_verb(reg);
if (!codec_is_running(codec) && verb != AC_VERB_SET_POWER_STATE)
return codec->lazy_cache ? 0 : -EAGAIN;
if (verb != AC_VERB_SET_POWER_STATE) {
pm_lock = codec_pm_lock(codec);
if (pm_lock < 0)
return codec->lazy_cache ? 0 : -EAGAIN;
}
if (is_stereo_amp_verb(reg))
return hda_reg_write_stereo_amp(codec, reg, val);
if (is_stereo_amp_verb(reg)) {
err = hda_reg_write_stereo_amp(codec, reg, val);
goto out;
}
if (verb == AC_VERB_SET_PROC_COEF)
return hda_reg_write_coef(codec, reg, val);
if (verb == AC_VERB_SET_PROC_COEF) {
err = hda_reg_write_coef(codec, reg, val);
goto out;
}
switch (verb & 0xf00) {
case AC_VERB_SET_AMP_GAIN_MUTE:
......@@ -319,10 +340,12 @@ static int hda_reg_write(void *context, unsigned int reg, unsigned int val)
reg |= (verb + i) << 8 | ((val >> (8 * i)) & 0xff);
err = snd_hdac_exec_verb(codec, reg, 0, NULL);
if (err < 0)
return err;
goto out;
}
return 0;
out:
codec_pm_unlock(codec, pm_lock);
return err;
}
static const struct regmap_config hda_regmap_cfg = {
......
This diff is collapsed.
......@@ -23,17 +23,5 @@ config SND_SGI_HAL2
help
Sound support for the SGI Indy and Indigo2 Workstation.
config SND_AU1X00
tristate "Au1x00 AC97 Port Driver (DEPRECATED)"
depends on MIPS_ALCHEMY
select SND_PCM
select SND_AC97_CODEC
help
ALSA Sound driver for the Au1x00's AC97 port.
Newer drivers for ASoC are available, please do not use
this driver as it will be removed in the future.
endif # SND_MIPS
......@@ -2,11 +2,9 @@
# Makefile for ALSA
#
snd-au1x00-objs := au1x00.o
snd-sgi-o2-objs := sgio2audio.o ad1843.o
snd-sgi-hal2-objs := hal2.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_AU1X00) += snd-au1x00.o
obj-$(CONFIG_SND_SGI_O2) += snd-sgi-o2.o
obj-$(CONFIG_SND_SGI_HAL2) += snd-sgi-hal2.o
This diff is collapsed.
......@@ -866,7 +866,7 @@ config SND_VIRTUOSO
select SND_OXYGEN_LIB
select SND_PCM
select SND_MPU401_UART
select SND_JACK if INPUT=y || INPUT=SND
select SND_JACK
help
Say Y here to include support for sound cards based on the
Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS, DSX,
......
......@@ -4,7 +4,7 @@ config SND_HDA
tristate
select SND_PCM
select SND_VMASTER
select SND_JACK if INPUT=y || INPUT=SND
select SND_JACK
select SND_HDA_CORE
config SND_HDA_INTEL
......
......@@ -26,6 +26,7 @@
#include <linux/slab.h>
#include <sound/core.h>
#include <asm/unaligned.h>
#include <sound/hda_chmap.h>
#include "hda_codec.h"
#include "hda_local.h"
......@@ -42,20 +43,6 @@ enum cea_edid_versions {
CEA_EDID_VER_RESERVED = 4,
};
static const char * const cea_speaker_allocation_names[] = {
/* 0 */ "FL/FR",
/* 1 */ "LFE",
/* 2 */ "FC",
/* 3 */ "RL/RR",
/* 4 */ "RC",
/* 5 */ "FLC/FRC",
/* 6 */ "RLC/RRC",
/* 7 */ "FLW/FRW",
/* 8 */ "FLH/FRH",
/* 9 */ "TC",
/* 10 */ "FCH",
};
static const char * const eld_connection_type_names[4] = {
"HDMI",
"DisplayPort",
......@@ -419,18 +406,6 @@ static void hdmi_show_short_audio_desc(struct hda_codec *codec,
a->channels, buf, buf2);
}
void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen)
{
int i, j;
for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) {
if (spk_alloc & (1 << i))
j += snprintf(buf + j, buflen - j, " %s",
cea_speaker_allocation_names[i]);
}
buf[j] = '\0'; /* necessary when j == 0 */
}
void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e)
{
int i;
......@@ -441,7 +416,7 @@ void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e)
if (e->spk_alloc) {
char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf));
snd_hdac_print_channel_allocation(e->spk_alloc, buf, sizeof(buf));
codec_dbg(codec, "HDMI: available speakers:%s\n", buf);
}
......@@ -516,7 +491,7 @@ void snd_hdmi_print_eld_info(struct hdmi_eld *eld,
snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai);
snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay);
snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf));
snd_hdac_print_channel_allocation(e->spk_alloc, buf, sizeof(buf));
snd_iprintf(buffer, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf);
snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count);
......
......@@ -2145,7 +2145,7 @@ static int azx_probe_continue(struct azx *chip)
azx_add_card_list(chip);
snd_hda_set_power_save(&chip->bus, power_save * 1000);
if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo)
pm_runtime_put_noidle(&pci->dev);
pm_runtime_put_autosuspend(&pci->dev);
out_free:
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL
......
......@@ -174,8 +174,12 @@ static void cs_automute(struct hda_codec *codec)
snd_hda_gen_update_outputs(codec);
if (spec->gpio_eapd_hp || spec->gpio_eapd_speaker) {
spec->gpio_data = spec->gen.hp_jack_present ?
spec->gpio_eapd_hp : spec->gpio_eapd_speaker;
if (spec->gen.automute_speaker)
spec->gpio_data = spec->gen.hp_jack_present ?
spec->gpio_eapd_hp : spec->gpio_eapd_speaker;
else
spec->gpio_data =
spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
snd_hda_codec_write(codec, 0x01, 0,
AC_VERB_SET_GPIO_DATA, spec->gpio_data);
}
......
......@@ -204,8 +204,13 @@ static void cx_auto_reboot_notify(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
if (codec->core.vendor_id != 0x14f150f2)
switch (codec->core.vendor_id) {
case 0x14f150f2: /* CX20722 */
case 0x14f150f4: /* CX20724 */
break;
default:
return;
}
/* Turn the CX20722 codec into D3 to avoid spurious noises
from the internal speaker during (and after) reboot */
......
This diff is collapsed.
......@@ -5556,6 +5556,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE),
SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
......
......@@ -10,23 +10,10 @@
static int (*led_set_func)(int, bool);
static void (*old_vmaster_hook)(void *, int);
static acpi_status acpi_check_cb(acpi_handle handle, u32 lvl, void *context,
void **rv)
{
bool *found = context;
*found = true;
return AE_OK;
}
static bool is_thinkpad(struct hda_codec *codec)
{
bool found = false;
if (codec->core.subsystem_id >> 16 != 0x17aa)
return false;
if (ACPI_SUCCESS(acpi_get_devices("LEN0068", acpi_check_cb, &found, NULL)) && found)
return true;
found = false;
return ACPI_SUCCESS(acpi_get_devices("IBM0068", acpi_check_cb, &found, NULL)) && found;
return (codec->core.subsystem_id >> 16 == 0x17aa) &&
(acpi_dev_present("LEN0068") || acpi_dev_present("IBM0068"));
}
static void update_tpacpi_mute_led(void *private_data, int enabled)
......
......@@ -2879,6 +2879,7 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip)
static struct snd_pci_quirk intel8x0_clock_list[] = {
SND_PCI_QUIRK(0x0e11, 0x008a, "AD1885", 41000),
SND_PCI_QUIRK(0x1014, 0x0581, "AD1981B", 48000),
SND_PCI_QUIRK(0x1028, 0x00be, "AD1885", 44100),
SND_PCI_QUIRK(0x1028, 0x0177, "AD1980", 48000),
SND_PCI_QUIRK(0x1028, 0x01ad, "AD1981B", 48000),
......
......@@ -132,7 +132,7 @@ static int mixart_set_pipe_state(struct mixart_mgr *mgr,
}
if(start) {
u32 stat;
u32 stat = 0;
group_state.pipe_count = 0; /* in case of start same command once again with pipe_count=0 */
......
......@@ -726,7 +726,7 @@ int mixart_update_playback_stream_level(struct snd_mixart* chip, int is_aes, int
int volume[2];
struct mixart_msg request;
struct mixart_set_out_stream_level_req set_level;
u32 status;
u32 status = 0;
struct mixart_pipe *pipe;
memset(&set_level, 0, sizeof(set_level));
......@@ -778,7 +778,7 @@ int mixart_update_capture_stream_level(struct snd_mixart* chip, int is_aes)
struct mixart_pipe *pipe;
struct mixart_msg request;
struct mixart_set_in_audio_level_req set_level;
u32 status;
u32 status = 0;
if(is_aes) {
idx = 1;
......
......@@ -6,7 +6,7 @@ menuconfig SND_SOC
tristate "ALSA for SoC audio support"
select SND_PCM
select AC97_BUS if SND_SOC_AC97_BUS
select SND_JACK if INPUT=y || INPUT=SND
select SND_JACK
select REGMAP_I2C if I2C
select REGMAP_SPI if SPI_MASTER
---help---
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -2134,7 +2134,6 @@ static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
"%s: ERROR: Unsupporter master mask 0x%x\n",
__func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
return -EINVAL;
break;
}
snd_soc_update_bits(codec, AB8500_DIGIFCONF3, mask, val);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -42,9 +42,19 @@ static const struct i2c_device_id adau1781_i2c_ids[] = {
};
MODULE_DEVICE_TABLE(i2c, adau1781_i2c_ids);
#if defined(CONFIG_OF)
static const struct of_device_id adau1781_i2c_dt_ids[] = {
{ .compatible = "adi,adau1381", },
{ .compatible = "adi,adau1781", },
{ },
};
MODULE_DEVICE_TABLE(of, adau1781_i2c_dt_ids);
#endif
static struct i2c_driver adau1781_i2c_driver = {
.driver = {
.name = "adau1781",
.of_match_table = of_match_ptr(adau1781_i2c_dt_ids),
},
.probe = adau1781_i2c_probe,
.remove = adau1781_i2c_remove,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment