Merge branch 'for-linus' into for-next
authorTakashi Iwai <tiwai@suse.de>
Mon, 28 Oct 2019 11:43:29 +0000 (12:43 +0100)
committerTakashi Iwai <tiwai@suse.de>
Mon, 28 Oct 2019 11:43:34 +0000 (12:43 +0100)
Back-merge the development process for catching up the HD-audio fix
(and apply a new one on top of that).

Signed-off-by: Takashi Iwai <tiwai@suse.de>
62 files changed:
drivers/pci/pci.c
include/linux/pci.h
include/sound/intel-dsp-config.h [new file with mode: 0644]
sound/core/Kconfig
sound/drivers/Kconfig
sound/firewire/Kconfig
sound/firewire/amdtp-stream.c
sound/firewire/amdtp-stream.h
sound/firewire/bebob/bebob.h
sound/firewire/bebob/bebob_midi.c
sound/firewire/bebob/bebob_pcm.c
sound/firewire/bebob/bebob_stream.c
sound/firewire/dice/dice-midi.c
sound/firewire/dice/dice-pcm.c
sound/firewire/dice/dice-stream.c
sound/firewire/dice/dice.h
sound/firewire/digi00x/digi00x-midi.c
sound/firewire/digi00x/digi00x-pcm.c
sound/firewire/digi00x/digi00x-stream.c
sound/firewire/digi00x/digi00x.h
sound/firewire/fireface/ff-pcm.c
sound/firewire/fireface/ff-stream.c
sound/firewire/fireface/ff.h
sound/firewire/fireworks/fireworks.h
sound/firewire/fireworks/fireworks_midi.c
sound/firewire/fireworks/fireworks_pcm.c
sound/firewire/fireworks/fireworks_stream.c
sound/firewire/motu/motu-midi.c
sound/firewire/motu/motu-pcm.c
sound/firewire/motu/motu-stream.c
sound/firewire/motu/motu.h
sound/firewire/oxfw/oxfw-midi.c
sound/firewire/oxfw/oxfw-pcm.c
sound/firewire/oxfw/oxfw-stream.c
sound/firewire/oxfw/oxfw.h
sound/firewire/tascam/tascam-pcm.c
sound/firewire/tascam/tascam-stream.c
sound/firewire/tascam/tascam.h
sound/hda/Kconfig
sound/hda/Makefile
sound/hda/intel-dsp-config.c [new file with mode: 0644]
sound/hda/intel-nhlt.c
sound/isa/Kconfig
sound/mips/Kconfig
sound/pci/Kconfig
sound/pci/hda/Kconfig
sound/pci/hda/hda_intel.c
sound/soc/cirrus/Kconfig
sound/soc/codecs/Kconfig
sound/soc/intel/Kconfig
sound/soc/intel/boards/Kconfig
sound/soc/intel/skylake/skl.c
sound/soc/pxa/Kconfig
sound/soc/qcom/Kconfig
sound/soc/samsung/Kconfig
sound/soc/sof/imx/Kconfig
sound/soc/sof/intel/Kconfig
sound/soc/sof/sof-pci-dev.c
sound/soc/xilinx/Kconfig
sound/soc/zte/Kconfig
sound/usb/Kconfig
sound/x86/intel_hdmi_audio.c

index e7982af9a5d86efd738640fbe08dba01e4704155..1df99d9e350e988621a6a2242d443a28c3972bad 100644 (file)
@@ -5856,6 +5856,24 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode,
        return 0;
 }
 
+#ifdef CONFIG_ACPI
+bool pci_pr3_present(struct pci_dev *pdev)
+{
+       struct acpi_device *adev;
+
+       if (acpi_disabled)
+               return false;
+
+       adev = ACPI_COMPANION(&pdev->dev);
+       if (!adev)
+               return false;
+
+       return adev->power.flags.power_resources &&
+               acpi_has_method(adev->handle, "_PR3");
+}
+EXPORT_SYMBOL_GPL(pci_pr3_present);
+#endif
+
 /**
  * pci_add_dma_alias - Add a DMA devfn alias for a device
  * @dev: the PCI device for which alias is added
index f9088c89a534737049463cc024e40db803422cb5..be529d311122d9d707ec3f9533e966d6dbb7f426 100644 (file)
@@ -2310,9 +2310,11 @@ struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus);
 
 void
 pci_msi_register_fwnode_provider(struct fwnode_handle *(*fn)(struct device *));
+bool pci_pr3_present(struct pci_dev *pdev);
 #else
 static inline struct irq_domain *
 pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; }
+static inline bool pci_pr3_present(struct pci_dev *pdev) { return false; }
 #endif
 
 #ifdef CONFIG_EEH
diff --git a/include/sound/intel-dsp-config.h b/include/sound/intel-dsp-config.h
new file mode 100644 (file)
index 0000000..c36622b
--- /dev/null
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ *  intel-dsp-config.h - Intel DSP config
+ *
+ *  Copyright (c) 2019 Jaroslav Kysela <perex@perex.cz>
+ */
+
+#ifndef __INTEL_DSP_CONFIG_H__
+#define __INTEL_DSP_CONFIG_H__
+
+struct pci_dev;
+
+enum {
+       SND_INTEL_DSP_DRIVER_ANY = 0,
+       SND_INTEL_DSP_DRIVER_LEGACY,
+       SND_INTEL_DSP_DRIVER_SST,
+       SND_INTEL_DSP_DRIVER_SOF,
+       SND_INTEL_DSP_DRIVER_LAST = SND_INTEL_DSP_DRIVER_SOF
+};
+
+#if IS_ENABLED(CONFIG_SND_INTEL_DSP_CONFIG)
+
+int snd_intel_dsp_driver_probe(struct pci_dev *pci);
+
+#else
+
+static inline int snd_intel_dsp_driver_probe(struct pci_dev *pci)
+{
+       return SND_INTEL_DSP_DRIVER_ANY;
+}
+
+#endif
+
+#endif
index 4ee79ad6ae229d27cd3d98c8deb34341929789d0..4044c42d859535b695360b4eeb204a8aa089a8f7 100644 (file)
@@ -72,11 +72,11 @@ config SND_PCM_OSS
 config SND_PCM_OSS_PLUGINS
        bool "OSS PCM (digital audio) API - Include plugin system"
        depends on SND_PCM_OSS
-        default y
+       default y
        help
-          If you disable this option, the ALSA's OSS PCM API will not
-          support conversion of channels, formats and rates. It will
-          behave like most of new OSS/Free drivers in 2.4/2.6 kernels.
+         If you disable this option, the ALSA's OSS PCM API will not
+         support conversion of channels, formats and rates. It will
+         behave like most of new OSS/Free drivers in 2.4/2.6 kernels.
 
 config SND_PCM_TIMER
        bool "PCM timer interface" if EXPERT
@@ -128,13 +128,13 @@ config SND_SUPPORT_OLD_API
          or older).
 
 config SND_PROC_FS
-        bool "Sound Proc FS Support" if EXPERT
-        depends on PROC_FS
-        default y
-        help
-          Say 'N' to disable Sound proc FS, which may reduce code size about
-          9KB on x86_64 platform.
-          If unsure say Y.
+       bool "Sound Proc FS Support" if EXPERT
+       depends on PROC_FS
+       default y
+       help
+         Say 'N' to disable Sound proc FS, which may reduce code size about
+         9KB on x86_64 platform.
+         If unsure say Y.
 
 config SND_VERBOSE_PROCFS
        bool "Verbose procfs contents"
@@ -142,8 +142,8 @@ config SND_VERBOSE_PROCFS
        default y
        help
          Say Y here to include code for verbose procfs contents (provides
-          useful information to developers when a problem occurs).  On the
-          other side, it makes the ALSA subsystem larger.
+         useful information to developers when a problem occurs).  On the
+         other side, it makes the ALSA subsystem larger.
 
 config SND_VERBOSE_PRINTK
        bool "Verbose printk"
@@ -164,7 +164,7 @@ config SND_DEBUG_VERBOSE
        depends on SND_DEBUG
        help
          Say Y here to enable extra-verbose debugging messages.
-         
+
          Let me repeat: it enables EXTRA-VERBOSE DEBUGGING messages.
          So, say Y only if you are ready to be annoyed.
 
index 09932cc98e9d8f0169c2f24d19181c7043a52b8a..15d6d46acf9c3ffe934439af2a5991c4f5cf0e5a 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config SND_MPU401_UART
-        tristate
-        select SND_RAWMIDI
+       tristate
+       select SND_RAWMIDI
 
 config SND_OPL3_LIB
        tristate
@@ -90,16 +90,16 @@ config SND_DUMMY
          will be called snd-dummy.
 
 config SND_ALOOP
-        tristate "Generic loopback driver (PCM)"
-        select SND_PCM
-        help
-          Say 'Y' or 'M' to include support for the PCM loopback device.
+       tristate "Generic loopback driver (PCM)"
+       select SND_PCM
+       help
+         Say 'Y' or 'M' to include support for the PCM loopback device.
          This module returns played samples back to the user space using
          the standard ALSA PCM device. The devices are routed 0->1 and
-          1->0, where first number is the playback PCM device and second
+         1->0, where first number is the playback PCM device and second
          number is the capture device. Module creates two PCM devices and
          configured number of substreams (see the pcm_substreams module
-          parameter).
+         parameter).
 
          The loopback device allows time sychronization with an external
          timing source using the time shift universal control (+-20%
@@ -142,12 +142,12 @@ config SND_MTS64
        select SND_RAWMIDI
        help
          The ESI Miditerminal 4140 is a 4 In 4 Out MIDI Interface with 
-          additional SMPTE Timecode capabilities for the parallel port.
+         additional SMPTE Timecode capabilities for the parallel port.
 
          Say 'Y' to include support for this device.
 
          To compile this driver as a module, chose 'M' here: the module 
-          will be called snd-mts64.
+         will be called snd-mts64.
 
 config SND_SERIAL_U16550
        tristate "UART16550 serial MIDI driver"
index b0a904cdb932d1095bfaa12de5bfc048ccaeb881..995c2cefc222b1e67d4d92e0970844b0e1a82798 100644 (file)
@@ -77,7 +77,7 @@ config SND_BEBOB
        tristate "BridgeCo DM1000/DM1100/DM1500 with BeBoB firmware"
        select SND_FIREWIRE_LIB
        select SND_HWDEP
-        help
+       help
         Say Y here to include support for FireWire devices based
         on BridgeCo DM1000/DM1100/DM1500 with BeBoB firmware:
          * Edirol FA-66/FA-101
@@ -111,8 +111,8 @@ config SND_BEBOB
          * M-Audio FireWire 1814/ProjectMix IO
          * Digidesign Mbox 2 Pro
 
-          To compile this driver as a module, choose M here: the module
-          will be called snd-bebob.
+         To compile this driver as a module, choose M here: the module
+         will be called snd-bebob.
 
 config SND_FIREWIRE_DIGI00X
        tristate "Digidesign Digi 002/003 family support"
index e50e28f77e74e3308cd49a2647d1099b3eb76cb1..37d38efb4c877f8084400b92a4c9e87599fc007c 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/firewire.h>
+#include <linux/firewire-constants.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <sound/pcm.h>
 #define CIP_FMT_AM             0x10
 #define AMDTP_FDF_NO_DATA      0xff
 
-/* TODO: make these configurable */
-#define INTERRUPT_INTERVAL     16
-#define QUEUE_LENGTH           48
-
 // For iso header, tstamp and 2 CIP header.
 #define IR_CTX_HEADER_SIZE_CIP         16
 // For iso header and tstamp.
@@ -180,6 +177,8 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
                                        struct snd_pcm_runtime *runtime)
 {
        struct snd_pcm_hardware *hw = &runtime->hw;
+       unsigned int ctx_header_size;
+       unsigned int maximum_usec_per_period;
        int err;
 
        hw->info = SNDRV_PCM_INFO_BATCH |
@@ -200,19 +199,36 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
        hw->period_bytes_max = hw->period_bytes_min * 2048;
        hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min;
 
-       /*
-        * Currently firewire-lib processes 16 packets in one software
-        * interrupt callback. This equals to 2msec but actually the
-        * interval of the interrupts has a jitter.
-        * Additionally, even if adding a constraint to fit period size to
-        * 2msec, actual calculated frames per period doesn't equal to 2msec,
-        * depending on sampling rate.
-        * Anyway, the interval to call snd_pcm_period_elapsed() cannot 2msec.
-        * Here let us use 5msec for safe period interrupt.
-        */
+       // Linux driver for 1394 OHCI controller voluntarily flushes isoc
+       // context when total size of accumulated context header reaches
+       // PAGE_SIZE. This kicks tasklet for the isoc context and brings
+       // callback in the middle of scheduled interrupts.
+       // Although AMDTP streams in the same domain use the same events per
+       // IRQ, use the largest size of context header between IT/IR contexts.
+       // Here, use the value of context header in IR context is for both
+       // contexts.
+       if (!(s->flags & CIP_NO_HEADER))
+               ctx_header_size = IR_CTX_HEADER_SIZE_CIP;
+       else
+               ctx_header_size = IR_CTX_HEADER_SIZE_NO_CIP;
+       maximum_usec_per_period = USEC_PER_SEC * PAGE_SIZE /
+                                 CYCLES_PER_SECOND / ctx_header_size;
+
+       // In IEC 61883-6, one isoc packet can transfer events up to the value
+       // of syt interval. This comes from the interval of isoc cycle. As 1394
+       // OHCI controller can generate hardware IRQ per isoc packet, the
+       // interval is 125 usec.
+       // However, there are two ways of transmission in IEC 61883-6; blocking
+       // and non-blocking modes. In blocking mode, the sequence of isoc packet
+       // includes 'empty' or 'NODATA' packets which include no event. In
+       // non-blocking mode, the number of events per packet is variable up to
+       // the syt interval.
+       // Due to the above protocol design, the minimum PCM frames per
+       // interrupt should be double of the value of syt interval, thus it is
+       // 250 usec.
        err = snd_pcm_hw_constraint_minmax(runtime,
                                           SNDRV_PCM_HW_PARAM_PERIOD_TIME,
-                                          5000, UINT_MAX);
+                                          250, maximum_usec_per_period);
        if (err < 0)
                goto end;
 
@@ -436,11 +452,12 @@ static void pcm_period_tasklet(unsigned long data)
                snd_pcm_period_elapsed(pcm);
 }
 
-static int queue_packet(struct amdtp_stream *s, struct fw_iso_packet *params)
+static int queue_packet(struct amdtp_stream *s, struct fw_iso_packet *params,
+                       bool sched_irq)
 {
        int err;
 
-       params->interrupt = IS_ALIGNED(s->packet_index + 1, INTERRUPT_INTERVAL);
+       params->interrupt = sched_irq;
        params->tag = s->tag;
        params->sy = 0;
 
@@ -451,18 +468,18 @@ static int queue_packet(struct amdtp_stream *s, struct fw_iso_packet *params)
                goto end;
        }
 
-       if (++s->packet_index >= QUEUE_LENGTH)
+       if (++s->packet_index >= s->queue_size)
                s->packet_index = 0;
 end:
        return err;
 }
 
 static inline int queue_out_packet(struct amdtp_stream *s,
-                                  struct fw_iso_packet *params)
+                                  struct fw_iso_packet *params, bool sched_irq)
 {
        params->skip =
                !!(params->header_length == 0 && params->payload_length == 0);
-       return queue_packet(s, params);
+       return queue_packet(s, params, sched_irq);
 }
 
 static inline int queue_in_packet(struct amdtp_stream *s,
@@ -472,7 +489,7 @@ static inline int queue_in_packet(struct amdtp_stream *s,
        params->header_length = s->ctx_data.tx.ctx_header_size;
        params->payload_length = s->ctx_data.tx.max_ctx_payload_length;
        params->skip = false;
-       return queue_packet(s, params);
+       return queue_packet(s, params, false);
 }
 
 static void generate_cip_header(struct amdtp_stream *s, __be32 cip_header[2],
@@ -669,13 +686,14 @@ static inline u32 increment_cycle_count(u32 cycle, unsigned int addend)
 }
 
 // Align to actual cycle count for the packet which is going to be scheduled.
-// This module queued the same number of isochronous cycle as QUEUE_LENGTH to
-// skip isochronous cycle, therefore it's OK to just increment the cycle by
-// QUEUE_LENGTH for scheduled cycle.
-static inline u32 compute_it_cycle(const __be32 ctx_header_tstamp)
+// This module queued the same number of isochronous cycle as the size of queue
+// to kip isochronous cycle, therefore it's OK to just increment the cycle by
+// the size of queue for scheduled cycle.
+static inline u32 compute_it_cycle(const __be32 ctx_header_tstamp,
+                                  unsigned int queue_size)
 {
        u32 cycle = compute_cycle_count(ctx_header_tstamp);
-       return increment_cycle_count(cycle, QUEUE_LENGTH);
+       return increment_cycle_count(cycle, queue_size);
 }
 
 static int generate_device_pkt_descs(struct amdtp_stream *s,
@@ -689,7 +707,7 @@ static int generate_device_pkt_descs(struct amdtp_stream *s,
 
        for (i = 0; i < packets; ++i) {
                struct pkt_desc *desc = descs + i;
-               unsigned int index = (s->packet_index + i) % QUEUE_LENGTH;
+               unsigned int index = (s->packet_index + i) % s->queue_size;
                unsigned int cycle;
                unsigned int payload_length;
                unsigned int data_blocks;
@@ -730,9 +748,9 @@ static void generate_ideal_pkt_descs(struct amdtp_stream *s,
 
        for (i = 0; i < packets; ++i) {
                struct pkt_desc *desc = descs + i;
-               unsigned int index = (s->packet_index + i) % QUEUE_LENGTH;
+               unsigned int index = (s->packet_index + i) % s->queue_size;
 
-               desc->cycle = compute_it_cycle(*ctx_header);
+               desc->cycle = compute_it_cycle(*ctx_header, s->queue_size);
                desc->syt = calculate_syt(s, desc->cycle);
                desc->data_blocks = calculate_data_blocks(s, desc->syt);
 
@@ -773,22 +791,40 @@ static void process_ctx_payloads(struct amdtp_stream *s,
                update_pcm_pointers(s, pcm, pcm_frames);
 }
 
+static void amdtp_stream_master_callback(struct fw_iso_context *context,
+                                        u32 tstamp, size_t header_length,
+                                        void *header, void *private_data);
+
+static void amdtp_stream_master_first_callback(struct fw_iso_context *context,
+                                       u32 tstamp, size_t header_length,
+                                       void *header, void *private_data);
+
 static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
                                size_t header_length, void *header,
                                void *private_data)
 {
        struct amdtp_stream *s = private_data;
        const __be32 *ctx_header = header;
-       unsigned int packets = header_length / sizeof(*ctx_header);
+       unsigned int events_per_period = s->ctx_data.rx.events_per_period;
+       unsigned int event_count = s->ctx_data.rx.event_count;
+       unsigned int packets;
+       bool is_irq_target;
        int i;
 
        if (s->packet_index < 0)
                return;
 
+       // Calculate the number of packets in buffer and check XRUN.
+       packets = header_length / sizeof(*ctx_header);
+
        generate_ideal_pkt_descs(s, s->pkt_descs, ctx_header, packets);
 
        process_ctx_payloads(s, s->pkt_descs, packets);
 
+       is_irq_target =
+               !!(context->callback.sc == amdtp_stream_master_callback ||
+                  context->callback.sc == amdtp_stream_master_first_callback);
+
        for (i = 0; i < packets; ++i) {
                const struct pkt_desc *desc = s->pkt_descs + i;
                unsigned int syt;
@@ -796,6 +832,7 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
                        struct fw_iso_packet params;
                        __be32 header[IT_PKT_HEADER_SIZE_CIP / sizeof(__be32)];
                } template = { {0}, {0} };
+               bool sched_irq = false;
 
                if (s->ctx_data.rx.syt_override < 0)
                        syt = desc->syt;
@@ -806,13 +843,21 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
                                    desc->data_blocks, desc->data_block_counter,
                                    syt, i);
 
-               if (queue_out_packet(s, &template.params) < 0) {
+               if (is_irq_target) {
+                       event_count += desc->data_blocks;
+                       if (event_count >= events_per_period) {
+                               event_count -= events_per_period;
+                               sched_irq = true;
+                       }
+               }
+
+               if (queue_out_packet(s, &template.params, sched_irq) < 0) {
                        cancel_stream(s);
                        return;
                }
        }
 
-       fw_iso_context_queue_flush(s->context);
+       s->ctx_data.rx.event_count = event_count;
 }
 
 static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
@@ -820,15 +865,15 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
                               void *private_data)
 {
        struct amdtp_stream *s = private_data;
-       unsigned int packets;
        __be32 *ctx_header = header;
+       unsigned int packets;
        int i;
        int err;
 
        if (s->packet_index < 0)
                return;
 
-       // The number of packets in buffer.
+       // Calculate the number of packets in buffer and check XRUN.
        packets = header_length / s->ctx_data.tx.ctx_header_size;
 
        err = generate_device_pkt_descs(s, s->pkt_descs, ctx_header, packets);
@@ -849,11 +894,40 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
                        return;
                }
        }
+}
+
+static void amdtp_stream_master_callback(struct fw_iso_context *context,
+                                        u32 tstamp, size_t header_length,
+                                        void *header, void *private_data)
+{
+       struct amdtp_domain *d = private_data;
+       struct amdtp_stream *irq_target = d->irq_target;
+       struct amdtp_stream *s;
+
+       out_stream_callback(context, tstamp, header_length, header, irq_target);
+       if (amdtp_streaming_error(irq_target))
+               goto error;
+
+       list_for_each_entry(s, &d->streams, list) {
+               if (s != irq_target && amdtp_stream_running(s)) {
+                       fw_iso_context_flush_completions(s->context);
+                       if (amdtp_streaming_error(s))
+                               goto error;
+               }
+       }
 
-       fw_iso_context_queue_flush(s->context);
+       return;
+error:
+       if (amdtp_stream_running(irq_target))
+               cancel_stream(irq_target);
+
+       list_for_each_entry(s, &d->streams, list) {
+               if (amdtp_stream_running(s))
+                       cancel_stream(s);
+       }
 }
 
-/* this is executed one time */
+// this is executed one time.
 static void amdtp_stream_first_callback(struct fw_iso_context *context,
                                        u32 tstamp, size_t header_length,
                                        void *header, void *private_data)
@@ -874,7 +948,7 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
 
                context->callback.sc = in_stream_callback;
        } else {
-               cycle = compute_it_cycle(*ctx_header);
+               cycle = compute_it_cycle(*ctx_header, s->queue_size);
 
                context->callback.sc = out_stream_callback;
        }
@@ -884,17 +958,42 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
        context->callback.sc(context, tstamp, header_length, header, s);
 }
 
+static void amdtp_stream_master_first_callback(struct fw_iso_context *context,
+                                              u32 tstamp, size_t header_length,
+                                              void *header, void *private_data)
+{
+       struct amdtp_domain *d = private_data;
+       struct amdtp_stream *s = d->irq_target;
+       const __be32 *ctx_header = header;
+
+       s->callbacked = true;
+       wake_up(&s->callback_wait);
+
+       s->start_cycle = compute_it_cycle(*ctx_header, s->queue_size);
+
+       context->callback.sc = amdtp_stream_master_callback;
+
+       context->callback.sc(context, tstamp, header_length, header, d);
+}
+
 /**
  * amdtp_stream_start - start transferring packets
  * @s: the AMDTP stream to start
  * @channel: the isochronous channel on the bus
  * @speed: firewire speed code
+ * @d: the AMDTP domain to which the AMDTP stream belongs
+ * @is_irq_target: whether isoc context for the AMDTP stream is used to generate
+ *                hardware IRQ.
+ * @start_cycle: the isochronous cycle to start the context. Start immediately
+ *              if negative value is given.
  *
  * The stream cannot be started until it has been configured with
  * amdtp_stream_set_parameters() and it must be started before any PCM or MIDI
  * device can be started.
  */
-static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
+static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed,
+                             struct amdtp_domain *d, bool is_irq_target,
+                             int start_cycle)
 {
        static const struct {
                unsigned int data_block;
@@ -908,10 +1007,15 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
                [CIP_SFC_88200]  = {  0,   67 },
                [CIP_SFC_176400] = {  0,   67 },
        };
+       unsigned int events_per_buffer = d->events_per_buffer;
+       unsigned int events_per_period = d->events_per_period;
+       unsigned int idle_irq_interval;
        unsigned int ctx_header_size;
        unsigned int max_ctx_payload_size;
        enum dma_data_direction dir;
        int type, tag, err;
+       fw_iso_callback_t ctx_cb;
+       void *ctx_data;
 
        mutex_lock(&s->mutex);
 
@@ -922,6 +1026,12 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
        }
 
        if (s->direction == AMDTP_IN_STREAM) {
+               // NOTE: IT context should be used for constant IRQ.
+               if (is_irq_target) {
+                       err = -EINVAL;
+                       goto err_unlock;
+               }
+
                s->data_block_counter = UINT_MAX;
        } else {
                entry = &initial_state[s->sfc];
@@ -953,14 +1063,37 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
                        max_ctx_payload_size -= IT_PKT_HEADER_SIZE_CIP;
        }
 
-       err = iso_packets_buffer_init(&s->buffer, s->unit, QUEUE_LENGTH,
+       // This is a case that AMDTP streams in domain run just for MIDI
+       // substream. Use the number of events equivalent to 10 msec as
+       // interval of hardware IRQ.
+       if (events_per_period == 0)
+               events_per_period = amdtp_rate_table[s->sfc] / 100;
+       if (events_per_buffer == 0)
+               events_per_buffer = events_per_period * 3;
+
+       idle_irq_interval = DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_period,
+                                        amdtp_rate_table[s->sfc]);
+       s->queue_size = DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_buffer,
+                                    amdtp_rate_table[s->sfc]);
+
+       err = iso_packets_buffer_init(&s->buffer, s->unit, s->queue_size,
                                      max_ctx_payload_size, dir);
        if (err < 0)
                goto err_unlock;
 
+       if (is_irq_target) {
+               s->ctx_data.rx.events_per_period = events_per_period;
+               s->ctx_data.rx.event_count = 0;
+               ctx_cb = amdtp_stream_master_first_callback;
+               ctx_data = d;
+       } else {
+               ctx_cb = amdtp_stream_first_callback;
+               ctx_data = s;
+       }
+
        s->context = fw_iso_context_create(fw_parent_device(s->unit)->card,
                                          type, channel, speed, ctx_header_size,
-                                         amdtp_stream_first_callback, s);
+                                         ctx_cb, ctx_data);
        if (IS_ERR(s->context)) {
                err = PTR_ERR(s->context);
                if (err == -EBUSY)
@@ -981,7 +1114,7 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
        else
                s->tag = TAG_CIP;
 
-       s->pkt_descs = kcalloc(INTERRUPT_INTERVAL, sizeof(*s->pkt_descs),
+       s->pkt_descs = kcalloc(s->queue_size, sizeof(*s->pkt_descs),
                               GFP_KERNEL);
        if (!s->pkt_descs) {
                err = -ENOMEM;
@@ -991,12 +1124,21 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
        s->packet_index = 0;
        do {
                struct fw_iso_packet params;
+
                if (s->direction == AMDTP_IN_STREAM) {
                        err = queue_in_packet(s, &params);
                } else {
+                       bool sched_irq = false;
+
                        params.header_length = 0;
                        params.payload_length = 0;
-                       err = queue_out_packet(s, &params);
+
+                       if (is_irq_target) {
+                               sched_irq = !((s->packet_index + 1) %
+                                             idle_irq_interval);
+                       }
+
+                       err = queue_out_packet(s, &params, sched_irq);
                }
                if (err < 0)
                        goto err_pkt_descs;
@@ -1008,7 +1150,7 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
                tag |= FW_ISO_CONTEXT_MATCH_TAG0;
 
        s->callbacked = false;
-       err = fw_iso_context_start(s->context, -1, 0, tag);
+       err = fw_iso_context_start(s->context, start_cycle, 0, tag);
        if (err < 0)
                goto err_pkt_descs;
 
@@ -1029,54 +1171,69 @@ err_unlock:
 }
 
 /**
- * amdtp_stream_pcm_pointer - get the PCM buffer position
+ * amdtp_domain_stream_pcm_pointer - get the PCM buffer position
+ * @d: the AMDTP domain.
  * @s: the AMDTP stream that transports the PCM data
  *
  * Returns the current buffer position, in frames.
  */
-unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s)
+unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d,
+                                             struct amdtp_stream *s)
 {
-       /*
-        * This function is called in software IRQ context of period_tasklet or
-        * process context.
-        *
-        * When the software IRQ context was scheduled by software IRQ context
-        * of IR/IT contexts, queued packets were already handled. Therefore,
-        * no need to flush the queue in buffer anymore.
-        *
-        * When the process context reach here, some packets will be already
-        * queued in the buffer. These packets should be handled immediately
-        * to keep better granularity of PCM pointer.
-        *
-        * Later, the process context will sometimes schedules software IRQ
-        * context of the period_tasklet. Then, no need to flush the queue by
-        * the same reason as described for IR/IT contexts.
-        */
-       if (!in_interrupt() && amdtp_stream_running(s))
-               fw_iso_context_flush_completions(s->context);
+       struct amdtp_stream *irq_target = d->irq_target;
+
+       if (irq_target && amdtp_stream_running(irq_target)) {
+               // This function is called in software IRQ context of
+               // period_tasklet or process context.
+               //
+               // When the software IRQ context was scheduled by software IRQ
+               // context of IT contexts, queued packets were already handled.
+               // Therefore, no need to flush the queue in buffer furthermore.
+               //
+               // When the process context reach here, some packets will be
+               // already queued in the buffer. These packets should be handled
+               // immediately to keep better granularity of PCM pointer.
+               //
+               // Later, the process context will sometimes schedules software
+               // IRQ context of the period_tasklet. Then, no need to flush the
+               // queue by the same reason as described in the above
+               if (!in_interrupt()) {
+                       // Queued packet should be processed without any kernel
+                       // preemption to keep latency against bus cycle.
+                       preempt_disable();
+                       fw_iso_context_flush_completions(irq_target->context);
+                       preempt_enable();
+               }
+       }
 
        return READ_ONCE(s->pcm_buffer_pointer);
 }
-EXPORT_SYMBOL(amdtp_stream_pcm_pointer);
+EXPORT_SYMBOL_GPL(amdtp_domain_stream_pcm_pointer);
 
 /**
- * amdtp_stream_pcm_ack - acknowledge queued PCM frames
+ * amdtp_domain_stream_pcm_ack - acknowledge queued PCM frames
+ * @d: the AMDTP domain.
  * @s: the AMDTP stream that transfers the PCM frames
  *
  * Returns zero always.
  */
-int amdtp_stream_pcm_ack(struct amdtp_stream *s)
+int amdtp_domain_stream_pcm_ack(struct amdtp_domain *d, struct amdtp_stream *s)
 {
-       /*
-        * Process isochronous packets for recent isochronous cycle to handle
-        * queued PCM frames.
-        */
-       if (amdtp_stream_running(s))
-               fw_iso_context_flush_completions(s->context);
+       struct amdtp_stream *irq_target = d->irq_target;
+
+       // Process isochronous packets for recent isochronous cycle to handle
+       // queued PCM frames.
+       if (irq_target && amdtp_stream_running(irq_target)) {
+               // Queued packet should be processed without any kernel
+               // preemption to keep latency against bus cycle.
+               preempt_disable();
+               fw_iso_context_flush_completions(irq_target->context);
+               preempt_enable();
+       }
 
        return 0;
 }
-EXPORT_SYMBOL(amdtp_stream_pcm_ack);
+EXPORT_SYMBOL_GPL(amdtp_domain_stream_pcm_ack);
 
 /**
  * amdtp_stream_update - update the stream after a bus reset
@@ -1143,6 +1300,8 @@ int amdtp_domain_init(struct amdtp_domain *d)
 {
        INIT_LIST_HEAD(&d->streams);
 
+       d->events_per_period = 0;
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(amdtp_domain_init);
@@ -1184,26 +1343,105 @@ int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s,
 }
 EXPORT_SYMBOL_GPL(amdtp_domain_add_stream);
 
+static int get_current_cycle_time(struct fw_card *fw_card, int *cur_cycle)
+{
+       int generation;
+       int rcode;
+       __be32 reg;
+       u32 data;
+
+       // This is a request to local 1394 OHCI controller and expected to
+       // complete without any event waiting.
+       generation = fw_card->generation;
+       smp_rmb();      // node_id vs. generation.
+       rcode = fw_run_transaction(fw_card, TCODE_READ_QUADLET_REQUEST,
+                                  fw_card->node_id, generation, SCODE_100,
+                                  CSR_REGISTER_BASE + CSR_CYCLE_TIME,
+                                  &reg, sizeof(reg));
+       if (rcode != RCODE_COMPLETE)
+               return -EIO;
+
+       data = be32_to_cpu(reg);
+       *cur_cycle = data >> 12;
+
+       return 0;
+}
+
 /**
  * amdtp_domain_start - start sending packets for isoc context in the domain.
  * @d: the AMDTP domain.
+ * @ir_delay_cycle: the cycle delay to start all IR contexts.
  */
-int amdtp_domain_start(struct amdtp_domain *d)
+int amdtp_domain_start(struct amdtp_domain *d, unsigned int ir_delay_cycle)
 {
        struct amdtp_stream *s;
-       int err = 0;
+       int cycle;
+       int err;
 
+       // Select an IT context as IRQ target.
        list_for_each_entry(s, &d->streams, list) {
-               err = amdtp_stream_start(s, s->channel, s->speed);
-               if (err < 0)
+               if (s->direction == AMDTP_OUT_STREAM)
                        break;
        }
+       if (!s)
+               return -ENXIO;
+       d->irq_target = s;
 
-       if (err < 0) {
-               list_for_each_entry(s, &d->streams, list)
-                       amdtp_stream_stop(s);
+       if (ir_delay_cycle > 0) {
+               struct fw_card *fw_card = fw_parent_device(s->unit)->card;
+
+               err = get_current_cycle_time(fw_card, &cycle);
+               if (err < 0)
+                       return err;
+
+               // No need to care overflow in cycle field because of enough
+               // width.
+               cycle += ir_delay_cycle;
+
+               // Round up to sec field.
+               if ((cycle & 0x00001fff) >= CYCLES_PER_SECOND) {
+                       unsigned int sec;
+
+                       // The sec field can overflow.
+                       sec = (cycle & 0xffffe000) >> 13;
+                       cycle = (++sec << 13) |
+                               ((cycle & 0x00001fff) / CYCLES_PER_SECOND);
+               }
+
+               // In OHCI 1394 specification, lower 2 bits are available for
+               // sec field.
+               cycle &= 0x00007fff;
+       } else {
+               cycle = -1;
+       }
+
+       list_for_each_entry(s, &d->streams, list) {
+               int cycle_match;
+
+               if (s->direction == AMDTP_IN_STREAM) {
+                       cycle_match = cycle;
+               } else {
+                       // IT context starts immediately.
+                       cycle_match = -1;
+               }
+
+               if (s != d->irq_target) {
+                       err = amdtp_stream_start(s, s->channel, s->speed, d,
+                                                false, cycle_match);
+                       if (err < 0)
+                               goto error;
+               }
        }
 
+       s = d->irq_target;
+       err = amdtp_stream_start(s, s->channel, s->speed, d, true, -1);
+       if (err < 0)
+               goto error;
+
+       return 0;
+error:
+       list_for_each_entry(s, &d->streams, list)
+               amdtp_stream_stop(s);
        return err;
 }
 EXPORT_SYMBOL_GPL(amdtp_domain_start);
@@ -1216,10 +1454,17 @@ void amdtp_domain_stop(struct amdtp_domain *d)
 {
        struct amdtp_stream *s, *next;
 
+       if (d->irq_target)
+               amdtp_stream_stop(d->irq_target);
+
        list_for_each_entry_safe(s, next, &d->streams, list) {
                list_del(&s->list);
 
-               amdtp_stream_stop(s);
+               if (s != d->irq_target)
+                       amdtp_stream_stop(s);
        }
+
+       d->events_per_period = 0;
+       d->irq_target = NULL;
 }
 EXPORT_SYMBOL_GPL(amdtp_domain_stop);
index bbbca964b9b46be5b7ef4376f6318fd9ae51049a..f2d44e2dc3c8a960c8ecdb2a3056ea1aa22f82a5 100644 (file)
@@ -117,6 +117,7 @@ struct amdtp_stream {
        /* For packet processing. */
        struct fw_iso_context *context;
        struct iso_packets_buffer buffer;
+       unsigned int queue_size;
        int packet_index;
        struct pkt_desc *pkt_descs;
        int tag;
@@ -142,6 +143,10 @@ struct amdtp_stream {
                        // To generate CIP header.
                        unsigned int fdf;
                        int syt_override;
+
+                       // To generate constant hardware IRQ.
+                       unsigned int event_count;
+                       unsigned int events_per_period;
                } rx;
        } ctx_data;
 
@@ -194,8 +199,6 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
                                        struct snd_pcm_runtime *runtime);
 
 void amdtp_stream_pcm_prepare(struct amdtp_stream *s);
-unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s);
-int amdtp_stream_pcm_ack(struct amdtp_stream *s);
 void amdtp_stream_pcm_abort(struct amdtp_stream *s);
 
 extern const unsigned int amdtp_syt_intervals[CIP_SFC_COUNT];
@@ -272,6 +275,11 @@ static inline bool amdtp_stream_wait_callback(struct amdtp_stream *s,
 
 struct amdtp_domain {
        struct list_head streams;
+
+       unsigned int events_per_period;
+       unsigned int events_per_buffer;
+
+       struct amdtp_stream *irq_target;
 };
 
 int amdtp_domain_init(struct amdtp_domain *d);
@@ -280,7 +288,21 @@ void amdtp_domain_destroy(struct amdtp_domain *d);
 int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s,
                            int channel, int speed);
 
-int amdtp_domain_start(struct amdtp_domain *d);
+int amdtp_domain_start(struct amdtp_domain *d, unsigned int ir_delay_cycle);
 void amdtp_domain_stop(struct amdtp_domain *d);
 
+static inline int amdtp_domain_set_events_per_period(struct amdtp_domain *d,
+                                               unsigned int events_per_period,
+                                               unsigned int events_per_buffer)
+{
+       d->events_per_period = events_per_period;
+       d->events_per_buffer = events_per_buffer;
+
+       return 0;
+}
+
+unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d,
+                                             struct amdtp_stream *s);
+int amdtp_domain_stream_pcm_ack(struct amdtp_domain *d, struct amdtp_stream *s);
+
 #endif
index 356d6ba609590750a7b08e29de5bd263df5fc80d..d1ad9a8451bcf04e498bfd39121760c624f42fd9 100644 (file)
@@ -217,7 +217,9 @@ int snd_bebob_stream_get_clock_src(struct snd_bebob *bebob,
                                   enum snd_bebob_clock_type *src);
 int snd_bebob_stream_discover(struct snd_bebob *bebob);
 int snd_bebob_stream_init_duplex(struct snd_bebob *bebob);
-int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate);
+int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate,
+                                   unsigned int frames_per_period,
+                                   unsigned int frames_per_buffer);
 int snd_bebob_stream_start_duplex(struct snd_bebob *bebob);
 void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob);
 void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob);
index 4d8805fa8a00a1f06ea5115aaaa89802ac685d52..6f597d03e7c157ae45476cfd888e64720d1604b0 100644 (file)
@@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream)
                return err;
 
        mutex_lock(&bebob->mutex);
-       err = snd_bebob_stream_reserve_duplex(bebob, 0);
+       err = snd_bebob_stream_reserve_duplex(bebob, 0, 0, 0);
        if (err >= 0) {
                ++bebob->substreams_counter;
                err = snd_bebob_stream_start_duplex(bebob);
index 0fb9eed468378e53643f4f76425a784cf1281be9..1b100159f4c5940189215f66062df578a0f84a82 100644 (file)
@@ -129,18 +129,17 @@ end:
        return err;
 }
 
-static int
-pcm_open(struct snd_pcm_substream *substream)
+static int pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_bebob *bebob = substream->private_data;
        const struct snd_bebob_rate_spec *spec = bebob->spec->rate;
-       unsigned int sampling_rate;
+       struct amdtp_domain *d = &bebob->domain;
        enum snd_bebob_clock_type src;
        int err;
 
        err = snd_bebob_stream_lock_try(bebob);
        if (err < 0)
-               goto end;
+               return err;
 
        err = pcm_init_hw_params(bebob, substream);
        if (err < 0)
@@ -150,15 +149,20 @@ pcm_open(struct snd_pcm_substream *substream)
        if (err < 0)
                goto err_locked;
 
-       /*
-        * When source of clock is internal or any PCM stream are running,
-        * the available sampling rate is limited at current sampling rate.
-        */
+       mutex_lock(&bebob->mutex);
+
+       // When source of clock is not internal or any stream is reserved for
+       // transmission of PCM frames, the available sampling rate is limited
+       // at current one.
        if (src == SND_BEBOB_CLOCK_TYPE_EXTERNAL ||
-           amdtp_stream_pcm_running(&bebob->tx_stream) ||
-           amdtp_stream_pcm_running(&bebob->rx_stream)) {
+           (bebob->substreams_counter > 0 && d->events_per_period > 0)) {
+               unsigned int frames_per_period = d->events_per_period;
+               unsigned int frames_per_buffer = d->events_per_buffer;
+               unsigned int sampling_rate;
+
                err = spec->get(bebob, &sampling_rate);
                if (err < 0) {
+                       mutex_unlock(&bebob->mutex);
                        dev_err(&bebob->unit->device,
                                "fail to get sampling rate: %d\n", err);
                        goto err_locked;
@@ -166,11 +170,31 @@ pcm_open(struct snd_pcm_substream *substream)
 
                substream->runtime->hw.rate_min = sampling_rate;
                substream->runtime->hw.rate_max = sampling_rate;
+
+               if (frames_per_period > 0) {
+                       err = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                       SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+                                       frames_per_period, frames_per_period);
+                       if (err < 0) {
+                               mutex_unlock(&bebob->mutex);
+                               goto err_locked;
+                       }
+
+                       err = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                       SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                       frames_per_buffer, frames_per_buffer);
+                       if (err < 0) {
+                               mutex_unlock(&bebob->mutex);
+                               goto err_locked;
+                       }
+               }
        }
 
+       mutex_unlock(&bebob->mutex);
+
        snd_pcm_set_sync(substream);
-end:
-       return err;
+
+       return 0;
 err_locked:
        snd_bebob_stream_lock_release(bebob);
        return err;
@@ -197,9 +221,12 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                unsigned int rate = params_rate(hw_params);
+               unsigned int frames_per_period = params_period_size(hw_params);
+               unsigned int frames_per_buffer = params_buffer_size(hw_params);
 
                mutex_lock(&bebob->mutex);
-               err = snd_bebob_stream_reserve_duplex(bebob, rate);
+               err = snd_bebob_stream_reserve_duplex(bebob, rate,
+                                       frames_per_period, frames_per_buffer);
                if (err >= 0)
                        ++bebob->substreams_counter;
                mutex_unlock(&bebob->mutex);
@@ -286,31 +313,33 @@ pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
        return 0;
 }
 
-static snd_pcm_uframes_t
-pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
+static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
 {
        struct snd_bebob *bebob = sbstrm->private_data;
-       return amdtp_stream_pcm_pointer(&bebob->tx_stream);
+
+       return amdtp_domain_stream_pcm_pointer(&bebob->domain,
+                                              &bebob->tx_stream);
 }
-static snd_pcm_uframes_t
-pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
+static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
 {
        struct snd_bebob *bebob = sbstrm->private_data;
-       return amdtp_stream_pcm_pointer(&bebob->rx_stream);
+
+       return amdtp_domain_stream_pcm_pointer(&bebob->domain,
+                                              &bebob->rx_stream);
 }
 
 static int pcm_capture_ack(struct snd_pcm_substream *substream)
 {
        struct snd_bebob *bebob = substream->private_data;
 
-       return amdtp_stream_pcm_ack(&bebob->tx_stream);
+       return amdtp_domain_stream_pcm_ack(&bebob->domain, &bebob->tx_stream);
 }
 
 static int pcm_playback_ack(struct snd_pcm_substream *substream)
 {
        struct snd_bebob *bebob = substream->private_data;
 
-       return amdtp_stream_pcm_ack(&bebob->rx_stream);
+       return amdtp_domain_stream_pcm_ack(&bebob->domain, &bebob->rx_stream);
 }
 
 int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
index 6c1497d9f52bac0e62b0cfce5bb0e59c64c70d31..f7f0db5aa811224975b9f52d12d093720517d505 100644 (file)
@@ -553,7 +553,9 @@ static int keep_resources(struct snd_bebob *bebob, struct amdtp_stream *stream,
        return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
 }
 
-int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate)
+int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate,
+                                   unsigned int frames_per_period,
+                                   unsigned int frames_per_buffer)
 {
        unsigned int curr_rate;
        int err;
@@ -606,6 +608,14 @@ int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate)
                        cmp_connection_release(&bebob->out_conn);
                        return err;
                }
+
+               err = amdtp_domain_set_events_per_period(&bebob->domain,
+                                       frames_per_period, frames_per_buffer);
+               if (err < 0) {
+                       cmp_connection_release(&bebob->out_conn);
+                       cmp_connection_release(&bebob->in_conn);
+                       return err;
+               }
        }
 
        return 0;
@@ -647,7 +657,15 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
                if (err < 0)
                        goto error;
 
-               err = amdtp_domain_start(&bebob->domain);
+               // The device postpones start of transmission mostly for 1 sec
+               // after receives packets firstly. For safe, IR context starts
+               // 1.5 sec (=12000 cycles) later. This is within 2.0 sec
+               // (=CALLBACK_TIMEOUT).
+               // Furthermore, some devices transfer isoc packets with
+               // discontinuous counter in the beginning of packet streaming.
+               // The delay has an effect to avoid detection of this
+               // discontinuity.
+               err = amdtp_domain_start(&bebob->domain, 12000);
                if (err < 0)
                        goto error;
 
index c9e19bddfc09e812085a5771b3f3b7db876ceaac..4c2998034313587ac8a53f18ad708db6fb32e4a7 100644 (file)
@@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream)
 
        mutex_lock(&dice->mutex);
 
-       err = snd_dice_stream_reserve_duplex(dice, 0);
+       err = snd_dice_stream_reserve_duplex(dice, 0, 0, 0);
        if (err >= 0) {
                ++dice->substreams_counter;
                err = snd_dice_stream_start_duplex(dice);
index 94a4dccfc381b9ed5b76a810597843b9cc9c4768..f1848fb39bd0e6062ff82b9952afc00ccdcbdd54 100644 (file)
@@ -164,13 +164,14 @@ static int init_hw_info(struct snd_dice *dice,
 static int pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_dice *dice = substream->private_data;
+       struct amdtp_domain *d = &dice->domain;
        unsigned int source;
        bool internal;
        int err;
 
        err = snd_dice_stream_lock_try(dice);
        if (err < 0)
-               goto end;
+               return err;
 
        err = init_hw_info(dice, substream);
        if (err < 0)
@@ -195,27 +196,56 @@ static int pcm_open(struct snd_pcm_substream *substream)
                break;
        }
 
-       /*
-        * When source of clock is not internal or any PCM streams are running,
-        * available sampling rate is limited at current sampling rate.
-        */
+       mutex_lock(&dice->mutex);
+
+       // When source of clock is not internal or any stream is reserved for
+       // transmission of PCM frames, the available sampling rate is limited
+       // at current one.
        if (!internal ||
-           amdtp_stream_pcm_running(&dice->tx_stream[0]) ||
-           amdtp_stream_pcm_running(&dice->tx_stream[1]) ||
-           amdtp_stream_pcm_running(&dice->rx_stream[0]) ||
-           amdtp_stream_pcm_running(&dice->rx_stream[1])) {
+           (dice->substreams_counter > 0 && d->events_per_period > 0)) {
+               unsigned int frames_per_period = d->events_per_period;
+               unsigned int frames_per_buffer = d->events_per_buffer;
                unsigned int rate;
 
                err = snd_dice_transaction_get_rate(dice, &rate);
-               if (err < 0)
+               if (err < 0) {
+                       mutex_unlock(&dice->mutex);
                        goto err_locked;
+               }
+
                substream->runtime->hw.rate_min = rate;
                substream->runtime->hw.rate_max = rate;
+
+               if (frames_per_period > 0) {
+                       // For double_pcm_frame quirk.
+                       if (rate > 96000) {
+                               frames_per_period *= 2;
+                               frames_per_buffer *= 2;
+                       }
+
+                       err = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                       SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+                                       frames_per_period, frames_per_period);
+                       if (err < 0) {
+                               mutex_unlock(&dice->mutex);
+                               goto err_locked;
+                       }
+
+                       err = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                       SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                       frames_per_buffer, frames_per_buffer);
+                       if (err < 0) {
+                               mutex_unlock(&dice->mutex);
+                               goto err_locked;
+                       }
+               }
        }
 
+       mutex_unlock(&dice->mutex);
+
        snd_pcm_set_sync(substream);
-end:
-       return err;
+
+       return 0;
 err_locked:
        snd_dice_stream_lock_release(dice);
        return err;
@@ -243,9 +273,17 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                unsigned int rate = params_rate(hw_params);
+               unsigned int events_per_period = params_period_size(hw_params);
+               unsigned int events_per_buffer = params_buffer_size(hw_params);
 
                mutex_lock(&dice->mutex);
-               err = snd_dice_stream_reserve_duplex(dice, rate);
+               // For double_pcm_frame quirk.
+               if (rate > 96000) {
+                       events_per_period /= 2;
+                       events_per_buffer /= 2;
+               }
+               err = snd_dice_stream_reserve_duplex(dice, rate,
+                                       events_per_period, events_per_buffer);
                if (err >= 0)
                        ++dice->substreams_counter;
                mutex_unlock(&dice->mutex);
@@ -341,14 +379,14 @@ static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
        struct snd_dice *dice = substream->private_data;
        struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 
-       return amdtp_stream_pcm_pointer(stream);
+       return amdtp_domain_stream_pcm_pointer(&dice->domain, stream);
 }
 static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
 {
        struct snd_dice *dice = substream->private_data;
        struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 
-       return amdtp_stream_pcm_pointer(stream);
+       return amdtp_domain_stream_pcm_pointer(&dice->domain, stream);
 }
 
 static int capture_ack(struct snd_pcm_substream *substream)
@@ -356,7 +394,7 @@ static int capture_ack(struct snd_pcm_substream *substream)
        struct snd_dice *dice = substream->private_data;
        struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 
-       return amdtp_stream_pcm_ack(stream);
+       return amdtp_domain_stream_pcm_ack(&dice->domain, stream);
 }
 
 static int playback_ack(struct snd_pcm_substream *substream)
@@ -364,7 +402,7 @@ static int playback_ack(struct snd_pcm_substream *substream)
        struct snd_dice *dice = substream->private_data;
        struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 
-       return amdtp_stream_pcm_ack(stream);
+       return amdtp_domain_stream_pcm_ack(&dice->domain, stream);
 }
 
 int snd_dice_create_pcm(struct snd_dice *dice)
index f6a8627ae5a2b0ce417ecddda9485dae93630629..6a3d60913e10ca85afeea21f3a8bfe2f49119390 100644 (file)
@@ -278,7 +278,9 @@ static void finish_session(struct snd_dice *dice, struct reg_params *tx_params,
        snd_dice_transaction_clear_enable(dice);
 }
 
-int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate)
+int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate,
+                                  unsigned int events_per_period,
+                                  unsigned int events_per_buffer)
 {
        unsigned int curr_rate;
        int err;
@@ -324,6 +326,11 @@ int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate)
                                          &rx_params);
                if (err < 0)
                        goto error;
+
+               err = amdtp_domain_set_events_per_period(&dice->domain,
+                                       events_per_period, events_per_buffer);
+               if (err < 0)
+                       goto error;
        }
 
        return 0;
@@ -455,7 +462,7 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice)
                        goto error;
                }
 
-               err = amdtp_domain_start(&dice->domain);
+               err = amdtp_domain_start(&dice->domain, 0);
                if (err < 0)
                        goto error;
 
index fa6d74303f54c578142d6f2d9cc216374a1eed38..16366773e22e841915df733874ab01009e99d14f 100644 (file)
@@ -210,7 +210,9 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice);
 void snd_dice_stream_stop_duplex(struct snd_dice *dice);
 int snd_dice_stream_init_duplex(struct snd_dice *dice);
 void snd_dice_stream_destroy_duplex(struct snd_dice *dice);
-int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate);
+int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate,
+                                  unsigned int events_per_period,
+                                  unsigned int events_per_buffer);
 void snd_dice_stream_update_duplex(struct snd_dice *dice);
 int snd_dice_stream_detect_current_formats(struct snd_dice *dice);
 
index 2b57ece891018814e69868396df6f48db0ee1253..68eb8c39afa6c58ea7994172ea1773b5ac654aed 100644 (file)
@@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream)
                return err;
 
        mutex_lock(&dg00x->mutex);
-       err = snd_dg00x_stream_reserve_duplex(dg00x, 0);
+       err = snd_dg00x_stream_reserve_duplex(dg00x, 0, 0, 0);
        if (err >= 0) {
                ++dg00x->substreams_counter;
                err = snd_dg00x_stream_start_duplex(dg00x);
index 18e561b26625d63fed15b1a0a2eee555c486fe11..8befc5d2ef220b9df5a3c06ad209b0d3d1cd5c75 100644 (file)
@@ -100,14 +100,14 @@ static int pcm_init_hw_params(struct snd_dg00x *dg00x,
 static int pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_dg00x *dg00x = substream->private_data;
+       struct amdtp_domain *d = &dg00x->domain;
        enum snd_dg00x_clock clock;
        bool detect;
-       unsigned int rate;
        int err;
 
        err = snd_dg00x_stream_lock_try(dg00x);
        if (err < 0)
-               goto end;
+               return err;
 
        err = pcm_init_hw_params(dg00x, substream);
        if (err < 0)
@@ -127,19 +127,49 @@ static int pcm_open(struct snd_pcm_substream *substream)
                }
        }
 
+       mutex_lock(&dg00x->mutex);
+
+       // When source of clock is not internal or any stream is reserved for
+       // transmission of PCM frames, the available sampling rate is limited
+       // at current one.
        if ((clock != SND_DG00X_CLOCK_INTERNAL) ||
-           amdtp_stream_pcm_running(&dg00x->rx_stream) ||
-           amdtp_stream_pcm_running(&dg00x->tx_stream)) {
+           (dg00x->substreams_counter > 0 && d->events_per_period > 0)) {
+               unsigned int frames_per_period = d->events_per_period;
+               unsigned int frames_per_buffer = d->events_per_buffer;
+               unsigned int rate;
+
                err = snd_dg00x_stream_get_external_rate(dg00x, &rate);
-               if (err < 0)
+               if (err < 0) {
+                       mutex_unlock(&dg00x->mutex);
                        goto err_locked;
+               }
                substream->runtime->hw.rate_min = rate;
                substream->runtime->hw.rate_max = rate;
+
+               if (frames_per_period > 0) {
+                       err = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                       SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+                                       frames_per_period, frames_per_period);
+                       if (err < 0) {
+                               mutex_unlock(&dg00x->mutex);
+                               goto err_locked;
+                       }
+
+                       err = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                       SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                       frames_per_buffer, frames_per_buffer);
+                       if (err < 0) {
+                               mutex_unlock(&dg00x->mutex);
+                               goto err_locked;
+                       }
+               }
        }
 
+       mutex_unlock(&dg00x->mutex);
+
        snd_pcm_set_sync(substream);
-end:
-       return err;
+
+       return 0;
 err_locked:
        snd_dg00x_stream_lock_release(dg00x);
        return err;
@@ -167,9 +197,12 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                unsigned int rate = params_rate(hw_params);
+               unsigned int frames_per_period = params_period_size(hw_params);
+               unsigned int frames_per_buffer = params_buffer_size(hw_params);
 
                mutex_lock(&dg00x->mutex);
-               err = snd_dg00x_stream_reserve_duplex(dg00x, rate);
+               err = snd_dg00x_stream_reserve_duplex(dg00x, rate,
+                                       frames_per_period, frames_per_buffer);
                if (err >= 0)
                        ++dg00x->substreams_counter;
                mutex_unlock(&dg00x->mutex);
@@ -268,28 +301,28 @@ static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
 {
        struct snd_dg00x *dg00x = sbstrm->private_data;
 
-       return amdtp_stream_pcm_pointer(&dg00x->tx_stream);
+       return amdtp_domain_stream_pcm_pointer(&dg00x->domain, &dg00x->tx_stream);
 }
 
 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
 {
        struct snd_dg00x *dg00x = sbstrm->private_data;
 
-       return amdtp_stream_pcm_pointer(&dg00x->rx_stream);
+       return amdtp_domain_stream_pcm_pointer(&dg00x->domain, &dg00x->rx_stream);
 }
 
 static int pcm_capture_ack(struct snd_pcm_substream *substream)
 {
        struct snd_dg00x *dg00x = substream->private_data;
 
-       return amdtp_stream_pcm_ack(&dg00x->tx_stream);
+       return amdtp_domain_stream_pcm_ack(&dg00x->domain, &dg00x->tx_stream);
 }
 
 static int pcm_playback_ack(struct snd_pcm_substream *substream)
 {
        struct snd_dg00x *dg00x = substream->private_data;
 
-       return amdtp_stream_pcm_ack(&dg00x->rx_stream);
+       return amdtp_domain_stream_pcm_ack(&dg00x->domain, &dg00x->rx_stream);
 }
 
 int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
index d6a92460060f649eb7f006e4215a4dd36fdee855..405d6903bfbc3d0eb1e5ba3c52aa1ef4afac6b5b 100644 (file)
@@ -283,7 +283,9 @@ void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x)
        destroy_stream(dg00x, &dg00x->tx_stream);
 }
 
-int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate)
+int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate,
+                                   unsigned int frames_per_period,
+                                   unsigned int frames_per_buffer)
 {
        unsigned int curr_rate;
        int err;
@@ -315,6 +317,14 @@ int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate)
                        fw_iso_resources_free(&dg00x->rx_resources);
                        return err;
                }
+
+               err = amdtp_domain_set_events_per_period(&dg00x->domain,
+                                       frames_per_period, frames_per_buffer);
+               if (err < 0) {
+                       fw_iso_resources_free(&dg00x->rx_resources);
+                       fw_iso_resources_free(&dg00x->tx_resources);
+                       return err;
+               }
        }
 
        return 0;
@@ -365,7 +375,7 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
                if (err < 0)
                        goto error;
 
-               err = amdtp_domain_start(&dg00x->domain);
+               err = amdtp_domain_start(&dg00x->domain, 0);
                if (err < 0)
                        goto error;
 
index 8041c65f27362ef0db2d2c4122e1981a479444d1..129de8edd5eab157ed18aa0e6c9e47228214b6f9 100644 (file)
@@ -141,7 +141,9 @@ int snd_dg00x_stream_get_clock(struct snd_dg00x *dg00x,
 int snd_dg00x_stream_check_external_clock(struct snd_dg00x *dg00x,
                                          bool *detect);
 int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x);
-int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate);
+int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate,
+                                   unsigned int frames_per_period,
+                                   unsigned int frames_per_buffer);
 int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x);
 void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x);
 void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x);
index 9eab3ad283ce4a4ffc7365e99343c11321a105e7..c29f87a65c0fcc8f9cade0df3936873da092e537 100644 (file)
@@ -139,6 +139,7 @@ static int pcm_init_hw_params(struct snd_ff *ff,
 static int pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_ff *ff = substream->private_data;
+       struct amdtp_domain *d = &ff->domain;
        unsigned int rate;
        enum snd_ff_clock_src src;
        int i, err;
@@ -155,16 +156,21 @@ static int pcm_open(struct snd_pcm_substream *substream)
        if (err < 0)
                goto release_lock;
 
+       mutex_lock(&ff->mutex);
+
+       // When source of clock is not internal or any stream is reserved for
+       // transmission of PCM frames, the available sampling rate is limited
+       // at current one.
        if (src != SND_FF_CLOCK_SRC_INTERNAL) {
                for (i = 0; i < CIP_SFC_COUNT; ++i) {
                        if (amdtp_rate_table[i] == rate)
                                break;
                }
-               /*
-                * The unit is configured at sampling frequency which packet
-                * streaming engine can't support.
-                */
+
+               // The unit is configured at sampling frequency which packet
+               // streaming engine can't support.
                if (i >= CIP_SFC_COUNT) {
+                       mutex_unlock(&ff->mutex);
                        err = -EIO;
                        goto release_lock;
                }
@@ -172,14 +178,34 @@ static int pcm_open(struct snd_pcm_substream *substream)
                substream->runtime->hw.rate_min = rate;
                substream->runtime->hw.rate_max = rate;
        } else {
-               if (amdtp_stream_pcm_running(&ff->rx_stream) ||
-                   amdtp_stream_pcm_running(&ff->tx_stream)) {
+               if (ff->substreams_counter > 0) {
+                       unsigned int frames_per_period = d->events_per_period;
+                       unsigned int frames_per_buffer = d->events_per_buffer;
+
                        rate = amdtp_rate_table[ff->rx_stream.sfc];
                        substream->runtime->hw.rate_min = rate;
                        substream->runtime->hw.rate_max = rate;
+
+                       err = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                       SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+                                       frames_per_period, frames_per_period);
+                       if (err < 0) {
+                               mutex_unlock(&ff->mutex);
+                               goto release_lock;
+                       }
+
+                       err = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                       SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                       frames_per_buffer, frames_per_buffer);
+                       if (err < 0) {
+                               mutex_unlock(&ff->mutex);
+                               goto release_lock;
+                       }
                }
        }
 
+       mutex_unlock(&ff->mutex);
+
        snd_pcm_set_sync(substream);
 
        return 0;
@@ -211,9 +237,12 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                unsigned int rate = params_rate(hw_params);
+               unsigned int frames_per_period = params_period_size(hw_params);
+               unsigned int frames_per_buffer = params_buffer_size(hw_params);
 
                mutex_lock(&ff->mutex);
-               err = snd_ff_stream_reserve_duplex(ff, rate);
+               err = snd_ff_stream_reserve_duplex(ff, rate, frames_per_period,
+                                                  frames_per_buffer);
                if (err >= 0)
                        ++ff->substreams_counter;
                mutex_unlock(&ff->mutex);
@@ -312,28 +341,28 @@ static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
 {
        struct snd_ff *ff = sbstrm->private_data;
 
-       return amdtp_stream_pcm_pointer(&ff->tx_stream);
+       return amdtp_domain_stream_pcm_pointer(&ff->domain, &ff->tx_stream);
 }
 
 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
 {
        struct snd_ff *ff = sbstrm->private_data;
 
-       return amdtp_stream_pcm_pointer(&ff->rx_stream);
+       return amdtp_domain_stream_pcm_pointer(&ff->domain, &ff->rx_stream);
 }
 
 static int pcm_capture_ack(struct snd_pcm_substream *substream)
 {
        struct snd_ff *ff = substream->private_data;
 
-       return amdtp_stream_pcm_ack(&ff->tx_stream);
+       return amdtp_domain_stream_pcm_ack(&ff->domain, &ff->tx_stream);
 }
 
 static int pcm_playback_ack(struct snd_pcm_substream *substream)
 {
        struct snd_ff *ff = substream->private_data;
 
-       return amdtp_stream_pcm_ack(&ff->rx_stream);
+       return amdtp_domain_stream_pcm_ack(&ff->domain, &ff->rx_stream);
 }
 
 int snd_ff_create_pcm_devices(struct snd_ff *ff)
index e8e6f9fd64339d2becc5d68888d6772cd411b3b6..63b79c4a54059db4fee7ab15c1f9b27ca2ff8874 100644 (file)
@@ -106,7 +106,9 @@ void snd_ff_stream_destroy_duplex(struct snd_ff *ff)
        destroy_stream(ff, &ff->tx_stream);
 }
 
-int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate)
+int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate,
+                                unsigned int frames_per_period,
+                                unsigned int frames_per_buffer)
 {
        unsigned int curr_rate;
        enum snd_ff_clock_src src;
@@ -150,6 +152,14 @@ int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate)
                err = ff->spec->protocol->allocate_resources(ff, rate);
                if (err < 0)
                        return err;
+
+               err = amdtp_domain_set_events_per_period(&ff->domain,
+                                       frames_per_period, frames_per_buffer);
+               if (err < 0) {
+                       fw_iso_resources_free(&ff->tx_resources);
+                       fw_iso_resources_free(&ff->rx_resources);
+                       return err;
+               }
        }
 
        return 0;
@@ -174,6 +184,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
         */
        if (!amdtp_stream_running(&ff->rx_stream)) {
                int spd = fw_parent_device(ff->unit)->max_speed;
+               unsigned int ir_delay_cycle;
 
                err = ff->spec->protocol->begin_session(ff, rate);
                if (err < 0)
@@ -189,7 +200,14 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
                if (err < 0)
                        goto error;
 
-               err = amdtp_domain_start(&ff->domain);
+               // The device postpones start of transmission mostly for several
+               // cycles after receiving packets firstly.
+               if (ff->spec->protocol == &snd_ff_protocol_ff800)
+                       ir_delay_cycle = 800;   // = 100 msec
+               else
+                       ir_delay_cycle = 16;    // = 2 msec
+
+               err = amdtp_domain_start(&ff->domain, ir_delay_cycle);
                if (err < 0)
                        goto error;
 
index b4c22ca6079ee41bef2a8f6f34fe712bb15e9ede..dc7a20f75983fa71dfea27312cfddf074590bbb6 100644 (file)
@@ -139,7 +139,9 @@ int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
                                      enum snd_ff_stream_mode *mode);
 int snd_ff_stream_init_duplex(struct snd_ff *ff);
 void snd_ff_stream_destroy_duplex(struct snd_ff *ff);
-int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate);
+int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate,
+                                unsigned int frames_per_period,
+                                unsigned int frames_per_buffer);
 int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate);
 void snd_ff_stream_stop_duplex(struct snd_ff *ff);
 void snd_ff_stream_update_duplex(struct snd_ff *ff);
index 4cda297f843864d2e6ba13353e7d6ba3cdc70c6b..dda797209a27bb3be7f19d3ed2a8d12979450186 100644 (file)
@@ -207,7 +207,9 @@ int snd_efw_command_get_sampling_rate(struct snd_efw *efw, unsigned int *rate);
 int snd_efw_command_set_sampling_rate(struct snd_efw *efw, unsigned int rate);
 
 int snd_efw_stream_init_duplex(struct snd_efw *efw);
-int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate);
+int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate,
+                                 unsigned int frames_per_period,
+                                 unsigned int frames_per_buffer);
 int snd_efw_stream_start_duplex(struct snd_efw *efw);
 void snd_efw_stream_stop_duplex(struct snd_efw *efw);
 void snd_efw_stream_update_duplex(struct snd_efw *efw);
index a9f4a9630d15e4d423362329ebf8dce4ac6d1817..84621e3568482431d4334a5d4afb773dfb4a63a7 100644 (file)
@@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream)
                goto end;
 
        mutex_lock(&efw->mutex);
-       err = snd_efw_stream_reserve_duplex(efw, 0);
+       err = snd_efw_stream_reserve_duplex(efw, 0, 0, 0);
        if (err >= 0) {
                ++efw->substreams_counter;
                err = snd_efw_stream_start_duplex(efw);
index a7025dccc75489cefde6340b6b5d124cb7a3ba91..64c1bcf28dfa2a422ad54ff46d5d03b42c005c3e 100644 (file)
@@ -173,13 +173,13 @@ end:
 static int pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_efw *efw = substream->private_data;
-       unsigned int sampling_rate;
+       struct amdtp_domain *d = &efw->domain;
        enum snd_efw_clock_source clock_source;
        int err;
 
        err = snd_efw_stream_lock_try(efw);
        if (err < 0)
-               goto end;
+               return err;
 
        err = pcm_init_hw_params(efw, substream);
        if (err < 0)
@@ -189,23 +189,49 @@ static int pcm_open(struct snd_pcm_substream *substream)
        if (err < 0)
                goto err_locked;
 
-       /*
-        * When source of clock is not internal or any PCM streams are running,
-        * available sampling rate is limited at current sampling rate.
-        */
+       mutex_lock(&efw->mutex);
+
+       // When source of clock is not internal or any stream is reserved for
+       // transmission of PCM frames, the available sampling rate is limited
+       // at current one.
        if ((clock_source != SND_EFW_CLOCK_SOURCE_INTERNAL) ||
-           amdtp_stream_pcm_running(&efw->tx_stream) ||
-           amdtp_stream_pcm_running(&efw->rx_stream)) {
+           (efw->substreams_counter > 0 && d->events_per_period > 0)) {
+               unsigned int frames_per_period = d->events_per_period;
+               unsigned int frames_per_buffer = d->events_per_buffer;
+               unsigned int sampling_rate;
+
                err = snd_efw_command_get_sampling_rate(efw, &sampling_rate);
-               if (err < 0)
+               if (err < 0) {
+                       mutex_unlock(&efw->mutex);
                        goto err_locked;
+               }
                substream->runtime->hw.rate_min = sampling_rate;
                substream->runtime->hw.rate_max = sampling_rate;
+
+               if (frames_per_period > 0) {
+                       err = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                       SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+                                       frames_per_period, frames_per_period);
+                       if (err < 0) {
+                               mutex_unlock(&efw->mutex);
+                               goto err_locked;
+                       }
+
+                       err = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                       SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                       frames_per_buffer, frames_per_buffer);
+                       if (err < 0) {
+                               mutex_unlock(&efw->mutex);
+                               goto err_locked;
+                       }
+               }
        }
 
+       mutex_unlock(&efw->mutex);
+
        snd_pcm_set_sync(substream);
-end:
-       return err;
+
+       return 0;
 err_locked:
        snd_efw_stream_lock_release(efw);
        return err;
@@ -231,9 +257,12 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                unsigned int rate = params_rate(hw_params);
+               unsigned int frames_per_period = params_period_size(hw_params);
+               unsigned int frames_per_buffer = params_buffer_size(hw_params);
 
                mutex_lock(&efw->mutex);
-               err = snd_efw_stream_reserve_duplex(efw, rate);
+               err = snd_efw_stream_reserve_duplex(efw, rate,
+                                       frames_per_period, frames_per_buffer);
                if (err >= 0)
                        ++efw->substreams_counter;
                mutex_unlock(&efw->mutex);
@@ -319,26 +348,28 @@ static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
 {
        struct snd_efw *efw = sbstrm->private_data;
-       return amdtp_stream_pcm_pointer(&efw->tx_stream);
+
+       return amdtp_domain_stream_pcm_pointer(&efw->domain, &efw->tx_stream);
 }
 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
 {
        struct snd_efw *efw = sbstrm->private_data;
-       return amdtp_stream_pcm_pointer(&efw->rx_stream);
+
+       return amdtp_domain_stream_pcm_pointer(&efw->domain, &efw->rx_stream);
 }
 
 static int pcm_capture_ack(struct snd_pcm_substream *substream)
 {
        struct snd_efw *efw = substream->private_data;
 
-       return amdtp_stream_pcm_ack(&efw->tx_stream);
+       return amdtp_domain_stream_pcm_ack(&efw->domain, &efw->tx_stream);
 }
 
 static int pcm_playback_ack(struct snd_pcm_substream *substream)
 {
        struct snd_efw *efw = substream->private_data;
 
-       return amdtp_stream_pcm_ack(&efw->rx_stream);
+       return amdtp_domain_stream_pcm_ack(&efw->domain, &efw->rx_stream);
 }
 
 int snd_efw_create_pcm_devices(struct snd_efw *efw)
index f2de304d2f26a6fb214876eae8b164e4a96709fa..2206af0fef4224aaff49d7963719d087be3d74e6 100644 (file)
@@ -181,7 +181,9 @@ static int keep_resources(struct snd_efw *efw, struct amdtp_stream *stream,
        return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
 }
 
-int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate)
+int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate,
+                                 unsigned int frames_per_period,
+                                 unsigned int frames_per_buffer)
 {
        unsigned int curr_rate;
        int err;
@@ -228,6 +230,14 @@ int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate)
                        cmp_connection_release(&efw->in_conn);
                        return err;
                }
+
+               err = amdtp_domain_set_events_per_period(&efw->domain,
+                                       frames_per_period, frames_per_buffer);
+               if (err < 0) {
+                       cmp_connection_release(&efw->in_conn);
+                       cmp_connection_release(&efw->out_conn);
+                       return err;
+               }
        }
 
        return 0;
@@ -262,7 +272,7 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw)
                if (err < 0)
                        goto error;
 
-               err = amdtp_domain_start(&efw->domain);
+               err = amdtp_domain_start(&efw->domain, 0);
                if (err < 0)
                        goto error;
 
index 46a0035df31e5ea573df1af852bed26c92024fd9..2365f7dfde2664dfa3990e2e8ab848b2de5ada4d 100644 (file)
@@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream)
 
        mutex_lock(&motu->mutex);
 
-       err = snd_motu_stream_reserve_duplex(motu, 0);
+       err = snd_motu_stream_reserve_duplex(motu, 0, 0, 0);
        if (err >= 0) {
                ++motu->substreams_counter;
                err = snd_motu_stream_start_duplex(motu);
index aa2e584da6fe65bdbf37576ea9718807f8066343..55d3d6661731e9ca05533fbcda728d471fedd459 100644 (file)
@@ -134,8 +134,8 @@ static int pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_motu *motu = substream->private_data;
        const struct snd_motu_protocol *const protocol = motu->spec->protocol;
+       struct amdtp_domain *d = &motu->domain;
        enum snd_motu_clock_source src;
-       unsigned int rate;
        int err;
 
        err = snd_motu_stream_lock_try(motu);
@@ -152,28 +152,50 @@ static int pcm_open(struct snd_pcm_substream *substream)
        if (err < 0)
                goto err_locked;
 
-       /*
-        * When source of clock is not internal or any PCM streams are running,
-        * available sampling rate is limited at current sampling rate.
-        */
        err = protocol->get_clock_source(motu, &src);
        if (err < 0)
                goto err_locked;
+
+       // When source of clock is not internal or any stream is reserved for
+       // transmission of PCM frames, the available sampling rate is limited
+       // at current one.
        if (src != SND_MOTU_CLOCK_SOURCE_INTERNAL ||
-           amdtp_stream_pcm_running(&motu->tx_stream) ||
-           amdtp_stream_pcm_running(&motu->rx_stream)) {
+           (motu->substreams_counter > 0 && d->events_per_period > 0)) {
+               unsigned int frames_per_period = d->events_per_period;
+               unsigned int frames_per_buffer = d->events_per_buffer;
+               unsigned int rate;
+
                err = protocol->get_clock_rate(motu, &rate);
                if (err < 0)
                        goto err_locked;
+
                substream->runtime->hw.rate_min = rate;
                substream->runtime->hw.rate_max = rate;
+
+               if (frames_per_period > 0) {
+                       err = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                       SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+                                       frames_per_period, frames_per_period);
+                       if (err < 0) {
+                               mutex_unlock(&motu->mutex);
+                               goto err_locked;
+                       }
+
+                       err = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                       SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                       frames_per_buffer, frames_per_buffer);
+                       if (err < 0) {
+                               mutex_unlock(&motu->mutex);
+                               goto err_locked;
+                       }
+               }
        }
 
        snd_pcm_set_sync(substream);
 
        mutex_unlock(&motu->mutex);
 
-       return err;
+       return 0;
 err_locked:
        mutex_unlock(&motu->mutex);
        snd_motu_stream_lock_release(motu);
@@ -202,9 +224,12 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                unsigned int rate = params_rate(hw_params);
+               unsigned int frames_per_period = params_period_size(hw_params);
+               unsigned int frames_per_buffer = params_buffer_size(hw_params);
 
                mutex_lock(&motu->mutex);
-               err = snd_motu_stream_reserve_duplex(motu, rate);
+               err = snd_motu_stream_reserve_duplex(motu, rate,
+                                       frames_per_period, frames_per_buffer);
                if (err >= 0)
                        ++motu->substreams_counter;
                mutex_unlock(&motu->mutex);
@@ -295,27 +320,27 @@ static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
 {
        struct snd_motu *motu = substream->private_data;
 
-       return amdtp_stream_pcm_pointer(&motu->tx_stream);
+       return amdtp_domain_stream_pcm_pointer(&motu->domain, &motu->tx_stream);
 }
 static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
 {
        struct snd_motu *motu = substream->private_data;
 
-       return amdtp_stream_pcm_pointer(&motu->rx_stream);
+       return amdtp_domain_stream_pcm_pointer(&motu->domain, &motu->rx_stream);
 }
 
 static int capture_ack(struct snd_pcm_substream *substream)
 {
        struct snd_motu *motu = substream->private_data;
 
-       return amdtp_stream_pcm_ack(&motu->tx_stream);
+       return amdtp_domain_stream_pcm_ack(&motu->domain, &motu->tx_stream);
 }
 
 static int playback_ack(struct snd_pcm_substream *substream)
 {
        struct snd_motu *motu = substream->private_data;
 
-       return amdtp_stream_pcm_ack(&motu->rx_stream);
+       return amdtp_domain_stream_pcm_ack(&motu->domain, &motu->rx_stream);
 }
 
 int snd_motu_create_pcm_devices(struct snd_motu *motu)
index 813e38e6a86ec87ee7b797f2186d664212276979..a17ddceb1becd6f4d1bd14ea8be19abf8230c8e0 100644 (file)
@@ -133,7 +133,9 @@ int snd_motu_stream_cache_packet_formats(struct snd_motu *motu)
        return 0;
 }
 
-int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate)
+int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate,
+                                  unsigned int frames_per_period,
+                                  unsigned int frames_per_buffer)
 {
        unsigned int curr_rate;
        int err;
@@ -171,6 +173,14 @@ int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate)
                        fw_iso_resources_free(&motu->tx_resources);
                        return err;
                }
+
+               err = amdtp_domain_set_events_per_period(&motu->domain,
+                                       frames_per_period, frames_per_buffer);
+               if (err < 0) {
+                       fw_iso_resources_free(&motu->tx_resources);
+                       fw_iso_resources_free(&motu->rx_resources);
+                       return err;
+               }
        }
 
        return 0;
@@ -250,7 +260,7 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu)
                if (err < 0)
                        goto stop_streams;
 
-               err = amdtp_domain_start(&motu->domain);
+               err = amdtp_domain_start(&motu->domain, 0);
                if (err < 0)
                        goto stop_streams;
 
index 350ee2c16f4a89f9c29dad04aff17d626e4b266a..35ed8b6bb8e857c45105f723ce29022f4607979a 100644 (file)
@@ -154,7 +154,9 @@ void snd_motu_transaction_unregister(struct snd_motu *motu);
 int snd_motu_stream_init_duplex(struct snd_motu *motu);
 void snd_motu_stream_destroy_duplex(struct snd_motu *motu);
 int snd_motu_stream_cache_packet_formats(struct snd_motu *motu);
-int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate);
+int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate,
+                                  unsigned int frames_per_period,
+                                  unsigned int frames_per_buffer);
 int snd_motu_stream_start_duplex(struct snd_motu *motu);
 void snd_motu_stream_stop_duplex(struct snd_motu *motu);
 int snd_motu_stream_lock_try(struct snd_motu *motu);
index 9bdec08cb8eac0de6605c7832cb067043342c362..775cba3f1f028a03853394443ddc92e9aecad912 100644 (file)
@@ -18,7 +18,7 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream)
 
        mutex_lock(&oxfw->mutex);
 
-       err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0);
+       err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0, 0, 0);
        if (err >= 0) {
                ++oxfw->substreams_count;
                err = snd_oxfw_stream_start_duplex(oxfw);
@@ -45,7 +45,7 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream)
 
        mutex_lock(&oxfw->mutex);
 
-       err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0);
+       err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0, 0, 0);
        if (err >= 0) {
                ++oxfw->substreams_count;
                err = snd_oxfw_stream_start_duplex(oxfw);
index 7c6d1c277d4d9e52a107c8079ff9f5a3254b4ac9..74bd1811cec2943f7c9a39b2180d2b0b9cba7ae1 100644 (file)
@@ -170,30 +170,56 @@ end:
 static int pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_oxfw *oxfw = substream->private_data;
+       struct amdtp_domain *d = &oxfw->domain;
        int err;
 
        err = snd_oxfw_stream_lock_try(oxfw);
        if (err < 0)
-               goto end;
+               return err;
 
        err = init_hw_params(oxfw, substream);
        if (err < 0)
                goto err_locked;
 
-       /*
-        * When any PCM streams are already running, the available sampling
-        * rate is limited at current value.
-        */
-       if (amdtp_stream_pcm_running(&oxfw->tx_stream) ||
-           amdtp_stream_pcm_running(&oxfw->rx_stream)) {
+       mutex_lock(&oxfw->mutex);
+
+       // When source of clock is not internal or any stream is reserved for
+       // transmission of PCM frames, the available sampling rate is limited
+       // at current one.
+       if (oxfw->substreams_count > 0 && d->events_per_period > 0) {
+               unsigned int frames_per_period = d->events_per_period;
+               unsigned int frames_per_buffer = d->events_per_buffer;
+
                err = limit_to_current_params(substream);
-               if (err < 0)
-                       goto end;
+               if (err < 0) {
+                       mutex_unlock(&oxfw->mutex);
+                       goto err_locked;
+               }
+
+               if (frames_per_period > 0) {
+                       err = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                       SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+                                       frames_per_period, frames_per_period);
+                       if (err < 0) {
+                               mutex_unlock(&oxfw->mutex);
+                               goto err_locked;
+                       }
+
+                       err = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                       SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                       frames_per_buffer, frames_per_buffer);
+                       if (err < 0) {
+                               mutex_unlock(&oxfw->mutex);
+                               goto err_locked;
+                       }
+               }
        }
 
+       mutex_unlock(&oxfw->mutex);
+
        snd_pcm_set_sync(substream);
-end:
-       return err;
+
+       return 0;
 err_locked:
        snd_oxfw_stream_lock_release(oxfw);
        return err;
@@ -221,10 +247,13 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                unsigned int rate = params_rate(hw_params);
                unsigned int channels = params_channels(hw_params);
+               unsigned int frames_per_period = params_period_size(hw_params);
+               unsigned int frames_per_buffer = params_buffer_size(hw_params);
 
                mutex_lock(&oxfw->mutex);
                err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream,
-                                                    rate, channels);
+                                       rate, channels, frames_per_period,
+                                       frames_per_buffer);
                if (err >= 0)
                        ++oxfw->substreams_count;
                mutex_unlock(&oxfw->mutex);
@@ -246,10 +275,13 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                unsigned int rate = params_rate(hw_params);
                unsigned int channels = params_channels(hw_params);
+               unsigned int frames_per_period = params_period_size(hw_params);
+               unsigned int frames_per_buffer = params_buffer_size(hw_params);
 
                mutex_lock(&oxfw->mutex);
                err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream,
-                                                    rate, channels);
+                                       rate, channels, frames_per_period,
+                                       frames_per_buffer);
                if (err >= 0)
                        ++oxfw->substreams_count;
                mutex_unlock(&oxfw->mutex);
@@ -361,27 +393,27 @@ static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstm)
 {
        struct snd_oxfw *oxfw = sbstm->private_data;
 
-       return amdtp_stream_pcm_pointer(&oxfw->tx_stream);
+       return amdtp_domain_stream_pcm_pointer(&oxfw->domain, &oxfw->tx_stream);
 }
 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstm)
 {
        struct snd_oxfw *oxfw = sbstm->private_data;
 
-       return amdtp_stream_pcm_pointer(&oxfw->rx_stream);
+       return amdtp_domain_stream_pcm_pointer(&oxfw->domain, &oxfw->rx_stream);
 }
 
 static int pcm_capture_ack(struct snd_pcm_substream *substream)
 {
        struct snd_oxfw *oxfw = substream->private_data;
 
-       return amdtp_stream_pcm_ack(&oxfw->tx_stream);
+       return amdtp_domain_stream_pcm_ack(&oxfw->domain, &oxfw->tx_stream);
 }
 
 static int pcm_playback_ack(struct snd_pcm_substream *substream)
 {
        struct snd_oxfw *oxfw = substream->private_data;
 
-       return amdtp_stream_pcm_ack(&oxfw->rx_stream);
+       return amdtp_domain_stream_pcm_ack(&oxfw->domain, &oxfw->rx_stream);
 }
 
 int snd_oxfw_create_pcm(struct snd_oxfw *oxfw)
index 3c9a796b65269594c88886568f09a70627a62e07..501a80094bf7d3aefc1cec9ae4e8981146498743 100644 (file)
@@ -244,7 +244,9 @@ static int keep_resources(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
 
 int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw,
                                   struct amdtp_stream *stream,
-                                  unsigned int rate, unsigned int pcm_channels)
+                                  unsigned int rate, unsigned int pcm_channels,
+                                  unsigned int frames_per_period,
+                                  unsigned int frames_per_buffer)
 {
        struct snd_oxfw_stream_formation formation;
        enum avc_general_plug_dir dir;
@@ -305,6 +307,15 @@ int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw,
                                return err;
                        }
                }
+
+               err = amdtp_domain_set_events_per_period(&oxfw->domain,
+                                       frames_per_period, frames_per_buffer);
+               if (err < 0) {
+                       cmp_connection_release(&oxfw->in_conn);
+                       if (oxfw->has_output)
+                               cmp_connection_release(&oxfw->out_conn);
+                       return err;
+               }
        }
 
        return 0;
@@ -344,7 +355,7 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
                        }
                }
 
-               err = amdtp_domain_start(&oxfw->domain);
+               err = amdtp_domain_start(&oxfw->domain, 0);
                if (err < 0)
                        goto error;
 
index c9627b8c5d6e8a8dca214a3832a91eaaba704803..c30e537087b06be51e408daed7c2fa5e53e0828a 100644 (file)
@@ -103,7 +103,9 @@ int avc_general_inquiry_sig_fmt(struct fw_unit *unit, unsigned int rate,
 int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw);
 int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw,
                                   struct amdtp_stream *stream,
-                                  unsigned int rate, unsigned int pcm_channels);
+                                  unsigned int rate, unsigned int pcm_channels,
+                                  unsigned int frames_per_period,
+                                  unsigned int frames_per_buffer);
 int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw);
 void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw);
 void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw);
index 2377732caa52a3f72f49b381a207ce29a362998a..cd45f20ba5158fed4a7175003dc02775600fcb35 100644 (file)
@@ -43,13 +43,13 @@ static int pcm_init_hw_params(struct snd_tscm *tscm,
 static int pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_tscm *tscm = substream->private_data;
+       struct amdtp_domain *d = &tscm->domain;
        enum snd_tscm_clock clock;
-       unsigned int rate;
        int err;
 
        err = snd_tscm_stream_lock_try(tscm);
        if (err < 0)
-               goto end;
+               return err;
 
        err = pcm_init_hw_params(tscm, substream);
        if (err < 0)
@@ -59,19 +59,46 @@ static int pcm_open(struct snd_pcm_substream *substream)
        if (err < 0)
                goto err_locked;
 
-       if (clock != SND_TSCM_CLOCK_INTERNAL ||
-           amdtp_stream_pcm_running(&tscm->rx_stream) ||
-           amdtp_stream_pcm_running(&tscm->tx_stream)) {
+       mutex_lock(&tscm->mutex);
+
+       // When source of clock is not internal or any stream is reserved for
+       // transmission of PCM frames, the available sampling rate is limited
+       // at current one.
+       if (clock != SND_TSCM_CLOCK_INTERNAL || tscm->substreams_counter > 0) {
+               unsigned int frames_per_period = d->events_per_period;
+               unsigned int frames_per_buffer = d->events_per_buffer;
+               unsigned int rate;
+
                err = snd_tscm_stream_get_rate(tscm, &rate);
-               if (err < 0)
+               if (err < 0) {
+                       mutex_unlock(&tscm->mutex);
                        goto err_locked;
+               }
                substream->runtime->hw.rate_min = rate;
                substream->runtime->hw.rate_max = rate;
+
+               err = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                       SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+                                       frames_per_period, frames_per_period);
+               if (err < 0) {
+                       mutex_unlock(&tscm->mutex);
+                       goto err_locked;
+               }
+
+               err = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                       SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                       frames_per_buffer, frames_per_buffer);
+               if (err < 0) {
+                       mutex_unlock(&tscm->mutex);
+                       goto err_locked;
+               }
        }
 
+       mutex_unlock(&tscm->mutex);
+
        snd_pcm_set_sync(substream);
-end:
-       return err;
+
+       return 0;
 err_locked:
        snd_tscm_stream_lock_release(tscm);
        return err;
@@ -99,9 +126,12 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                unsigned int rate = params_rate(hw_params);
+               unsigned int frames_per_period = params_period_size(hw_params);
+               unsigned int frames_per_buffer = params_buffer_size(hw_params);
 
                mutex_lock(&tscm->mutex);
-               err = snd_tscm_stream_reserve_duplex(tscm, rate);
+               err = snd_tscm_stream_reserve_duplex(tscm, rate,
+                                       frames_per_period, frames_per_buffer);
                if (err >= 0)
                        ++tscm->substreams_counter;
                mutex_unlock(&tscm->mutex);
@@ -200,28 +230,28 @@ static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
 {
        struct snd_tscm *tscm = sbstrm->private_data;
 
-       return amdtp_stream_pcm_pointer(&tscm->tx_stream);
+       return amdtp_domain_stream_pcm_pointer(&tscm->domain, &tscm->tx_stream);
 }
 
 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
 {
        struct snd_tscm *tscm = sbstrm->private_data;
 
-       return amdtp_stream_pcm_pointer(&tscm->rx_stream);
+       return amdtp_domain_stream_pcm_pointer(&tscm->domain, &tscm->rx_stream);
 }
 
 static int pcm_capture_ack(struct snd_pcm_substream *substream)
 {
        struct snd_tscm *tscm = substream->private_data;
 
-       return amdtp_stream_pcm_ack(&tscm->tx_stream);
+       return amdtp_domain_stream_pcm_ack(&tscm->domain, &tscm->tx_stream);
 }
 
 static int pcm_playback_ack(struct snd_pcm_substream *substream)
 {
        struct snd_tscm *tscm = substream->private_data;
 
-       return amdtp_stream_pcm_ack(&tscm->rx_stream);
+       return amdtp_domain_stream_pcm_ack(&tscm->domain, &tscm->rx_stream);
 }
 
 int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
index adf69a520b800bb68eed64adc00e3d68664412e8..eb07e1decf9bad3770548e19b8ed2dee14793e17 100644 (file)
@@ -383,7 +383,9 @@ void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm)
        destroy_stream(tscm, &tscm->tx_stream);
 }
 
-int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate)
+int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate,
+                                  unsigned int frames_per_period,
+                                  unsigned int frames_per_buffer)
 {
        unsigned int curr_rate;
        int err;
@@ -413,6 +415,14 @@ int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate)
                        fw_iso_resources_free(&tscm->tx_resources);
                        return err;
                }
+
+               err = amdtp_domain_set_events_per_period(&tscm->domain,
+                                       frames_per_period, frames_per_buffer);
+               if (err < 0) {
+                       fw_iso_resources_free(&tscm->tx_resources);
+                       fw_iso_resources_free(&tscm->rx_resources);
+                       return err;
+               }
        }
 
        return 0;
@@ -463,7 +473,7 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
                if (err < 0)
                        goto error;
 
-               err = amdtp_domain_start(&tscm->domain);
+               err = amdtp_domain_start(&tscm->domain, 0);
                if (err < 0)
                        return err;
 
index 15bd335fa07fe126c7abafd42f56e83196c052cb..78b7a08986a1d311860b467b1ec29c03fec02845 100644 (file)
@@ -168,7 +168,9 @@ int snd_tscm_stream_get_clock(struct snd_tscm *tscm,
 int snd_tscm_stream_init_duplex(struct snd_tscm *tscm);
 void snd_tscm_stream_update_duplex(struct snd_tscm *tscm);
 void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm);
-int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate);
+int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate,
+                                  unsigned int frames_per_period,
+                                  unsigned int frames_per_buffer);
 int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate);
 void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm);
 
index 3d33fc1757ba21eff3c5149ae66b31e7ed6cd116..b0c88fe040ee1fdcbc7783d0d4d84dd5e1635692 100644 (file)
@@ -34,6 +34,12 @@ config SND_HDA_PREALLOC_SIZE
          via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too.
 
 config SND_INTEL_NHLT
-       tristate
+       bool
        # this config should be selected only for Intel ACPI platforms.
-       # A fallback is provided so that the code compiles in all cases.
\ No newline at end of file
+       # A fallback is provided so that the code compiles in all cases.
+
+config SND_INTEL_DSP_CONFIG
+       tristate
+       select SND_INTEL_NHLT if ACPI
+       # this config should be selected only for Intel DSP platforms.
+       # A fallback is provided so that the code compiles in all cases.
index 8560f6ef1b1997e97361ef54f3567323a336b880..601e617918b8b4545e2dd9d623e33928f559103c 100644 (file)
@@ -14,5 +14,6 @@ obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o
 #extended hda
 obj-$(CONFIG_SND_HDA_EXT_CORE) += ext/
 
-snd-intel-nhlt-objs := intel-nhlt.o
-obj-$(CONFIG_SND_INTEL_NHLT) += snd-intel-nhlt.o
+snd-intel-dspcfg-objs := intel-dsp-config.o
+snd-intel-dspcfg-$(CONFIG_SND_INTEL_NHLT) += intel-nhlt.o
+obj-$(CONFIG_SND_INTEL_DSP_CONFIG) += snd-intel-dspcfg.o
diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c
new file mode 100644 (file)
index 0000000..0b2a720
--- /dev/null
@@ -0,0 +1,357 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Jaroslav Kysela <perex@perex.cz>
+
+#include <linux/bits.h>
+#include <linux/dmi.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include <sound/intel-dsp-config.h>
+#include <sound/intel-nhlt.h>
+
+static int dsp_driver;
+
+module_param(dsp_driver, int, 0444);
+MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF)");
+
+#define FLAG_SST               BIT(0)
+#define FLAG_SOF               BIT(1)
+#define FLAG_SOF_ONLY_IF_DMIC  BIT(16)
+
+struct config_entry {
+       u32 flags;
+       u16 device;
+       const struct dmi_system_id *dmi_table;
+};
+
+/*
+ * configuration table
+ * - the order of similar PCI ID entries is important!
+ * - the first successful match will win
+ */
+static const struct config_entry config_table[] = {
+/* Merrifield */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
+       {
+               .flags = FLAG_SOF,
+               .device = 0x119a,
+       },
+#endif
+/* Broxton-T */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
+       {
+               .flags = FLAG_SOF,
+               .device = 0x1a98,
+       },
+#endif
+/*
+ * Apollolake (Broxton-P)
+ * the legacy HDaudio driver is used except on Up Squared (SOF) and
+ * Chromebooks (SST)
+ */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
+       {
+               .flags = FLAG_SOF,
+               .device = 0x5a98,
+               .dmi_table = (const struct dmi_system_id []) {
+                       {
+                               .ident = "Up Squared",
+                               .matches = {
+                                       DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
+                                       DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"),
+                               }
+                       },
+                       {}
+               }
+       },
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
+       {
+               .flags = FLAG_SST,
+               .device = 0x5a98,
+               .dmi_table = (const struct dmi_system_id []) {
+                       {
+                               .ident = "Google Chromebooks",
+                               .matches = {
+                                       DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+                               }
+                       },
+                       {}
+               }
+       },
+#endif
+/*
+ * Skylake and Kabylake use legacy HDaudio driver except for Google
+ * Chromebooks (SST)
+ */
+
+/* Sunrise Point-LP */
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
+       {
+               .flags = FLAG_SST,
+               .device = 0x9d70,
+               .dmi_table = (const struct dmi_system_id []) {
+                       {
+                               .ident = "Google Chromebooks",
+                               .matches = {
+                                       DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+                               }
+                       },
+                       {}
+               }
+       },
+#endif
+/* Kabylake-LP */
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
+       {
+               .flags = FLAG_SST,
+               .device = 0x9d71,
+               .dmi_table = (const struct dmi_system_id []) {
+                       {
+                               .ident = "Google Chromebooks",
+                               .matches = {
+                                       DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+                               }
+                       },
+                       {}
+               }
+       },
+#endif
+
+/*
+ * Geminilake uses legacy HDaudio driver except for Google
+ * Chromebooks
+ */
+/* Geminilake */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
+       {
+               .flags = FLAG_SOF,
+               .device = 0x3198,
+               .dmi_table = (const struct dmi_system_id []) {
+                       {
+                               .ident = "Google Chromebooks",
+                               .matches = {
+                                       DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+                               }
+                       },
+                       {}
+               }
+       },
+#endif
+
+/*
+ * CoffeeLake, CannonLake, CometLake, IceLake, TigerLake use legacy
+ * HDaudio driver except for Google Chromebooks and when DMICs are
+ * present. Two cases are required since Coreboot does not expose NHLT
+ * tables.
+ *
+ * When the Chromebook quirk is not present, it's based on information
+ * that no such device exists. When the quirk is present, it could be
+ * either based on product information or a placeholder.
+ */
+
+/* Cannonlake */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
+       {
+               .flags = FLAG_SOF,
+               .device = 0x9dc8,
+               .dmi_table = (const struct dmi_system_id []) {
+                       {
+                               .ident = "Google Chromebooks",
+                               .matches = {
+                                       DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+                               }
+                       },
+                       {}
+               }
+       },
+       {
+               .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
+               .device = 0x9dc8,
+       },
+#endif
+
+/* Coffelake */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
+       {
+               .flags = FLAG_SOF,
+               .device = 0xa348,
+               .dmi_table = (const struct dmi_system_id []) {
+                       {
+                               .ident = "Google Chromebooks",
+                               .matches = {
+                                       DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+                               }
+                       },
+                       {}
+               }
+       },
+       {
+               .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
+               .device = 0xa348,
+       },
+#endif
+
+/* Cometlake-LP */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP)
+       {
+               .flags = FLAG_SOF,
+               .device = 0x02c8,
+               .dmi_table = (const struct dmi_system_id []) {
+                       {
+                               .ident = "Google Chromebooks",
+                               .matches = {
+                                       DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+                               }
+                       },
+                       {}
+               }
+       },
+       {
+               .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
+               .device = 0x02c8,
+       },
+#endif
+/* Cometlake-H */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H)
+       {
+               .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
+               .device = 0x06c8,
+       },
+#endif
+
+/* Icelake */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
+       {
+               .flags = FLAG_SOF,
+               .device = 0x34c8,
+               .dmi_table = (const struct dmi_system_id []) {
+                       {
+                               .ident = "Google Chromebooks",
+                               .matches = {
+                                       DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+                               }
+                       },
+                       {}
+               }
+       },
+       {
+               .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
+               .device = 0x34c8,
+       },
+#endif
+
+/* Tigerlake */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
+       {
+               .flags = FLAG_SOF,
+               .device = 0xa0c8,
+               .dmi_table = (const struct dmi_system_id []) {
+                       {
+                               .ident = "Google Chromebooks",
+                               .matches = {
+                                       DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+                               }
+                       },
+                       {}
+               }
+       },
+
+       {
+               .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
+               .device = 0xa0c8,
+       },
+#endif
+
+/* Elkhart Lake */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
+       {
+               .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
+               .device = 0x4b55,
+       },
+#endif
+
+};
+
+static const struct config_entry *snd_intel_dsp_find_config
+               (struct pci_dev *pci, const struct config_entry *table, u32 len)
+{
+       u16 device;
+
+       device = pci->device;
+       for (; len > 0; len--, table++) {
+               if (table->device != device)
+                       continue;
+               if (table->dmi_table && !dmi_check_system(table->dmi_table))
+                       continue;
+               return table;
+       }
+       return NULL;
+}
+
+static int snd_intel_dsp_check_dmic(struct pci_dev *pci)
+{
+       struct nhlt_acpi_table *nhlt;
+       int ret = 0;
+
+       nhlt = intel_nhlt_init(&pci->dev);
+       if (nhlt) {
+               if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt))
+                       ret = 1;
+               intel_nhlt_free(nhlt);
+       }
+       return ret;
+}
+
+int snd_intel_dsp_driver_probe(struct pci_dev *pci)
+{
+       const struct config_entry *cfg;
+
+       if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
+               return dsp_driver;
+
+       /* Intel vendor only */
+       if (snd_BUG_ON(pci->vendor != 0x8086))
+               return SND_INTEL_DSP_DRIVER_ANY;
+
+       /*
+        * detect DSP by checking class/subclass/prog-id information
+        * class=04 subclass 03 prog-if 00: no DSP, use legacy driver
+        * class=04 subclass 01 prog-if 00: DSP is present
+        *  (and may be required e.g. for DMIC or SSP support)
+        * class=04 subclass 03 prog-if 80: use DSP or legacy mode
+        */
+       if (pci->class == 0x040300)
+               return SND_INTEL_DSP_DRIVER_LEGACY;
+       if (pci->class != 0x040100 && pci->class != 0x040380) {
+               dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDA legacy driver\n", pci->class);
+               return SND_INTEL_DSP_DRIVER_LEGACY;
+       }
+
+       dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
+
+       /* find the configuration for the specific device */
+       cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table));
+       if (!cfg)
+               return SND_INTEL_DSP_DRIVER_ANY;
+
+       if (cfg->flags & FLAG_SOF) {
+               if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC) {
+                       if (snd_intel_dsp_check_dmic(pci)) {
+                               dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n");
+                               return SND_INTEL_DSP_DRIVER_SOF;
+                       }
+               } else {
+                       return SND_INTEL_DSP_DRIVER_SOF;
+               }
+       }
+
+       if (cfg->flags & FLAG_SST)
+               return SND_INTEL_DSP_DRIVER_SST;
+
+       return SND_INTEL_DSP_DRIVER_LEGACY;
+}
+EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel DSP config driver");
index daede96f28ee31dbd9debca853b9b301b0a89f02..097ff6c100999863fae6717e3adddcc465a3c6dc 100644 (file)
@@ -102,6 +102,3 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt)
        return dmic_geo;
 }
 EXPORT_SYMBOL_GPL(intel_nhlt_get_dmic_geo);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel NHLT driver");
index b690ed937cbe8bd5ef1dbfa0eb313005d35093ac..6ffa48dd5983035684a5359196b53d93ac1d6b18 100644 (file)
@@ -2,22 +2,22 @@
 # ALSA ISA drivers
 
 config SND_WSS_LIB
-        tristate
-        select SND_PCM
+       tristate
+       select SND_PCM
        select SND_TIMER
 
 config SND_SB_COMMON
-        tristate
+       tristate
 
 config SND_SB8_DSP
-        tristate
-        select SND_PCM
-        select SND_SB_COMMON
+       tristate
+       select SND_PCM
+       select SND_SB_COMMON
 
 config SND_SB16_DSP
-        tristate
-        select SND_PCM
-        select SND_SB_COMMON
+       tristate
+       select SND_PCM
+       select SND_SB_COMMON
 
 menuconfig SND_ISA
        bool "ISA sound devices"
index 8a33402fd415cbf4dde9aa80616a336efea109d8..b497b803c83471452cc9166c55538b290c554882 100644 (file)
@@ -14,15 +14,15 @@ config SND_SGI_O2
        tristate "SGI O2 Audio"
        depends on SGI_IP32
        select SND_PCM
-        help
-                Sound support for the SGI O2 Workstation. 
+       help
+         Sound support for the SGI O2 Workstation.
 
 config SND_SGI_HAL2
-        tristate "SGI HAL2 Audio"
-        depends on SGI_HAS_HAL2
+       tristate "SGI HAL2 Audio"
+       depends on SGI_HAS_HAL2
        select SND_PCM
-        help
-                Sound support for the SGI Indy and Indigo2 Workstation.
+       help
+         Sound support for the SGI Indy and Indigo2 Workstation.
 
 endif  # SND_MIPS
 
index 7630f808d087c7e26c0cfa604bafc844fff4de9c..93bc9bef7641fa1839e1bdd9fb58f86681b35c84 100644 (file)
@@ -217,7 +217,7 @@ config SND_CMIPCI
          will be called snd-cmipci.
 
 config SND_OXYGEN_LIB
-        tristate
+       tristate
 
 config SND_OXYGEN
        tristate "C-Media 8786, 8787, 8788 (Oxygen)"
index dae47a45b2b8bdabef5d92fe698f72fc80ecd218..bd48335d09d74f1d0fe22a98a441c362e6bbb11f 100644 (file)
@@ -12,7 +12,7 @@ config SND_HDA_INTEL
        tristate "HD Audio PCI"
        depends on SND_PCI
        select SND_HDA
-       select SND_INTEL_NHLT if ACPI
+       select SND_INTEL_DSP_CONFIG
        help
          Say Y here to include support for Intel "High Definition
          Audio" (Azalia) and its compatible devices.
@@ -23,15 +23,6 @@ config SND_HDA_INTEL
          To compile this driver as a module, choose M here: the module
          will be called snd-hda-intel.
 
-config SND_HDA_INTEL_DETECT_DMIC
-       bool "DMIC detection and probe abort"
-       depends on SND_HDA_INTEL
-       help
-         Say Y to detect digital microphones on SKL+ devices. DMICs
-         cannot be handled by the HDaudio legacy driver and are
-         currently only supported by the SOF driver.
-         If unsure say N.
-
 config SND_HDA_TEGRA
        tristate "NVIDIA Tegra HD Audio"
        depends on ARCH_TEGRA
index cf53fbd872ee34526d277bd4f479c1a5024b32b6..2a9d87ff2e1ce0f8ff280626f949ccf732e0d1d7 100644 (file)
@@ -46,7 +46,7 @@
 #include <sound/initval.h>
 #include <sound/hdaudio.h>
 #include <sound/hda_i915.h>
-#include <sound/intel-nhlt.h>
+#include <sound/intel-dsp-config.h>
 #include <linux/vgaarb.h>
 #include <linux/vga_switcheroo.h>
 #include <linux/firmware.h>
@@ -124,7 +124,7 @@ static char *patch[SNDRV_CARDS];
 static bool beep_mode[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] =
                                        CONFIG_SND_HDA_INPUT_BEEP_MODE};
 #endif
-static bool dmic_detect = IS_ENABLED(CONFIG_SND_HDA_INTEL_DETECT_DMIC);
+static bool dsp_driver = 1;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
@@ -159,8 +159,9 @@ module_param_array(beep_mode, bool, NULL, 0444);
 MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode "
                            "(0=off, 1=on) (default=1).");
 #endif
-module_param(dmic_detect, bool, 0444);
-MODULE_PARM_DESC(dmic_detect, "DMIC detect on SKL+ platforms");
+module_param(dsp_driver, bool, 0444);
+MODULE_PARM_DESC(dsp_driver, "Allow DSP driver selection (bypass this driver) "
+                            "(0=off, 1=on) (default=1)");
 
 #ifdef CONFIG_PM
 static int param_set_xint(const char *val, const struct kernel_param *kp);
@@ -1280,11 +1281,17 @@ static void init_vga_switcheroo(struct azx *chip)
 {
        struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
        struct pci_dev *p = get_bound_vga(chip->pci);
+       struct pci_dev *parent;
        if (p) {
                dev_info(chip->card->dev,
                         "Handle vga_switcheroo audio client\n");
                hda->use_vga_switcheroo = 1;
-               chip->bus.keep_power = 1; /* cleared in either gpu_bound op or codec probe */
+
+               /* cleared in either gpu_bound op or codec probe, or when its
+                * upstream port has _PR3 (i.e. dGPU).
+                */
+               parent = pci_upstream_bridge(p);
+               chip->bus.keep_power = parent ? !pci_pr3_present(parent) : 1;
                chip->driver_caps |= AZX_DCAPS_PM_RUNTIME;
                pci_dev_put(p);
        }
@@ -2020,25 +2027,6 @@ static const struct hda_controller_ops pci_hda_ops = {
        .position_check = azx_position_check,
 };
 
-static int azx_check_dmic(struct pci_dev *pci, struct azx *chip)
-{
-       struct nhlt_acpi_table *nhlt;
-       int ret = 0;
-
-       if (chip->driver_type == AZX_DRIVER_SKL &&
-           pci->class != 0x040300) {
-               nhlt = intel_nhlt_init(&pci->dev);
-               if (nhlt) {
-                       if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt)) {
-                               ret = -ENODEV;
-                               dev_info(&pci->dev, "Digital mics found on Skylake+ platform, aborting probe\n");
-                       }
-                       intel_nhlt_free(nhlt);
-               }
-       }
-       return ret;
-}
-
 static int azx_probe(struct pci_dev *pci,
                     const struct pci_device_id *pci_id)
 {
@@ -2056,6 +2044,16 @@ static int azx_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
+       /*
+        * stop probe if another Intel's DSP driver should be activated
+        */
+       if (dsp_driver) {
+               err = snd_intel_dsp_driver_probe(pci);
+               if (err != SND_INTEL_DSP_DRIVER_ANY &&
+                   err != SND_INTEL_DSP_DRIVER_LEGACY)
+                       return -ENODEV;
+       }
+
        err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
                           0, &card);
        if (err < 0) {
@@ -2069,17 +2067,6 @@ static int azx_probe(struct pci_dev *pci,
        card->private_data = chip;
        hda = container_of(chip, struct hda_intel, chip);
 
-       /*
-        * stop probe if digital microphones detected on Skylake+ platform
-        * with the DSP enabled. This is an opt-in behavior defined at build
-        * time or at run-time with a module parameter
-        */
-       if (dmic_detect) {
-               err = azx_check_dmic(pci, chip);
-               if (err < 0)
-                       goto out_free;
-       }
-
        pci_set_drvdata(pci, card);
 
        err = register_vga_switcheroo(chip);
index 2333efac758a156d5592c968f35578f8da7e03b3..8039a8febefafd3fc5ac14db92d91e330d0ffa8e 100644 (file)
@@ -33,13 +33,13 @@ config SND_EP93XX_SOC_AC97
        select SND_SOC_AC97_BUS
 
 config SND_EP93XX_SOC_SNAPPERCL15
-        tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
-        depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 && I2C
-        select SND_EP93XX_SOC_I2S
-        select SND_SOC_TLV320AIC23_I2C
-        help
-          Say Y or M here if you want to add support for I2S audio on the
-          Bluewater Systems Snapper CL15 module.
+       tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
+       depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 && I2C
+       select SND_EP93XX_SOC_I2S
+       select SND_SOC_TLV320AIC23_I2C
+       help
+         Say Y or M here if you want to add support for I2S audio on the
+         Bluewater Systems Snapper CL15 module.
 
 config SND_EP93XX_SOC_SIMONE
        tristate "SoC Audio support for Simplemachines Sim.One board"
index 229cc89f8c5a519116a38978c19469f6f792e6db..ef9d73b896239a6320e65c44c5ad7eca95826759 100644 (file)
@@ -257,16 +257,16 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM9705 if (SND_SOC_AC97_BUS || SND_SOC_AC97_BUS_NEW)
        select SND_SOC_WM9712 if (SND_SOC_AC97_BUS || SND_SOC_AC97_BUS_NEW)
        select SND_SOC_WM9713 if (SND_SOC_AC97_BUS || SND_SOC_AC97_BUS_NEW)
-        help
-          Normally ASoC codec drivers are only built if a machine driver which
-          uses them is also built since they are only usable with a machine
-          driver.  Selecting this option will allow these drivers to be built
-          without an explicit machine driver for test and development purposes.
+       help
+         Normally ASoC codec drivers are only built if a machine driver which
+         uses them is also built since they are only usable with a machine
+         driver.  Selecting this option will allow these drivers to be built
+         without an explicit machine driver for test and development purposes.
 
          Support for the bus types used to access the codecs to be built must
          be selected separately.
 
-          If unsure select "N".
+         If unsure select "N".
 
 config SND_SOC_88PM860X
        tristate
@@ -570,8 +570,8 @@ config SND_SOC_CS42XX8_I2C
 
 # Cirrus Logic CS43130 HiFi DAC
 config SND_SOC_CS43130
-        tristate "Cirrus Logic CS43130 CODEC"
-        depends on I2C
+       tristate "Cirrus Logic CS43130 CODEC"
+       depends on I2C
 
 config SND_SOC_CS4341
        tristate "Cirrus Logic CS4341 CODEC"
@@ -643,19 +643,19 @@ config SND_SOC_L3
        tristate
 
 config SND_SOC_DA7210
-        tristate
+       tristate
 
 config SND_SOC_DA7213
-        tristate
+       tristate
 
 config SND_SOC_DA7218
        tristate
 
 config SND_SOC_DA7219
-        tristate
+       tristate
 
 config SND_SOC_DA732X
-        tristate
+       tristate
 
 config SND_SOC_DA9055
        tristate
@@ -717,7 +717,7 @@ config SND_SOC_INNO_RK3036
        select REGMAP_MMIO
 
 config SND_SOC_ISABELLE
-        tristate
+       tristate
 
 config SND_SOC_LM49453
        tristate
@@ -988,7 +988,7 @@ config SND_SOC_RT5640
        tristate
 
 config SND_SOC_RT5645
-        tristate
+       tristate
 
 config SND_SOC_RT5651
        tristate
@@ -1220,7 +1220,7 @@ config SND_SOC_UDA134X
        tristate
 
 config SND_SOC_UDA1380
-        tristate
+       tristate
        depends on I2C
 
 config SND_SOC_WCD9335
@@ -1348,7 +1348,7 @@ config SND_SOC_WM8904
        depends on I2C
 
 config SND_SOC_WM8940
-        tristate
+       tristate
 
 config SND_SOC_WM8955
        tristate
index 01c99750212a22b0509c8b110757c119efe5301f..3f9e65c10d5b571e9177c29b8b540164da8c8934 100644 (file)
@@ -113,7 +113,7 @@ config SND_SOC_INTEL_SKYLAKE
        select SND_SOC_INTEL_CNL
        select SND_SOC_INTEL_CFL
        help
-          This is a backwards-compatible option to select all devices
+         This is a backwards-compatible option to select all devices
          supported by the Intel SST/Skylake driver. This option is no
          longer recommended and will be deprecated when the SOF
          driver is introduced.  Distributions should explicitly
@@ -215,7 +215,7 @@ config SND_SOC_INTEL_SKYLAKE_COMMON
        select SND_SOC_INTEL_SST
        select SND_SOC_HDAC_HDA if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC
        select SND_SOC_ACPI_INTEL_MATCH
-       select SND_INTEL_NHLT if ACPI
+       select SND_INTEL_DSP_CONFIG
        help
          If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/
          GeminiLake or CannonLake platform with the DSP enabled in the BIOS
index 5c27f7ab4a5f5714170659648d9815afbbaa00b1..882ff36a7c9c1d52a662835cefa1f630f8c3e0b2 100644 (file)
@@ -3,13 +3,13 @@ menuconfig SND_SOC_INTEL_MACH
        bool "Intel Machine drivers"
        depends on SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL
        help
-         Intel ASoC Machine Drivers. If you have a Intel machine that
-         has an audio controller with a DSP and I2S or DMIC port, then
-         enable this option by saying Y
+        Intel ASoC Machine Drivers. If you have a Intel machine that
+        has an audio controller with a DSP and I2S or DMIC port, then
+        enable this option by saying Y
 
-         Note that the answer to this question doesn't directly affect the
-         kernel: saying N will just cause the configurator to skip all
-         the questions about Intel ASoC machine drivers.
+        Note that the answer to this question doesn't directly affect the
+        kernel: saying N will just cause the configurator to skip all
+        the questions about Intel ASoC machine drivers.
 
 if SND_SOC_INTEL_MACH
 
@@ -114,11 +114,11 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
        depends on X86_INTEL_LPSS || COMPILE_TEST
        select SND_SOC_ACPI
        select SND_SOC_RT5670
-        help
-          This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
-          platforms with RT5672 audio codec.
-          Say Y or m if you have such a device. This is a recommended option.
-          If unsure select "N".
+       help
+         This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
+         platforms with RT5672 audio codec.
+         Say Y or m if you have such a device. This is a recommended option.
+         If unsure select "N".
 
 config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
        tristate "Cherrytrail & Braswell with RT5645/5650 codec"
@@ -311,20 +311,20 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
          If unsure select "N".
 
 config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
-        tristate "KBL with RT5663, RT5514 and MAX98927 in I2S Mode"
+       tristate "KBL with RT5663, RT5514 and MAX98927 in I2S Mode"
        depends on I2C && ACPI
        depends on MFD_INTEL_LPSS || COMPILE_TEST
-        depends on SPI
-        select SND_SOC_RT5663
-        select SND_SOC_RT5514
-        select SND_SOC_RT5514_SPI
-        select SND_SOC_MAX98927
-        select SND_SOC_HDAC_HDMI
-        help
-          This adds support for ASoC Onboard Codec I2S machine driver. This will
-          create an alsa sound card for RT5663 + RT5514 + MAX98927.
-          Say Y or m if you have such a device. This is a recommended option.
-          If unsure select "N".
+       depends on SPI
+       select SND_SOC_RT5663
+       select SND_SOC_RT5514
+       select SND_SOC_RT5514_SPI
+       select SND_SOC_MAX98927
+       select SND_SOC_HDAC_HDMI
+       help
+         This adds support for ASoC Onboard Codec I2S machine driver. This will
+         create an alsa sound card for RT5663 + RT5514 + MAX98927.
+         Say Y or m if you have such a device. This is a recommended option.
+         If unsure select "N".
 
 config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH
        tristate "KBL with DA7219 and MAX98357A in I2S Mode"
@@ -393,7 +393,7 @@ config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH
        help
          This adds support for ASoC machine driver for Intel platforms
          SKL/KBL/BXT/APL with iDisp, HDA audio codecs.
-          Say Y or m if you have such a device. This is a recommended option.
+         Say Y or m if you have such a device. This is a recommended option.
          If unsure select "N".
 
 endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC
index 141dbbf975acdfea4b5c8b2a2e5e1efcc613ed9f..58ba3e9469ba04d6aaa6b1733a22bc8388768ce8 100644 (file)
@@ -27,6 +27,7 @@
 #include <sound/hda_i915.h>
 #include <sound/hda_codec.h>
 #include <sound/intel-nhlt.h>
+#include <sound/intel-dsp-config.h>
 #include "skl.h"
 #include "skl-sst-dsp.h"
 #include "skl-sst-ipc.h"
@@ -987,22 +988,10 @@ static int skl_probe(struct pci_dev *pci,
 
        switch (skl_pci_binding) {
        case SND_SKL_PCI_BIND_AUTO:
-               /*
-                * detect DSP by checking class/subclass/prog-id information
-                * class=04 subclass 03 prog-if 00: no DSP, use legacy driver
-                * class=04 subclass 01 prog-if 00: DSP is present
-                *   (and may be required e.g. for DMIC or SSP support)
-                * class=04 subclass 03 prog-if 80: use DSP or legacy mode
-                */
-               if (pci->class == 0x040300) {
-                       dev_info(&pci->dev, "The DSP is not enabled on this platform, aborting probe\n");
+               err = snd_intel_dsp_driver_probe(pci);
+               if (err != SND_INTEL_DSP_DRIVER_ANY &&
+                   err != SND_INTEL_DSP_DRIVER_SST)
                        return -ENODEV;
-               }
-               if (pci->class != 0x040100 && pci->class != 0x040380) {
-                       dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, aborting probe\n", pci->class);
-                       return -ENODEV;
-               }
-               dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
                break;
        case SND_SKL_PCI_BIND_LEGACY:
                dev_info(&pci->dev, "Module parameter forced binding with HDaudio legacy, aborting probe\n");
index 213d4dab0346d191895b6e2c58974ecc51ec9d00..295cfffa4646ea58b5d6c828bc15a4256c76249a 100644 (file)
@@ -190,14 +190,14 @@ config SND_PXA2XX_SOC_MAGICIAN
          HTC Magician.
 
 config SND_PXA2XX_SOC_MIOA701
-        tristate "SoC Audio support for MIO A701"
-        depends on SND_PXA2XX_SOC && MACH_MIOA701
+       tristate "SoC Audio support for MIO A701"
+       depends on SND_PXA2XX_SOC && MACH_MIOA701
        depends on AC97_BUS=n
-        select SND_PXA2XX_SOC_AC97
-        select SND_SOC_WM9713
-        help
-          Say Y if you want to add support for SoC audio on the
-          MIO A701.
+       select SND_PXA2XX_SOC_AC97
+       select SND_SOC_WM9713
+       help
+         Say Y if you want to add support for SoC audio on the
+         MIO A701.
 
 config SND_PXA2XX_SOC_IMOTE2
        tristate "SoC Audio support for IMote 2"
@@ -205,7 +205,7 @@ config SND_PXA2XX_SOC_IMOTE2
        select SND_PXA2XX_SOC_I2S
        select SND_SOC_WM8940
        help
-         Say Y if you want to add support for SoC audio on the
+        Say Y if you want to add support for SoC audio on the
         IMote 2.
 
 config SND_MMP_SOC_BROWNSTONE
index 60086858e920baca09e3930ffcd2fd4b0705bfd1..6530d2462a9e0b29cc3c6b1a2cad8d5677f21930 100644 (file)
@@ -3,8 +3,8 @@ config SND_SOC_QCOM
        tristate "ASoC support for QCOM platforms"
        depends on ARCH_QCOM || COMPILE_TEST
        help
-          Say Y or M if you want to add support to use audio devices
-          in Qualcomm Technologies SOC-based platforms.
+         Say Y or M if you want to add support to use audio devices
+         in Qualcomm Technologies SOC-based platforms.
 
 config SND_SOC_LPASS_CPU
        tristate
@@ -30,17 +30,17 @@ config SND_SOC_STORM
        select SND_SOC_LPASS_IPQ806X
        select SND_SOC_MAX98357A
        help
-          Say Y or M if you want add support for SoC audio on the
-          Qualcomm Technologies IPQ806X-based Storm board.
+         Say Y or M if you want add support for SoC audio on the
+         Qualcomm Technologies IPQ806X-based Storm board.
 
 config SND_SOC_APQ8016_SBC
        tristate "SoC Audio support for APQ8016 SBC platforms"
        depends on SND_SOC_QCOM
        select SND_SOC_LPASS_APQ8016
        help
-          Support for Qualcomm Technologies LPASS audio block in
-          APQ8016 SOC-based systems.
-          Say Y if you want to use audio devices on MI2S.
+         Support for Qualcomm Technologies LPASS audio block in
+         APQ8016 SOC-based systems.
+         Say Y if you want to use audio devices on MI2S.
 
 config SND_SOC_QCOM_COMMON
        tristate
@@ -93,9 +93,9 @@ config SND_SOC_MSM8996
        select SND_SOC_QDSP6
        select SND_SOC_QCOM_COMMON
        help
-          Support for Qualcomm Technologies LPASS audio block in
-          APQ8096 SoC-based systems.
-          Say Y if you want to use audio device on this SoCs
+         Support for Qualcomm Technologies LPASS audio block in
+         APQ8096 SoC-based systems.
+         Say Y if you want to use audio device on this SoCs
 
 config SND_SOC_SDM845
        tristate "SoC Machine driver for SDM845 boards"
index 638983123d8fcc8e071563ab0dc495da394e330d..9304177de78a960a1b541d448c064749933928c8 100644 (file)
@@ -195,10 +195,10 @@ config SND_SOC_ODROID
          Say Y here to enable audio support for the Odroid XU3/XU4.
 
 config SND_SOC_ARNDALE_RT5631_ALC5631
-        tristate "Audio support for RT5631(ALC5631) on Arndale Board"
-        depends on I2C
-        select SND_SAMSUNG_I2S
-        select SND_SOC_RT5631
+       tristate "Audio support for RT5631(ALC5631) on Arndale Board"
+       depends on I2C
+       select SND_SAMSUNG_I2S
+       select SND_SOC_RT5631
 
 config SND_SOC_SAMSUNG_TM2_WM5110
        tristate "SoC I2S Audio support for WM5110 on TM2 board"
index 5acae75f5750db0f871d973d5f1d5b1340995431..6315fba8ce719c62b0c7f77cf7719720d8e6b5e8 100644 (file)
@@ -5,9 +5,9 @@ config SND_SOC_SOF_IMX_TOPLEVEL
        depends on ARM64|| COMPILE_TEST
        depends on SND_SOC_SOF_OF
        help
-          This adds support for Sound Open Firmware for NXP i.MX platforms.
-          Say Y if you have such a device.
-          If unsure select "N".
+         This adds support for Sound Open Firmware for NXP i.MX platforms.
+         Say Y if you have such a device.
+         If unsure select "N".
 
 if SND_SOC_SOF_IMX_TOPLEVEL
 
@@ -16,8 +16,8 @@ config SND_SOC_SOF_IMX8
        depends on IMX_SCU
        depends on IMX_DSP
        help
-          This adds support for Sound Open Firmware for NXP i.MX8 platforms
-          Say Y if you have such a device.
-          If unsure select "N".
+         This adds support for Sound Open Firmware for NXP i.MX8 platforms
+         Say Y if you have such a device.
+         If unsure select "N".
 
 endif ## SND_SOC_SOF_IMX_IMX_TOPLEVEL
index d62f51d33be148531916c887e6aa046328f5c2dc..05f4aed13af9f0068a8ff362bfd8ca6a1837a9b7 100644 (file)
@@ -36,7 +36,7 @@ config SND_SOC_SOF_INTEL_PCI
 config SND_SOC_SOF_INTEL_HIFI_EP_IPC
        tristate
        help
-          This option is not user-selectable but automagically handled by
+         This option is not user-selectable but automagically handled by
          'select' statements at a higher level
 
 config SND_SOC_SOF_INTEL_ATOM_HIFI_EP
@@ -217,31 +217,31 @@ config SND_SOC_SOF_COMETLAKE_H_SUPPORT
 config SND_SOC_SOF_TIGERLAKE_SUPPORT
        bool "SOF support for Tigerlake"
        help
-          This adds support for Sound Open Firmware for Intel(R) platforms
-          using the Tigerlake processors.
-          Say Y if you have such a device.
-          If unsure select "N".
+         This adds support for Sound Open Firmware for Intel(R) platforms
+         using the Tigerlake processors.
+         Say Y if you have such a device.
+         If unsure select "N".
 
 config SND_SOC_SOF_TIGERLAKE
        tristate
        select SND_SOC_SOF_HDA_COMMON
        help
-          This option is not user-selectable but automagically handled by
+         This option is not user-selectable but automagically handled by
          'select' statements at a higher level
 
 config SND_SOC_SOF_ELKHARTLAKE_SUPPORT
        bool "SOF support for ElkhartLake"
        help
-          This adds support for Sound Open Firmware for Intel(R) platforms
-          using the ElkhartLake processors.
-          Say Y if you have such a device.
-          If unsure select "N".
+         This adds support for Sound Open Firmware for Intel(R) platforms
+         using the ElkhartLake processors.
+         Say Y if you have such a device.
+         If unsure select "N".
 
 config SND_SOC_SOF_ELKHARTLAKE
        tristate
        select SND_SOC_SOF_HDA_COMMON
        help
-          This option is not user-selectable but automagically handled by
+         This option is not user-selectable but automagically handled by
          'select' statements at a higher level
 
 config SND_SOC_SOF_HDA_COMMON
@@ -296,7 +296,7 @@ config SND_SOC_SOF_HDA
        tristate
        select SND_HDA_EXT_CORE if SND_SOC_SOF_HDA_LINK
        select SND_SOC_HDAC_HDA if SND_SOC_SOF_HDA_AUDIO_CODEC
-       select SND_INTEL_NHLT if ACPI
+       select SND_INTEL_DSP_CONFIG
        help
          This option is not user-selectable but automagically handled by
          'select' statements at a higher level
index d66412a778739772b002bb2457524e260c0888e8..3a9e0e2a150d31fc8f1fe910fb76ded1314301a0 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/pm_runtime.h>
+#include <sound/intel-dsp-config.h>
 #include <sound/soc-acpi.h>
 #include <sound/soc-acpi-intel-match.h>
 #include <sound/sof.h>
@@ -277,6 +278,11 @@ static int sof_pci_probe(struct pci_dev *pci,
        const struct snd_sof_dsp_ops *ops;
        int ret;
 
+       ret = snd_intel_dsp_driver_probe(pci);
+       if (ret != SND_INTEL_DSP_DRIVER_ANY &&
+           ret != SND_INTEL_DSP_DRIVER_SOF)
+               return -ENODEV;
+
        dev_dbg(&pci->dev, "PCI DSP detected");
 
        /* get ops for platform */
index 69973179ef15a1048838d9a89d576f699acc11bc..1d3586b68db7134e2a9bde5be3019e3f4419385d 100644 (file)
@@ -9,15 +9,15 @@ config SND_SOC_XILINX_I2S
          encapsulates PCM in AES format and sends AES data.
 
 config SND_SOC_XILINX_AUDIO_FORMATTER
-        tristate "Audio support for the the Xilinx audio formatter"
-        help
-          Select this option to enable Xilinx audio formatter
-          support. This provides DMA platform device support for
-          audio functionality.
+       tristate "Audio support for the the Xilinx audio formatter"
+       help
+         Select this option to enable Xilinx audio formatter
+         support. This provides DMA platform device support for
+         audio functionality.
 
 config SND_SOC_XILINX_SPDIF
-        tristate "Audio support for the the Xilinx SPDIF"
-        help
-          Select this option to enable Xilinx SPDIF Audio.
-          This provides playback and capture of SPDIF audio in
-          AES format.
+       tristate "Audio support for the the Xilinx SPDIF"
+       help
+         Select this option to enable Xilinx SPDIF Audio.
+         This provides playback and capture of SPDIF audio in
+         AES format.
index a7842e4b791c2713a3eed30a1e487d22459991e3..a23d4f13ca19e0a95d6a41b9d9bfe7a3908baf45 100644 (file)
@@ -18,9 +18,9 @@ config ZX_I2S
          ZTE ZX I2S interface
 
 config ZX_TDM
-        tristate "ZTE ZX TDM Driver Support"
-        depends on COMMON_CLK
-        select SND_SOC_GENERIC_DMAENGINE_PCM
-        help
-          Say Y or M if you want to add support for codecs attached to the
-          ZTE ZX TDM interface
+       tristate "ZTE ZX TDM Driver Support"
+       depends on COMMON_CLK
+       select SND_SOC_GENERIC_DMAENGINE_PCM
+       help
+         Say Y or M if you want to add support for codecs attached to the
+         ZTE ZX TDM interface
index e2c53a0841da34403ede69d90f7216e512870b8e..059242f15d758b490d6be442a68943a4143a7cc7 100644 (file)
@@ -107,24 +107,24 @@ config SND_USB_US122L
          will be called snd-usb-us122l.
 
 config SND_USB_6FIRE
-        tristate "TerraTec DMX 6Fire USB"
-        select FW_LOADER
-        select BITREVERSE
-        select SND_RAWMIDI
-        select SND_PCM
-        select SND_VMASTER
-        help
-          Say Y here to include support for TerraTec 6fire DMX USB interface.
-
-          You will need firmware files in order to be able to use the device
-          after it has been coldstarted. An install script for the firmware
-          and further help can be found at
-          http://sixfireusb.sourceforge.net
+       tristate "TerraTec DMX 6Fire USB"
+       select FW_LOADER
+       select BITREVERSE
+       select SND_RAWMIDI
+       select SND_PCM
+       select SND_VMASTER
+       help
+         Say Y here to include support for TerraTec 6fire DMX USB interface.
+
+         You will need firmware files in order to be able to use the device
+         after it has been coldstarted. An install script for the firmware
+         and further help can be found at
+         http://sixfireusb.sourceforge.net
 
 config SND_USB_HIFACE
-        tristate "M2Tech hiFace USB-SPDIF driver"
-        select SND_PCM
-        help
+       tristate "M2Tech hiFace USB-SPDIF driver"
+       select SND_PCM
+       help
          Select this option to include support for M2Tech hiFace USB-SPDIF
          interface.
 
index 5fd4e32247a6d6967591ce058eb86acfb53167ab..cd389d21219a769cc1914848c3d6422c10de8da2 100644 (file)
@@ -1708,10 +1708,8 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)
 
        /* get resources */
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "Could not get irq resource: %d\n", irq);
+       if (irq < 0)
                return irq;
-       }
 
        res_mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res_mmio) {