Merge remote-tracking branch 'takashi/for-next' into tag/merge-20191111

This commit is contained in:
Pierre-Louis Bossart 2019-11-11 14:27:04 -06:00
commit 7faa29780b
167 changed files with 2148 additions and 1142 deletions

View File

@ -1383,7 +1383,7 @@ shows only the skeleton, how to build up the PCM interfaces.
/* pre-allocation of buffers */
/* NOTE: this may fail */
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
&chip->pci->dev,
64*1024, 64*1024);
return 0;
}
@ -1470,7 +1470,7 @@ buffer. For the pre-allocation, simply call the following:
::
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
&chip->pci->dev,
64*1024, 64*1024);
It will allocate a buffer up to 64kB as default. Buffer management
@ -2095,10 +2095,12 @@ This callback is atomic as default.
page callback
~~~~~~~~~~~~~
This callback is optional too. This callback is used mainly for
non-contiguous buffers. The mmap calls this callback to get the page
address. Some examples will be explained in the later section `Buffer
and Memory Management`_, too.
This callback is optional too. The mmap calls this callback to get the
page fault address.
Since the recent changes, you need no special callback any longer for
the standard SG-buffer or vmalloc-buffer. Hence this callback should
be rarely used.
mmap calllback
~~~~~~~~~~~~~~
@ -3512,7 +3514,7 @@ bus).
::
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(pci), size, max);
&pci->dev, size, max);
where ``size`` is the byte size to be pre-allocated and the ``max`` is
the maximum size to be changed via the ``prealloc`` proc file. The
@ -3523,12 +3525,14 @@ The second argument (type) and the third argument (device pointer) are
dependent on the bus. For normal devices, pass the device pointer
(typically identical as ``card->dev``) to the third argument with
``SNDRV_DMA_TYPE_DEV`` type. For the continuous buffer unrelated to the
bus can be pre-allocated with ``SNDRV_DMA_TYPE_CONTINUOUS`` type and the
``snd_dma_continuous_data(GFP_KERNEL)`` device pointer, where
``GFP_KERNEL`` is the kernel allocation flag to use. For the
scatter-gather buffers, use ``SNDRV_DMA_TYPE_DEV_SG`` with the device
pointer (see the `Non-Contiguous Buffers`_
section).
bus can be pre-allocated with ``SNDRV_DMA_TYPE_CONTINUOUS`` type.
You can pass NULL to the device pointer in that case, which is the
default mode implying to allocate with ``GFP_KRENEL`` flag.
If you need a different GFP flag, you can pass it by encoding the flag
into the device pointer via a special macro
:c:func:`snd_dma_continuous_data()`.
For the scatter-gather buffers, use ``SNDRV_DMA_TYPE_DEV_SG`` with the
device pointer (see the `Non-Contiguous Buffers`_ section).
Once the buffer is pre-allocated, you can use the allocator in the
``hw_params`` callback:
@ -3696,10 +3700,17 @@ For creating the SG-buffer handler, call
:c:func:`snd_pcm_lib_preallocate_pages()` or
:c:func:`snd_pcm_lib_preallocate_pages_for_all()` with
``SNDRV_DMA_TYPE_DEV_SG`` in the PCM constructor like other PCI
pre-allocator. You need to pass ``snd_dma_pci_data(pci)``, where pci is
pre-allocator. You need to pass ``&pci->dev``, where pci is
the :c:type:`struct pci_dev <pci_dev>` pointer of the chip as
well. The ``struct snd_sg_buf`` instance is created as
``substream->dma_private``. You can cast the pointer like:
well.
::
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
&pci->dev, size, max);
The ``struct snd_sg_buf`` instance is created as
``substream->dma_private`` in turn. You can cast the pointer like:
::
@ -3715,10 +3726,6 @@ physically non-contiguous. The physical address table is set up in
``sgbuf->table``. You can get the physical address at a certain offset
via :c:func:`snd_pcm_sgbuf_get_addr()`.
When a SG-handler is used, you need to set
:c:func:`snd_pcm_sgbuf_ops_page()` as the ``page`` callback. (See
`page callback`_ section.)
To release the data, call :c:func:`snd_pcm_lib_free_pages()` in
the ``hw_free`` callback as usual.
@ -3726,30 +3733,33 @@ Vmalloc'ed Buffers
------------------
It's possible to use a buffer allocated via :c:func:`vmalloc()`, for
example, for an intermediate buffer. Since the allocated pages are not
contiguous, you need to set the ``page`` callback to obtain the physical
address at every offset.
The easiest way to achieve it would be to use
:c:func:`snd_pcm_lib_alloc_vmalloc_buffer()` for allocating the buffer
via :c:func:`vmalloc()`, and set :c:func:`snd_pcm_sgbuf_ops_page()` to
the ``page`` callback. At release, you need to call
:c:func:`snd_pcm_lib_free_vmalloc_buffer()`.
If you want to implementation the ``page`` manually, it would be like
this:
example, for an intermediate buffer. In the recent version of kernel,
you can simply allocate it via standard
:c:func:`snd_pcm_lib_malloc_pages()` and co after setting up the
buffer preallocation with ``SNDRV_DMA_TYPE_VMALLOC`` type.
::
#include <linux/vmalloc.h>
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
NULL, 0, 0);
/* get the physical page pointer on the given offset */
static struct page *mychip_page(struct snd_pcm_substream *substream,
unsigned long offset)
{
void *pageptr = substream->runtime->dma_area + offset;
return vmalloc_to_page(pageptr);
}
The NULL is passed to the device pointer argument, which indicates
that the default pages (GFP_KERNEL and GFP_HIGHMEM) will be
allocated.
Also, note that zero is passed to both the size and the max size
arguments here. Since each vmalloc call should succeed at any time,
we don't need to pre-allocate the buffers like other continuous
pages.
If you need the 32bit DMA allocation, pass the device pointer encoded
by :c:func:`snd_dma_continuous_data()` with ``GFP_KERNEL|__GFP_DMA32``
argument.
::
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
snd_dma_continuous_data(GFP_KERNEL | __GFP_DMA32), 0, 0);
Proc Interface
==============

View File

@ -353,7 +353,7 @@ static int solo_snd_pcm_init(struct solo_dev *solo_dev)
snd_pcm_lib_preallocate_pages_for_all(pcm,
SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_KERNEL),
NULL,
G723_PERIOD_BYTES * PERIODS,
G723_PERIOD_BYTES * PERIODS);

View File

@ -300,7 +300,7 @@ static int tw686x_snd_pcm_init(struct tw686x_dev *dev)
snd_pcm_lib_preallocate_pages_for_all(pcm,
SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(dev->pci_dev),
&dev->pci_dev->dev,
TW686X_AUDIO_PAGE_MAX * AUDIO_DMA_SIZE_MAX,
TW686X_AUDIO_PAGE_MAX * AUDIO_DMA_SIZE_MAX);
return 0;

View File

@ -378,8 +378,7 @@ int usbtv_audio_init(struct usbtv *usbtv)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usbtv_pcm_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_KERNEL), USBTV_AUDIO_BUFFER,
USBTV_AUDIO_BUFFER);
NULL, USBTV_AUDIO_BUFFER, USBTV_AUDIO_BUFFER);
rv = snd_card_register(card);
if (rv)

View File

@ -5854,6 +5854,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

View File

@ -344,8 +344,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
pr_err("Requested number of channels not supported.\n");
return -EINVAL;
}
return snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
}
/**
@ -359,7 +358,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
*/
static int pcm_hw_free(struct snd_pcm_substream *substream)
{
return snd_pcm_lib_free_vmalloc_buffer(substream);
return snd_pcm_lib_free_pages(substream);
}
/**
@ -469,7 +468,6 @@ static const struct snd_pcm_ops pcm_ops = {
.prepare = pcm_prepare,
.trigger = pcm_trigger,
.pointer = pcm_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
};
static int split_arg_list(char *buf, u16 *ch_num, char **sample_res)
@ -663,6 +661,8 @@ static int audio_probe_channel(struct most_interface *iface, int channel_id,
pcm->private_data = channel;
strscpy(pcm->name, device_name, sizeof(pcm->name));
snd_pcm_set_ops(pcm, direction, &pcm_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
NULL, 0, 0);
return 0;

View File

@ -585,7 +585,7 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
sprintf(card->longname, "%s %i", card_name, card->dev->id);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_KERNEL), 0, BUFF_SIZE_MAX);
NULL, 0, BUFF_SIZE_MAX);
err = snd_card_register(card);

View 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

View File

@ -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

View File

@ -21,7 +21,6 @@ struct snd_dma_device {
struct device *dev; /* generic device */
};
#define snd_dma_pci_data(pci) (&(pci)->dev)
#define snd_dma_continuous_data(x) ((struct device *)(__force unsigned long)(x))
@ -44,6 +43,7 @@ struct snd_dma_device {
#else
#define SNDRV_DMA_TYPE_DEV_IRAM SNDRV_DMA_TYPE_DEV
#endif
#define SNDRV_DMA_TYPE_VMALLOC 7 /* vmalloc'ed buffer */
/*
* info for buffer allocation

View File

@ -1236,14 +1236,6 @@ static inline int snd_pcm_lib_alloc_vmalloc_32_buffer
*/
#define snd_pcm_substream_sgbuf(substream) \
snd_pcm_get_dma_buf(substream)->private_data
struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream,
unsigned long offset);
#else /* !SND_DMA_SGBUF */
/*
* fake using a continuous buffer
*/
#define snd_pcm_sgbuf_ops_page NULL
#endif /* SND_DMA_SGBUF */
/**

View File

@ -118,8 +118,10 @@ int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer);
int snd_timer_global_free(struct snd_timer *timer);
int snd_timer_global_register(struct snd_timer *timer);
int snd_timer_open(struct snd_timer_instance **ti, char *owner, struct snd_timer_id *tid, unsigned int slave_id);
int snd_timer_close(struct snd_timer_instance *timeri);
struct snd_timer_instance *snd_timer_instance_new(const char *owner);
void snd_timer_instance_free(struct snd_timer_instance *timeri);
int snd_timer_open(struct snd_timer_instance *timeri, struct snd_timer_id *tid, unsigned int slave_id);
void snd_timer_close(struct snd_timer_instance *timeri);
unsigned long snd_timer_resolution(struct snd_timer_instance *timeri);
int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks);
int snd_timer_stop(struct snd_timer_instance *timeri);

View File

@ -1028,7 +1028,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
/* well, we really should support scatter/gather DMA */
snd_pcm_lib_preallocate_pages_for_all(
dev->pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(macio_get_pci_dev(i2sdev->macio)),
&macio_get_pci_dev(i2sdev->macio)->dev,
64 * 1024, 64 * 1024);
return 0;

View 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.

View File

@ -10,6 +10,7 @@
#include <linux/mm.h>
#include <linux/dma-mapping.h>
#include <linux/genalloc.h>
#include <linux/vmalloc.h>
#ifdef CONFIG_X86
#include <asm/set_memory.h>
#endif
@ -99,6 +100,14 @@ static void snd_free_dev_iram(struct snd_dma_buffer *dmab)
*
*/
static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev,
gfp_t default_gfp)
{
if (!dev)
return default_gfp;
else
return (__force gfp_t)(unsigned long)dev;
}
/**
* snd_dma_alloc_pages - allocate the buffer area according to the given type
@ -116,20 +125,25 @@ static void snd_free_dev_iram(struct snd_dma_buffer *dmab)
int snd_dma_alloc_pages(int type, struct device *device, size_t size,
struct snd_dma_buffer *dmab)
{
gfp_t gfp;
if (WARN_ON(!size))
return -ENXIO;
if (WARN_ON(!dmab))
return -ENXIO;
if (WARN_ON(!device))
return -EINVAL;
dmab->dev.type = type;
dmab->dev.dev = device;
dmab->bytes = 0;
switch (type) {
case SNDRV_DMA_TYPE_CONTINUOUS:
dmab->area = alloc_pages_exact(size,
(__force gfp_t)(unsigned long)device);
gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL);
dmab->area = alloc_pages_exact(size, gfp);
dmab->addr = 0;
break;
case SNDRV_DMA_TYPE_VMALLOC:
gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL | __GFP_HIGHMEM);
dmab->area = __vmalloc(size, gfp, PAGE_KERNEL);
dmab->addr = 0;
break;
#ifdef CONFIG_HAS_DMA
@ -215,6 +229,9 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
case SNDRV_DMA_TYPE_CONTINUOUS:
free_pages_exact(dmab->area, dmab->bytes);
break;
case SNDRV_DMA_TYPE_VMALLOC:
vfree(dmab->area);
break;
#ifdef CONFIG_HAS_DMA
#ifdef CONFIG_GENERIC_ALLOCATOR
case SNDRV_DMA_TYPE_DEV_IRAM:

View File

@ -67,4 +67,9 @@ static inline void snd_pcm_timer_done(struct snd_pcm_substream *substream) {}
void __snd_pcm_xrun(struct snd_pcm_substream *substream);
void snd_pcm_group_init(struct snd_pcm_group *group);
#ifdef CONFIG_SND_DMA_SGBUF
struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream,
unsigned long offset);
#endif
#endif /* __SOUND_CORE_PCM_LOCAL_H */

View File

@ -203,7 +203,8 @@ static void snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream,
if (substream->dma_buffer.bytes > 0)
substream->buffer_bytes_max = substream->dma_buffer.bytes;
substream->dma_max = max;
preallocate_info_init(substream);
if (max > 0)
preallocate_info_init(substream);
}
@ -221,6 +222,8 @@ void snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream,
int type, struct device *data,
size_t size, size_t max)
{
if (snd_BUG_ON(substream->dma_buffer.dev.type))
return;
substream->dma_buffer.dev.type = type;
substream->dma_buffer.dev.dev = data;
snd_pcm_lib_preallocate_pages1(substream, size, max);
@ -252,7 +255,7 @@ void snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);
#ifdef CONFIG_SND_DMA_SGBUF
/**
/*
* snd_pcm_sgbuf_ops_page - get the page struct at the given offset
* @substream: the pcm substream instance
* @offset: the buffer offset
@ -270,7 +273,6 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne
return NULL;
return sgbuf->page_table[idx];
}
EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
#endif /* CONFIG_SND_DMA_SGBUF */
/**

View File

@ -13,6 +13,7 @@
#include <linux/pm_qos.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/vmalloc.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/info.h>
@ -222,7 +223,8 @@ static bool hw_support_mmap(struct snd_pcm_substream *substream)
return false;
if (substream->ops->mmap ||
substream->dma_buffer.dev.type != SNDRV_DMA_TYPE_DEV)
(substream->dma_buffer.dev.type != SNDRV_DMA_TYPE_DEV &&
substream->dma_buffer.dev.type != SNDRV_DMA_TYPE_DEV_UC))
return true;
return dma_can_mmap(substream->dma_buffer.dev.dev);
@ -3334,7 +3336,18 @@ static inline struct page *
snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs)
{
void *vaddr = substream->runtime->dma_area + ofs;
return virt_to_page(vaddr);
switch (substream->dma_buffer.dev.type) {
#ifdef CONFIG_SND_DMA_SGBUF
case SNDRV_DMA_TYPE_DEV_SG:
case SNDRV_DMA_TYPE_DEV_UC_SG:
return snd_pcm_sgbuf_ops_page(substream, ofs);
#endif /* CONFIG_SND_DMA_SGBUF */
case SNDRV_DMA_TYPE_VMALLOC:
return vmalloc_to_page(vaddr);
default:
return virt_to_page(vaddr);
}
}
/*
@ -3403,7 +3416,8 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
#endif /* CONFIG_GENERIC_ALLOCATOR */
#ifndef CONFIG_X86 /* for avoiding warnings arch/x86/mm/pat.c */
if (IS_ENABLED(CONFIG_HAS_DMA) && !substream->ops->page &&
substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
(substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV ||
substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_UC))
return dma_mmap_coherent(substream->dma_buffer.dev.dev,
area,
substream->runtime->dma_area,

View File

@ -272,7 +272,13 @@ int snd_seq_timer_open(struct snd_seq_queue *q)
return -EINVAL;
if (tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_SLAVE)
tmr->alsa_id.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER;
err = snd_timer_open(&t, str, &tmr->alsa_id, q->queue);
t = snd_timer_instance_new(str);
if (!t)
return -ENOMEM;
t->callback = snd_seq_timer_interrupt;
t->callback_data = q;
t->flags |= SNDRV_TIMER_IFLG_AUTO;
err = snd_timer_open(t, &tmr->alsa_id, q->queue);
if (err < 0 && tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_SLAVE) {
if (tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_GLOBAL ||
tmr->alsa_id.device != SNDRV_TIMER_GLOBAL_SYSTEM) {
@ -282,16 +288,14 @@ int snd_seq_timer_open(struct snd_seq_queue *q)
tid.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER;
tid.card = -1;
tid.device = SNDRV_TIMER_GLOBAL_SYSTEM;
err = snd_timer_open(&t, str, &tid, q->queue);
err = snd_timer_open(t, &tid, q->queue);
}
}
if (err < 0) {
pr_err("ALSA: seq fatal error: cannot create timer (%i)\n", err);
snd_timer_instance_free(t);
return err;
}
t->callback = snd_seq_timer_interrupt;
t->callback_data = q;
t->flags |= SNDRV_TIMER_IFLG_AUTO;
spin_lock_irq(&tmr->lock);
tmr->timeri = t;
spin_unlock_irq(&tmr->lock);
@ -310,8 +314,10 @@ int snd_seq_timer_close(struct snd_seq_queue *q)
t = tmr->timeri;
tmr->timeri = NULL;
spin_unlock_irq(&tmr->lock);
if (t)
if (t) {
snd_timer_close(t);
snd_timer_instance_free(t);
}
return 0;
}

View File

@ -74,6 +74,9 @@ static LIST_HEAD(snd_timer_slave_list);
/* lock for slave active lists */
static DEFINE_SPINLOCK(slave_active_lock);
#define MAX_SLAVE_INSTANCES 1000
static int num_slaves;
static DEFINE_MUTEX(register_mutex);
static int snd_timer_free(struct snd_timer *timer);
@ -85,12 +88,11 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l
/*
* create a timer instance with the given owner string.
* when timer is not NULL, increments the module counter
*/
static struct snd_timer_instance *snd_timer_instance_new(char *owner,
struct snd_timer *timer)
struct snd_timer_instance *snd_timer_instance_new(const char *owner)
{
struct snd_timer_instance *timeri;
timeri = kzalloc(sizeof(*timeri), GFP_KERNEL);
if (timeri == NULL)
return NULL;
@ -105,15 +107,20 @@ static struct snd_timer_instance *snd_timer_instance_new(char *owner,
INIT_LIST_HEAD(&timeri->slave_list_head);
INIT_LIST_HEAD(&timeri->slave_active_head);
timeri->timer = timer;
if (timer && !try_module_get(timer->module)) {
kfree(timeri->owner);
kfree(timeri);
return NULL;
}
return timeri;
}
EXPORT_SYMBOL(snd_timer_instance_new);
void snd_timer_instance_free(struct snd_timer_instance *timeri)
{
if (timeri) {
if (timeri->private_free)
timeri->private_free(timeri);
kfree(timeri->owner);
kfree(timeri);
}
}
EXPORT_SYMBOL(snd_timer_instance_free);
/*
* find a timer instance from the given timer id
@ -160,6 +167,28 @@ static void snd_timer_request(struct snd_timer_id *tid)
#endif
/* move the slave if it belongs to the master; return 1 if match */
static int check_matching_master_slave(struct snd_timer_instance *master,
struct snd_timer_instance *slave)
{
if (slave->slave_class != master->slave_class ||
slave->slave_id != master->slave_id)
return 0;
if (master->timer->num_instances >= master->timer->max_instances)
return -EBUSY;
list_move_tail(&slave->open_list, &master->slave_list_head);
master->timer->num_instances++;
spin_lock_irq(&slave_active_lock);
spin_lock(&master->timer->lock);
slave->master = master;
slave->timer = master->timer;
if (slave->flags & SNDRV_TIMER_IFLG_RUNNING)
list_add_tail(&slave->active_list, &master->slave_active_head);
spin_unlock(&master->timer->lock);
spin_unlock_irq(&slave_active_lock);
return 1;
}
/*
* look for a master instance matching with the slave id of the given slave.
* when found, relink the open_link of the slave.
@ -170,27 +199,18 @@ static int snd_timer_check_slave(struct snd_timer_instance *slave)
{
struct snd_timer *timer;
struct snd_timer_instance *master;
int err = 0;
/* FIXME: it's really dumb to look up all entries.. */
list_for_each_entry(timer, &snd_timer_list, device_list) {
list_for_each_entry(master, &timer->open_list_head, open_list) {
if (slave->slave_class == master->slave_class &&
slave->slave_id == master->slave_id) {
if (master->timer->num_instances >=
master->timer->max_instances)
return -EBUSY;
list_move_tail(&slave->open_list,
&master->slave_list_head);
master->timer->num_instances++;
spin_lock_irq(&slave_active_lock);
slave->master = master;
slave->timer = master->timer;
spin_unlock_irq(&slave_active_lock);
return 0;
}
err = check_matching_master_slave(master, slave);
if (err != 0) /* match found or error */
goto out;
}
}
return 0;
out:
return err < 0 ? err : 0;
}
/*
@ -202,43 +222,29 @@ static int snd_timer_check_slave(struct snd_timer_instance *slave)
static int snd_timer_check_master(struct snd_timer_instance *master)
{
struct snd_timer_instance *slave, *tmp;
int err = 0;
/* check all pending slaves */
list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) {
if (slave->slave_class == master->slave_class &&
slave->slave_id == master->slave_id) {
if (master->timer->num_instances >=
master->timer->max_instances)
return -EBUSY;
list_move_tail(&slave->open_list, &master->slave_list_head);
master->timer->num_instances++;
spin_lock_irq(&slave_active_lock);
spin_lock(&master->timer->lock);
slave->master = master;
slave->timer = master->timer;
if (slave->flags & SNDRV_TIMER_IFLG_RUNNING)
list_add_tail(&slave->active_list,
&master->slave_active_head);
spin_unlock(&master->timer->lock);
spin_unlock_irq(&slave_active_lock);
}
err = check_matching_master_slave(master, slave);
if (err < 0)
break;
}
return 0;
return err < 0 ? err : 0;
}
static int snd_timer_close_locked(struct snd_timer_instance *timeri,
struct device **card_devp_to_put);
static void snd_timer_close_locked(struct snd_timer_instance *timeri,
struct device **card_devp_to_put);
/*
* open a timer instance
* when opening a master, the slave id must be here given.
*/
int snd_timer_open(struct snd_timer_instance **ti,
char *owner, struct snd_timer_id *tid,
int snd_timer_open(struct snd_timer_instance *timeri,
struct snd_timer_id *tid,
unsigned int slave_id)
{
struct snd_timer *timer;
struct snd_timer_instance *timeri = NULL;
struct device *card_dev_to_put = NULL;
int err;
@ -252,21 +258,17 @@ int snd_timer_open(struct snd_timer_instance **ti,
err = -EINVAL;
goto unlock;
}
timeri = snd_timer_instance_new(owner, NULL);
if (!timeri) {
err = -ENOMEM;
if (num_slaves >= MAX_SLAVE_INSTANCES) {
err = -EBUSY;
goto unlock;
}
timeri->slave_class = tid->dev_sclass;
timeri->slave_id = tid->device;
timeri->flags |= SNDRV_TIMER_IFLG_SLAVE;
list_add_tail(&timeri->open_list, &snd_timer_slave_list);
num_slaves++;
err = snd_timer_check_slave(timeri);
if (err < 0) {
snd_timer_close_locked(timeri, &card_dev_to_put);
timeri = NULL;
}
goto unlock;
goto list_added;
}
/* open a master instance */
@ -296,45 +298,40 @@ int snd_timer_open(struct snd_timer_instance **ti,
err = -EBUSY;
goto unlock;
}
timeri = snd_timer_instance_new(owner, timer);
if (!timeri) {
err = -ENOMEM;
if (!try_module_get(timer->module)) {
err = -EBUSY;
goto unlock;
}
/* take a card refcount for safe disconnection */
if (timer->card)
if (timer->card) {
get_device(&timer->card->card_dev);
timeri->slave_class = tid->dev_sclass;
timeri->slave_id = slave_id;
card_dev_to_put = &timer->card->card_dev;
}
if (list_empty(&timer->open_list_head) && timer->hw.open) {
err = timer->hw.open(timer);
if (err) {
kfree(timeri->owner);
kfree(timeri);
timeri = NULL;
if (timer->card)
card_dev_to_put = &timer->card->card_dev;
module_put(timer->module);
goto unlock;
}
}
timeri->timer = timer;
timeri->slave_class = tid->dev_sclass;
timeri->slave_id = slave_id;
list_add_tail(&timeri->open_list, &timer->open_list_head);
timer->num_instances++;
err = snd_timer_check_master(timeri);
if (err < 0) {
list_added:
if (err < 0)
snd_timer_close_locked(timeri, &card_dev_to_put);
timeri = NULL;
}
unlock:
mutex_unlock(&register_mutex);
/* put_device() is called after unlock for avoiding deadlock */
if (card_dev_to_put)
if (err < 0 && card_dev_to_put)
put_device(card_dev_to_put);
*ti = timeri;
return err;
}
EXPORT_SYMBOL(snd_timer_open);
@ -343,8 +340,8 @@ EXPORT_SYMBOL(snd_timer_open);
* close a timer instance
* call this with register_mutex down.
*/
static int snd_timer_close_locked(struct snd_timer_instance *timeri,
struct device **card_devp_to_put)
static void snd_timer_close_locked(struct snd_timer_instance *timeri,
struct device **card_devp_to_put)
{
struct snd_timer *timer = timeri->timer;
struct snd_timer_instance *slave, *tmp;
@ -355,7 +352,11 @@ static int snd_timer_close_locked(struct snd_timer_instance *timeri,
spin_unlock_irq(&timer->lock);
}
list_del(&timeri->open_list);
if (!list_empty(&timeri->open_list)) {
list_del_init(&timeri->open_list);
if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
num_slaves--;
}
/* force to stop the timer */
snd_timer_stop(timeri);
@ -374,6 +375,7 @@ static int snd_timer_close_locked(struct snd_timer_instance *timeri,
/* remove slave links */
spin_lock_irq(&slave_active_lock);
spin_lock(&timer->lock);
timeri->timer = NULL;
list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
open_list) {
list_move_tail(&slave->open_list, &snd_timer_slave_list);
@ -391,11 +393,6 @@ static int snd_timer_close_locked(struct snd_timer_instance *timeri,
timer = NULL;
}
if (timeri->private_free)
timeri->private_free(timeri);
kfree(timeri->owner);
kfree(timeri);
if (timer) {
if (list_empty(&timer->open_list_head) && timer->hw.close)
timer->hw.close(timer);
@ -404,28 +401,24 @@ static int snd_timer_close_locked(struct snd_timer_instance *timeri,
*card_devp_to_put = &timer->card->card_dev;
module_put(timer->module);
}
return 0;
}
/*
* close a timer instance
*/
int snd_timer_close(struct snd_timer_instance *timeri)
void snd_timer_close(struct snd_timer_instance *timeri)
{
struct device *card_dev_to_put = NULL;
int err;
if (snd_BUG_ON(!timeri))
return -ENXIO;
return;
mutex_lock(&register_mutex);
err = snd_timer_close_locked(timeri, &card_dev_to_put);
snd_timer_close_locked(timeri, &card_dev_to_put);
mutex_unlock(&register_mutex);
/* put_device() is called after unlock for avoiding deadlock */
if (card_dev_to_put)
put_device(card_dev_to_put);
return err;
}
EXPORT_SYMBOL(snd_timer_close);
@ -1474,8 +1467,10 @@ static int snd_timer_user_release(struct inode *inode, struct file *file)
tu = file->private_data;
file->private_data = NULL;
mutex_lock(&tu->ioctl_lock);
if (tu->timeri)
if (tu->timeri) {
snd_timer_close(tu->timeri);
snd_timer_instance_free(tu->timeri);
}
mutex_unlock(&tu->ioctl_lock);
kfree(tu->queue);
kfree(tu->tqueue);
@ -1716,6 +1711,7 @@ static int snd_timer_user_tselect(struct file *file,
tu = file->private_data;
if (tu->timeri) {
snd_timer_close(tu->timeri);
snd_timer_instance_free(tu->timeri);
tu->timeri = NULL;
}
if (copy_from_user(&tselect, _tselect, sizeof(tselect))) {
@ -1725,9 +1721,11 @@ static int snd_timer_user_tselect(struct file *file,
sprintf(str, "application %i", current->pid);
if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE)
tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION;
err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid);
if (err < 0)
tu->timeri = snd_timer_instance_new(str);
if (!tu->timeri) {
err = -ENOMEM;
goto __err;
}
tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST;
tu->timeri->callback = tu->tread
@ -1736,6 +1734,12 @@ static int snd_timer_user_tselect(struct file *file,
tu->timeri->callback_data = (void *)tu;
tu->timeri->disconnect = snd_timer_user_disconnect;
err = snd_timer_open(tu->timeri, &tselect.id, current->pid);
if (err < 0) {
snd_timer_instance_free(tu->timeri);
tu->timeri = NULL;
}
__err:
return err;
}

View 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"

View File

@ -576,8 +576,7 @@ static void loopback_runtime_free(struct snd_pcm_runtime *runtime)
static int loopback_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
return snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(params));
return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
}
static int loopback_hw_free(struct snd_pcm_substream *substream)
@ -589,7 +588,7 @@ static int loopback_hw_free(struct snd_pcm_substream *substream)
mutex_lock(&dpcm->loopback->cable_lock);
cable->valid &= ~(1 << substream->stream);
mutex_unlock(&dpcm->loopback->cable_lock);
return snd_pcm_lib_free_vmalloc_buffer(substream);
return snd_pcm_lib_free_pages(substream);
}
static unsigned int get_cable_index(struct snd_pcm_substream *substream)
@ -765,7 +764,6 @@ static const struct snd_pcm_ops loopback_pcm_ops = {
.prepare = loopback_prepare,
.trigger = loopback_trigger,
.pointer = loopback_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
};
static int loopback_pcm_new(struct loopback *loopback,
@ -780,6 +778,8 @@ static int loopback_pcm_new(struct loopback *loopback,
return err;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_pcm_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_pcm_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
NULL, 0, 0);
pcm->private_data = loopback;
pcm->info_flags = 0;

View File

@ -702,7 +702,7 @@ static int snd_card_dummy_pcm(struct snd_dummy *dummy, int device,
if (!fake_buffer) {
snd_pcm_lib_preallocate_pages_for_all(pcm,
SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_KERNEL),
NULL,
0, 64*1024);
}
return 0;

View File

@ -1242,7 +1242,7 @@ snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device)
ml403_ac97cr->pcm = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_KERNEL),
NULL,
64 * 1024,
128 * 1024);
return 0;

View File

@ -352,8 +352,8 @@ int snd_pcsp_new_pcm(struct snd_pcsp *chip)
snd_pcm_lib_preallocate_pages_for_all(chip->pcm,
SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data
(GFP_KERNEL), PCSP_BUFFER_SIZE,
NULL,
PCSP_BUFFER_SIZE,
PCSP_BUFFER_SIZE);
return 0;

View File

@ -778,8 +778,7 @@ static snd_pcm_uframes_t vx_pcm_playback_pointer(struct snd_pcm_substream *subs)
static int vx_pcm_hw_params(struct snd_pcm_substream *subs,
struct snd_pcm_hw_params *hw_params)
{
return snd_pcm_lib_alloc_vmalloc_32_buffer
(subs, params_buffer_bytes(hw_params));
return snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw_params));
}
/*
@ -787,7 +786,7 @@ static int vx_pcm_hw_params(struct snd_pcm_substream *subs,
*/
static int vx_pcm_hw_free(struct snd_pcm_substream *subs)
{
return snd_pcm_lib_free_vmalloc_buffer(subs);
return snd_pcm_lib_free_pages(subs);
}
/*
@ -867,7 +866,6 @@ static const struct snd_pcm_ops vx_pcm_playback_ops = {
.prepare = vx_pcm_prepare,
.trigger = vx_pcm_trigger,
.pointer = vx_pcm_playback_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
};
@ -1088,7 +1086,6 @@ static const struct snd_pcm_ops vx_pcm_capture_ops = {
.prepare = vx_pcm_prepare,
.trigger = vx_pcm_trigger,
.pointer = vx_pcm_capture_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
};
@ -1233,6 +1230,9 @@ int snd_vx_pcm_new(struct vx_core *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &vx_pcm_playback_ops);
if (ins)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &vx_pcm_capture_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
snd_dma_continuous_data(GFP_KERNEL | GFP_DMA32),
0, 0);
pcm->private_data = chip;
pcm->private_free = snd_vx_pcm_free;

View 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"

View 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>
@ -52,10 +53,6 @@
#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;
}
}
fw_iso_context_queue_flush(s->context);
}
/* this is executed one time */
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;
}
}
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.
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 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
}
/**
* 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);

View 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

View 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);

View 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);

View File

@ -129,18 +129,17 @@ pcm_init_hw_params(struct snd_bebob *bebob,
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;
@ -190,16 +214,18 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_bebob *bebob = substream->private_data;
int err;
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
if (err < 0)
return err;
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);
@ -221,7 +247,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
mutex_unlock(&bebob->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
return snd_pcm_lib_free_pages(substream);
}
static int
@ -286,31 +312,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)
@ -325,7 +353,6 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
.trigger = pcm_capture_trigger,
.pointer = pcm_capture_pointer,
.ack = pcm_capture_ack,
.page = snd_pcm_lib_get_vmalloc_page,
};
static const struct snd_pcm_ops playback_ops = {
.open = pcm_open,
@ -337,7 +364,6 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
.trigger = pcm_playback_trigger,
.pointer = pcm_playback_pointer,
.ack = pcm_playback_ack,
.page = snd_pcm_lib_get_vmalloc_page,
};
struct snd_pcm *pcm;
int err;
@ -351,6 +377,8 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
"%s PCM", bebob->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
NULL, 0, 0);
end:
return err;
}

View File

@ -7,7 +7,7 @@
#include "./bebob.h"
#define CALLBACK_TIMEOUT 2000
#define CALLBACK_TIMEOUT 2500
#define FW_ISO_RESOURCE_DELAY 1000
/*
@ -398,36 +398,19 @@ check_connection_used_by_others(struct snd_bebob *bebob, struct amdtp_stream *s)
return err;
}
static int make_both_connections(struct snd_bebob *bebob)
{
int err = 0;
err = cmp_connection_establish(&bebob->out_conn);
if (err < 0)
return err;
err = cmp_connection_establish(&bebob->in_conn);
if (err < 0) {
cmp_connection_break(&bebob->out_conn);
return err;
}
return 0;
}
static void
break_both_connections(struct snd_bebob *bebob)
static void break_both_connections(struct snd_bebob *bebob)
{
cmp_connection_break(&bebob->in_conn);
cmp_connection_break(&bebob->out_conn);
/* These models seems to be in transition state for a longer time. */
if (bebob->maudio_special_quirk != NULL)
msleep(200);
// These models seem to be in transition state for a longer time. When
// accessing in the state, any transactions is corrupted. In the worst
// case, the device is going to reboot.
if (bebob->version < 2)
msleep(600);
}
static int
start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
static int start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
{
struct cmp_connection *conn;
int err = 0;
@ -437,18 +420,19 @@ start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
else
conn = &bebob->out_conn;
/* channel mapping */
// channel mapping.
if (bebob->maudio_special_quirk == NULL) {
err = map_data_channels(bebob, stream);
if (err < 0)
goto end;
return err;
}
// start amdtp stream.
err = amdtp_domain_add_stream(&bebob->domain, stream,
conn->resources.channel, conn->speed);
end:
return err;
err = cmp_connection_establish(conn);
if (err < 0)
return err;
return amdtp_domain_add_stream(&bebob->domain, stream,
conn->resources.channel, conn->speed);
}
static int init_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
@ -553,7 +537,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 +592,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;
@ -627,7 +621,10 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
}
if (!amdtp_stream_running(&bebob->rx_stream)) {
enum snd_bebob_clock_type src;
struct amdtp_stream *master, *slave;
unsigned int curr_rate;
unsigned int ir_delay_cycle;
if (bebob->maudio_special_quirk) {
err = bebob->spec->rate->get(bebob, &curr_rate);
@ -635,19 +632,40 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
return err;
}
err = make_both_connections(bebob);
err = snd_bebob_stream_get_clock_src(bebob, &src);
if (err < 0)
return err;
err = start_stream(bebob, &bebob->rx_stream);
if (src != SND_BEBOB_CLOCK_TYPE_SYT) {
master = &bebob->tx_stream;
slave = &bebob->rx_stream;
} else {
master = &bebob->rx_stream;
slave = &bebob->tx_stream;
}
err = start_stream(bebob, master);
if (err < 0)
goto error;
err = start_stream(bebob, &bebob->tx_stream);
err = start_stream(bebob, slave);
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
// 0.4 sec (=3200 cycles) later to version 1 or 2 firmware,
// 2.0 sec (=16000 cycles) for version 3 firmware. This is
// within 2.5 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.
if (bebob->version < 2)
ir_delay_cycle = 3200;
else
ir_delay_cycle = 16000;
err = amdtp_domain_start(&bebob->domain, ir_delay_cycle);
if (err < 0)
goto error;

View 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);

View 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;
@ -236,16 +266,23 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_dice *dice = substream->private_data;
int err;
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
if (err < 0)
return err;
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);
@ -267,7 +304,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
mutex_unlock(&dice->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
return snd_pcm_lib_free_pages(substream);
}
static int capture_prepare(struct snd_pcm_substream *substream)
@ -341,14 +378,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 +393,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 +401,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)
@ -379,7 +416,6 @@ int snd_dice_create_pcm(struct snd_dice *dice)
.trigger = capture_trigger,
.pointer = capture_pointer,
.ack = capture_ack,
.page = snd_pcm_lib_get_vmalloc_page,
};
static const struct snd_pcm_ops playback_ops = {
.open = pcm_open,
@ -391,7 +427,6 @@ int snd_dice_create_pcm(struct snd_dice *dice)
.trigger = playback_trigger,
.pointer = playback_pointer,
.ack = playback_ack,
.page = snd_pcm_lib_get_vmalloc_page,
};
struct snd_pcm *pcm;
unsigned int capture, playback;
@ -421,6 +456,10 @@ int snd_dice_create_pcm(struct snd_dice *dice)
if (playback > 0)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
&playback_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm,
SNDRV_DMA_TYPE_VMALLOC,
NULL, 0, 0);
}
return 0;

View 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;

View 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);

View 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);

View 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;
@ -160,16 +190,18 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_dg00x *dg00x = substream->private_data;
int err;
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
if (err < 0)
return err;
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);
@ -191,7 +223,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
mutex_unlock(&dg00x->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
return snd_pcm_lib_free_pages(substream);
}
static int pcm_capture_prepare(struct snd_pcm_substream *substream)
@ -268,28 +300,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)
@ -304,7 +336,6 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
.trigger = pcm_capture_trigger,
.pointer = pcm_capture_pointer,
.ack = pcm_capture_ack,
.page = snd_pcm_lib_get_vmalloc_page,
};
static const struct snd_pcm_ops playback_ops = {
.open = pcm_open,
@ -316,7 +347,6 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
.trigger = pcm_playback_trigger,
.pointer = pcm_playback_pointer,
.ack = pcm_playback_ack,
.page = snd_pcm_lib_get_vmalloc_page,
};
struct snd_pcm *pcm;
int err;
@ -330,6 +360,8 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
"%s PCM", dg00x->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
NULL, 0, 0);
return 0;
}

View 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;

View 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);

View 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;
@ -204,16 +230,18 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_ff *ff = substream->private_data;
int err;
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
if (err < 0)
return err;
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);
@ -235,7 +263,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
mutex_unlock(&ff->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
return snd_pcm_lib_free_pages(substream);
}
static int pcm_capture_prepare(struct snd_pcm_substream *substream)
@ -312,28 +340,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)
@ -348,7 +376,6 @@ int snd_ff_create_pcm_devices(struct snd_ff *ff)
.trigger = pcm_capture_trigger,
.pointer = pcm_capture_pointer,
.ack = pcm_capture_ack,
.page = snd_pcm_lib_get_vmalloc_page,
};
static const struct snd_pcm_ops pcm_playback_ops = {
.open = pcm_open,
@ -360,7 +387,6 @@ int snd_ff_create_pcm_devices(struct snd_ff *ff)
.trigger = pcm_playback_trigger,
.pointer = pcm_playback_pointer,
.ack = pcm_playback_ack,
.page = snd_pcm_lib_get_vmalloc_page,
};
struct snd_pcm *pcm;
int err;
@ -374,6 +400,8 @@ int snd_ff_create_pcm_devices(struct snd_ff *ff)
"%s PCM", ff->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
NULL, 0, 0);
return 0;
}

View 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;

View 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);

View 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);

View 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);

View File

@ -173,13 +173,13 @@ pcm_init_hw_params(struct snd_efw *efw,
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;
@ -224,16 +250,18 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_efw *efw = substream->private_data;
int err;
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
if (err < 0)
return err;
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);
@ -255,7 +283,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
mutex_unlock(&efw->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
return snd_pcm_lib_free_pages(substream);
}
static int pcm_capture_prepare(struct snd_pcm_substream *substream)
@ -319,26 +347,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)
@ -353,7 +383,6 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw)
.trigger = pcm_capture_trigger,
.pointer = pcm_capture_pointer,
.ack = pcm_capture_ack,
.page = snd_pcm_lib_get_vmalloc_page,
};
static const struct snd_pcm_ops playback_ops = {
.open = pcm_open,
@ -365,7 +394,6 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw)
.trigger = pcm_playback_trigger,
.pointer = pcm_playback_pointer,
.ack = pcm_playback_ack,
.page = snd_pcm_lib_get_vmalloc_page,
};
struct snd_pcm *pcm;
int err;
@ -378,6 +406,8 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw)
snprintf(pcm->name, sizeof(pcm->name), "%s PCM", efw->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
NULL, 0, 0);
end:
return err;
}

View 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;

View File

@ -288,8 +288,7 @@ static int isight_hw_params(struct snd_pcm_substream *substream,
struct isight *isight = substream->private_data;
int err;
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
if (err < 0)
return err;
@ -337,7 +336,7 @@ static int isight_hw_free(struct snd_pcm_substream *substream)
isight_stop_streaming(isight);
mutex_unlock(&isight->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
return snd_pcm_lib_free_pages(substream);
}
static int isight_start_streaming(struct isight *isight)
@ -453,7 +452,6 @@ static int isight_create_pcm(struct isight *isight)
.prepare = isight_prepare,
.trigger = isight_trigger,
.pointer = isight_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
};
struct snd_pcm *pcm;
int err;
@ -465,6 +463,8 @@ static int isight_create_pcm(struct isight *isight)
strcpy(pcm->name, "iSight");
isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
isight->pcm->ops = &ops;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
NULL, 0, 0);
return 0;
}

View 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);

View 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,51 @@ 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;
if (src != SND_MOTU_CLOCK_SOURCE_INTERNAL ||
amdtp_stream_pcm_running(&motu->tx_stream) ||
amdtp_stream_pcm_running(&motu->rx_stream)) {
// 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 &&
src != SND_MOTU_CLOCK_SOURCE_SPH) ||
(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);
@ -195,16 +218,18 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_motu *motu = substream->private_data;
int err;
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
if (err < 0)
return err;
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);
@ -226,7 +251,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
mutex_unlock(&motu->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
return snd_pcm_lib_free_pages(substream);
}
static int capture_prepare(struct snd_pcm_substream *substream)
@ -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)
@ -330,7 +355,6 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu)
.trigger = capture_trigger,
.pointer = capture_pointer,
.ack = capture_ack,
.page = snd_pcm_lib_get_vmalloc_page,
};
static const struct snd_pcm_ops playback_ops = {
.open = pcm_open,
@ -342,7 +366,6 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu)
.trigger = playback_trigger,
.pointer = playback_pointer,
.ack = playback_ack,
.page = snd_pcm_lib_get_vmalloc_page,
};
struct snd_pcm *pcm;
int err;
@ -355,6 +378,8 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
NULL, 0, 0);
return 0;
}

View File

@ -16,9 +16,11 @@ static const char *const clock_names[] = {
[SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT] = "S/PDIF on optical interface",
[SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A] = "S/PDIF on optical interface A",
[SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B] = "S/PDIF on optical interface B",
[SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX] = "S/PCIF on coaxial interface",
[SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX] = "S/PDIF on coaxial interface",
[SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR] = "AESEBU on XLR interface",
[SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC] = "Word clock on BNC interface",
[SND_MOTU_CLOCK_SOURCE_SPH] = "Source packet header",
[SND_MOTU_CLOCK_SOURCE_UNKNOWN] = "Unknown",
};
static void proc_read_clock(struct snd_info_entry *entry,

View File

@ -12,10 +12,8 @@
#define V2_CLOCK_RATE_SHIFT 3
#define V2_CLOCK_SRC_MASK 0x00000007
#define V2_CLOCK_SRC_SHIFT 0
#define V2_CLOCK_TRAVELER_FETCH_DISABLE 0x04000000
#define V2_CLOCK_TRAVELER_FETCH_ENABLE 0x03000000
#define V2_CLOCK_8PRE_FETCH_DISABLE 0x02000000
#define V2_CLOCK_8PRE_FETCH_ENABLE 0x00000000
#define V2_CLOCK_FETCH_ENABLE 0x02000000
#define V2_CLOCK_MODEL_SPECIFIC 0x04000000
#define V2_IN_OUT_CONF_OFFSET 0x0c04
#define V2_OPT_OUT_IFACE_MASK 0x00000c00
@ -26,10 +24,20 @@
#define V2_OPT_IFACE_MODE_ADAT 1
#define V2_OPT_IFACE_MODE_SPDIF 2
static int get_clock_rate(u32 data, unsigned int *rate)
{
unsigned int index = (data & V2_CLOCK_RATE_MASK) >> V2_CLOCK_RATE_SHIFT;
if (index >= ARRAY_SIZE(snd_motu_clock_rates))
return -EIO;
*rate = snd_motu_clock_rates[index];
return 0;
}
static int v2_get_clock_rate(struct snd_motu *motu, unsigned int *rate)
{
__be32 reg;
unsigned int index;
int err;
err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
@ -37,13 +45,7 @@ static int v2_get_clock_rate(struct snd_motu *motu, unsigned int *rate)
if (err < 0)
return err;
index = (be32_to_cpu(reg) & V2_CLOCK_RATE_MASK) >> V2_CLOCK_RATE_SHIFT;
if (index >= ARRAY_SIZE(snd_motu_clock_rates))
return -EIO;
*rate = snd_motu_clock_rates[index];
return 0;
return get_clock_rate(be32_to_cpu(reg), rate);
}
static int v2_set_clock_rate(struct snd_motu *motu, unsigned int rate)
@ -69,51 +71,44 @@ static int v2_set_clock_rate(struct snd_motu *motu, unsigned int rate)
data &= ~V2_CLOCK_RATE_MASK;
data |= i << V2_CLOCK_RATE_SHIFT;
if (motu->spec == &snd_motu_spec_traveler) {
data &= ~V2_CLOCK_TRAVELER_FETCH_ENABLE;
data |= V2_CLOCK_TRAVELER_FETCH_DISABLE;
}
reg = cpu_to_be32(data);
return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, &reg,
sizeof(reg));
}
static int v2_get_clock_source(struct snd_motu *motu,
enum snd_motu_clock_source *src)
static int get_clock_source(struct snd_motu *motu, u32 data,
enum snd_motu_clock_source *src)
{
__be32 reg;
unsigned int index;
int err;
err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
sizeof(reg));
if (err < 0)
return err;
index = be32_to_cpu(reg) & V2_CLOCK_SRC_MASK;
unsigned int index = data & V2_CLOCK_SRC_MASK;
if (index > 5)
return -EIO;
/* To check the configuration of optical interface. */
err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, &reg,
sizeof(reg));
if (err < 0)
return err;
switch (index) {
case 0:
*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
break;
case 1:
{
__be32 reg;
// To check the configuration of optical interface.
int err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET,
&reg, sizeof(reg));
if (err < 0)
return err;
if (be32_to_cpu(reg) & 0x00000200)
*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT;
else
*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;
break;
}
case 2:
*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
break;
case 3:
*src = SND_MOTU_CLOCK_SOURCE_SPH;
break;
case 4:
*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
break;
@ -127,44 +122,65 @@ static int v2_get_clock_source(struct snd_motu *motu,
return 0;
}
static int v2_get_clock_source(struct snd_motu *motu,
enum snd_motu_clock_source *src)
{
__be32 reg;
int err;
err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
sizeof(reg));
if (err < 0)
return err;
return get_clock_source(motu, be32_to_cpu(reg), src);
}
static int v2_switch_fetching_mode(struct snd_motu *motu, bool enable)
{
enum snd_motu_clock_source src;
__be32 reg;
u32 data;
int err = 0;
if (motu->spec == &snd_motu_spec_traveler ||
motu->spec == &snd_motu_spec_8pre) {
err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET,
&reg, sizeof(reg));
// 828mkII implements Altera ACEX 1K EP1K30. Nothing to do.
if (motu->spec == &snd_motu_spec_828mk2)
return 0;
err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
sizeof(reg));
if (err < 0)
return err;
data = be32_to_cpu(reg);
err = get_clock_source(motu, data, &src);
if (err < 0)
return err;
data &= ~(V2_CLOCK_FETCH_ENABLE | V2_CLOCK_MODEL_SPECIFIC);
if (enable)
data |= V2_CLOCK_FETCH_ENABLE;
if (motu->spec->flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4) {
// Expected for Traveler and 896HD, which implements Altera
// Cyclone EP1C3.
data |= V2_CLOCK_MODEL_SPECIFIC;
} else {
// For UltraLite and 8pre, which implements Xilinx Spartan
// XC3S200.
unsigned int rate;
err = get_clock_rate(data, &rate);
if (err < 0)
return err;
data = be32_to_cpu(reg);
if (motu->spec == &snd_motu_spec_traveler) {
data &= ~(V2_CLOCK_TRAVELER_FETCH_DISABLE |
V2_CLOCK_TRAVELER_FETCH_ENABLE);
if (enable)
data |= V2_CLOCK_TRAVELER_FETCH_ENABLE;
else
data |= V2_CLOCK_TRAVELER_FETCH_DISABLE;
} else if (motu->spec == &snd_motu_spec_8pre) {
data &= ~(V2_CLOCK_8PRE_FETCH_DISABLE |
V2_CLOCK_8PRE_FETCH_ENABLE);
if (enable)
data |= V2_CLOCK_8PRE_FETCH_DISABLE;
else
data |= V2_CLOCK_8PRE_FETCH_ENABLE;
}
reg = cpu_to_be32(data);
err = snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET,
&reg, sizeof(reg));
if (src == SND_MOTU_CLOCK_SOURCE_SPH && rate > 48000)
data |= V2_CLOCK_MODEL_SPECIFIC;
}
return err;
reg = cpu_to_be32(data);
return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, &reg,
sizeof(reg));
}
static void calculate_fixed_part(struct snd_motu_packet_format *formats,
@ -191,7 +207,7 @@ static void calculate_fixed_part(struct snd_motu_packet_format *formats,
pcm_chunks[1] += 2;
}
} else {
if (flags & SND_MOTU_SPEC_RX_SEPARETED_MAIN) {
if (flags & SND_MOTU_SPEC_RX_SEPARATED_MAIN) {
pcm_chunks[0] += 2;
pcm_chunks[1] += 2;
}

View File

@ -104,6 +104,8 @@ static int v3_get_clock_source(struct snd_motu *motu,
*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
} else if (val == 0x01) {
*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
} else if (val == 0x02) {
*src = SND_MOTU_CLOCK_SOURCE_SPH;
} else if (val == 0x10) {
*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
} else if (val == 0x18 || val == 0x19) {
@ -187,7 +189,7 @@ static void calculate_fixed_part(struct snd_motu_packet_format *formats,
pcm_chunks[1] += 2;
}
} else {
if (flags & SND_MOTU_SPEC_RX_SEPARETED_MAIN) {
if (flags & SND_MOTU_SPEC_RX_SEPARATED_MAIN) {
pcm_chunks[0] += 2;
pcm_chunks[1] += 2;
}

View 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;

View File

@ -172,13 +172,13 @@ static void motu_bus_update(struct fw_unit *unit)
snd_motu_transaction_reregister(motu);
}
static const struct snd_motu_spec motu_828mk2 = {
const struct snd_motu_spec snd_motu_spec_828mk2 = {
.name = "828mk2",
.protocol = &snd_motu_protocol_v2,
.flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 |
SND_MOTU_SPEC_TX_MICINST_CHUNK |
SND_MOTU_SPEC_TX_RETURN_CHUNK |
SND_MOTU_SPEC_RX_SEPARETED_MAIN |
SND_MOTU_SPEC_RX_SEPARATED_MAIN |
SND_MOTU_SPEC_HAS_OPT_IFACE_A |
SND_MOTU_SPEC_RX_MIDI_2ND_Q |
SND_MOTU_SPEC_TX_MIDI_2ND_Q,
@ -187,7 +187,7 @@ static const struct snd_motu_spec motu_828mk2 = {
.analog_out_ports = 8,
};
const struct snd_motu_spec snd_motu_spec_traveler = {
static const struct snd_motu_spec motu_traveler = {
.name = "Traveler",
.protocol = &snd_motu_protocol_v2,
.flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 |
@ -202,7 +202,20 @@ const struct snd_motu_spec snd_motu_spec_traveler = {
.analog_out_ports = 8,
};
const struct snd_motu_spec snd_motu_spec_8pre = {
static const struct snd_motu_spec motu_ultralite = {
.name = "UltraLite",
.protocol = &snd_motu_protocol_v2,
.flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 |
SND_MOTU_SPEC_TX_MICINST_CHUNK | // padding.
SND_MOTU_SPEC_TX_RETURN_CHUNK |
SND_MOTU_SPEC_RX_MIDI_2ND_Q |
SND_MOTU_SPEC_TX_MIDI_2ND_Q |
SND_MOTU_SPEC_RX_SEPARATED_MAIN,
.analog_in_ports = 8,
.analog_out_ports = 8,
};
static const struct snd_motu_spec motu_8pre = {
.name = "8pre",
.protocol = &snd_motu_protocol_v2,
// In tx, use coax chunks for mix-return 1/2. In rx, use coax chunks for
@ -224,7 +237,7 @@ static const struct snd_motu_spec motu_828mk3 = {
SND_MOTU_SPEC_TX_MICINST_CHUNK |
SND_MOTU_SPEC_TX_RETURN_CHUNK |
SND_MOTU_SPEC_TX_REVERB_CHUNK |
SND_MOTU_SPEC_RX_SEPARETED_MAIN |
SND_MOTU_SPEC_RX_SEPARATED_MAIN |
SND_MOTU_SPEC_HAS_OPT_IFACE_A |
SND_MOTU_SPEC_HAS_OPT_IFACE_B |
SND_MOTU_SPEC_RX_MIDI_3RD_Q |
@ -240,7 +253,7 @@ static const struct snd_motu_spec motu_audio_express = {
.flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 |
SND_MOTU_SPEC_TX_MICINST_CHUNK |
SND_MOTU_SPEC_TX_RETURN_CHUNK |
SND_MOTU_SPEC_RX_SEPARETED_MAIN |
SND_MOTU_SPEC_RX_SEPARATED_MAIN |
SND_MOTU_SPEC_RX_MIDI_2ND_Q |
SND_MOTU_SPEC_TX_MIDI_3RD_Q,
.analog_in_ports = 2,
@ -253,7 +266,7 @@ static const struct snd_motu_spec motu_4pre = {
.flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 |
SND_MOTU_SPEC_TX_MICINST_CHUNK |
SND_MOTU_SPEC_TX_RETURN_CHUNK |
SND_MOTU_SPEC_RX_SEPARETED_MAIN,
SND_MOTU_SPEC_RX_SEPARATED_MAIN,
.analog_in_ports = 2,
.analog_out_ports = 2,
};
@ -270,9 +283,10 @@ static const struct snd_motu_spec motu_4pre = {
}
static const struct ieee1394_device_id motu_id_table[] = {
SND_MOTU_DEV_ENTRY(0x000003, &motu_828mk2),
SND_MOTU_DEV_ENTRY(0x000009, &snd_motu_spec_traveler),
SND_MOTU_DEV_ENTRY(0x00000f, &snd_motu_spec_8pre),
SND_MOTU_DEV_ENTRY(0x000003, &snd_motu_spec_828mk2),
SND_MOTU_DEV_ENTRY(0x000009, &motu_traveler),
SND_MOTU_DEV_ENTRY(0x00000d, &motu_ultralite),
SND_MOTU_DEV_ENTRY(0x00000f, &motu_8pre),
SND_MOTU_DEV_ENTRY(0x000015, &motu_828mk3), /* FireWire only. */
SND_MOTU_DEV_ENTRY(0x000035, &motu_828mk3), /* Hybrid. */
SND_MOTU_DEV_ENTRY(0x000033, &motu_audio_express),

View File

@ -86,7 +86,7 @@ enum snd_motu_spec_flags {
SND_MOTU_SPEC_RX_MIDI_3RD_Q = 0x0200,
SND_MOTU_SPEC_TX_MIDI_2ND_Q = 0x0400,
SND_MOTU_SPEC_TX_MIDI_3RD_Q = 0x0800,
SND_MOTU_SPEC_RX_SEPARETED_MAIN = 0x1000,
SND_MOTU_SPEC_RX_SEPARATED_MAIN = 0x1000,
};
#define SND_MOTU_CLOCK_RATE_COUNT 6
@ -104,6 +104,7 @@ enum snd_motu_clock_source {
SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX,
SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR,
SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC,
SND_MOTU_CLOCK_SOURCE_SPH,
SND_MOTU_CLOCK_SOURCE_UNKNOWN,
};
@ -129,8 +130,7 @@ struct snd_motu_spec {
extern const struct snd_motu_protocol snd_motu_protocol_v2;
extern const struct snd_motu_protocol snd_motu_protocol_v3;
extern const struct snd_motu_spec snd_motu_spec_traveler;
extern const struct snd_motu_spec snd_motu_spec_8pre;
extern const struct snd_motu_spec snd_motu_spec_828mk2;
int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir,
@ -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);

View 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);

View File

@ -170,30 +170,56 @@ static int limit_to_current_params(struct snd_pcm_substream *substream)
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;
@ -213,18 +239,20 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
struct snd_oxfw *oxfw = substream->private_data;
int err;
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
if (err < 0)
return err;
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);
@ -238,18 +266,20 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
struct snd_oxfw *oxfw = substream->private_data;
int err;
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
if (err < 0)
return err;
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);
@ -271,7 +301,7 @@ static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
mutex_unlock(&oxfw->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
return snd_pcm_lib_free_pages(substream);
}
static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
{
@ -286,7 +316,7 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
mutex_unlock(&oxfw->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
return snd_pcm_lib_free_pages(substream);
}
static int pcm_capture_prepare(struct snd_pcm_substream *substream)
@ -361,27 +391,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)
@ -396,7 +426,6 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw)
.trigger = pcm_capture_trigger,
.pointer = pcm_capture_pointer,
.ack = pcm_capture_ack,
.page = snd_pcm_lib_get_vmalloc_page,
};
static const struct snd_pcm_ops playback_ops = {
.open = pcm_open,
@ -408,7 +437,6 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw)
.trigger = pcm_playback_trigger,
.pointer = pcm_playback_pointer,
.ack = pcm_playback_ack,
.page = snd_pcm_lib_get_vmalloc_page,
};
struct snd_pcm *pcm;
unsigned int cap = 0;
@ -426,6 +454,8 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
if (cap > 0)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
NULL, 0, 0);
return 0;
}

View 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;

View 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);

View 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;
@ -92,16 +119,18 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_tscm *tscm = substream->private_data;
int err;
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
if (err < 0)
return err;
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);
@ -123,7 +152,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
mutex_unlock(&tscm->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
return snd_pcm_lib_free_pages(substream);
}
static int pcm_capture_prepare(struct snd_pcm_substream *substream)
@ -200,28 +229,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)
@ -236,7 +265,6 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
.trigger = pcm_capture_trigger,
.pointer = pcm_capture_pointer,
.ack = pcm_capture_ack,
.page = snd_pcm_lib_get_vmalloc_page,
};
static const struct snd_pcm_ops playback_ops = {
.open = pcm_open,
@ -248,7 +276,6 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
.trigger = pcm_playback_trigger,
.pointer = pcm_playback_pointer,
.ack = pcm_playback_ack,
.page = snd_pcm_lib_get_vmalloc_page,
};
struct snd_pcm *pcm;
int err;
@ -262,6 +289,8 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
"%s PCM", tscm->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
NULL, 0, 0);
return 0;
}

View 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;

View 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);

View 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.
# 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.

View 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

View File

@ -363,6 +363,7 @@ static const struct regmap_config hda_regmap_cfg = {
.reg_write = hda_reg_write,
.use_single_read = true,
.use_single_write = true,
.disable_locking = true,
};
/**

View File

@ -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;
/* Intel vendor only */
if (pci->vendor != 0x8086)
return SND_INTEL_DSP_DRIVER_ANY;
if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
return dsp_driver;
/*
* 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");

View 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");

View 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"

View 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

View File

@ -741,8 +741,7 @@ static int hal2_pcm_create(struct snd_hal2 *hal2)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
&hal2_capture_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_KERNEL),
0, 1024 * 1024);
NULL, 0, 1024 * 1024);
return 0;
}

View File

@ -582,14 +582,13 @@ static int snd_sgio2audio_pcm_close(struct snd_pcm_substream *substream)
static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
return snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
}
/* hw_free callback */
static int snd_sgio2audio_pcm_hw_free(struct snd_pcm_substream *substream)
{
return snd_pcm_lib_free_vmalloc_buffer(substream);
return snd_pcm_lib_free_pages(substream);
}
/* prepare callback */
@ -670,7 +669,6 @@ static const struct snd_pcm_ops snd_sgio2audio_playback1_ops = {
.prepare = snd_sgio2audio_pcm_prepare,
.trigger = snd_sgio2audio_pcm_trigger,
.pointer = snd_sgio2audio_pcm_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
};
static const struct snd_pcm_ops snd_sgio2audio_playback2_ops = {
@ -682,7 +680,6 @@ static const struct snd_pcm_ops snd_sgio2audio_playback2_ops = {
.prepare = snd_sgio2audio_pcm_prepare,
.trigger = snd_sgio2audio_pcm_trigger,
.pointer = snd_sgio2audio_pcm_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
};
static const struct snd_pcm_ops snd_sgio2audio_capture_ops = {
@ -694,7 +691,6 @@ static const struct snd_pcm_ops snd_sgio2audio_capture_ops = {
.prepare = snd_sgio2audio_pcm_prepare,
.trigger = snd_sgio2audio_pcm_trigger,
.pointer = snd_sgio2audio_pcm_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
};
/*
@ -720,6 +716,8 @@ static int snd_sgio2audio_new_pcm(struct snd_sgio2audio *chip)
&snd_sgio2audio_playback1_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
&snd_sgio2audio_capture_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
NULL, 0, 0);
/* create second pcm device with one outputs and no input */
err = snd_pcm_new(chip->card, "SGI O2 Audio", 1, 1, 0, &pcm);
@ -732,6 +730,8 @@ static int snd_sgio2audio_new_pcm(struct snd_sgio2audio *chip)
/* set operators */
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
&snd_sgio2audio_playback2_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
NULL, 0, 0);
return 0;
}

View 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)"

View File

@ -633,9 +633,9 @@ snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device)
chip->csubs = NULL;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
BUFFER_BYTES_MAX / 2,
BUFFER_BYTES_MAX);
&chip->pci->dev,
BUFFER_BYTES_MAX / 2,
BUFFER_BYTES_MAX);
return 0;
}

View File

@ -1672,7 +1672,7 @@ static int snd_ali_pcm(struct snd_ali *codec, int device,
desc->capture_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(codec->pci),
&codec->pci->dev,
64*1024, 128*1024);
pcm->info_flags = 0;

View File

@ -592,7 +592,8 @@ static int snd_als300_new_pcm(struct snd_als300 *chip)
/* pre-allocation of buffers */
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 64*1024);
&chip->pci->dev,
64*1024, 64*1024);
return 0;
}

View File

@ -693,7 +693,8 @@ static int snd_als4000_pcm(struct snd_sb *chip, int device)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_als4000_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_als4000_capture_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
&chip->pci->dev,
64*1024, 64*1024);
chip->pcm = pcm;

View File

@ -1325,8 +1325,8 @@ static int snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi, int device)
/*? do we want to emulate MMAP for non-BBM cards?
Jack doesn't work with ALSAs MMAP emulation - WHY NOT? */
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(asihpi->pci),
64*1024, BUFFER_BYTES_MAX);
&asihpi->pci->dev,
64*1024, BUFFER_BYTES_MAX);
return 0;
}

View File

@ -353,7 +353,7 @@ static int atiixp_build_dma_packets(struct atiixp *chip, struct atiixp_dma *dma,
if (dma->desc_buf.area == NULL) {
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
&chip->pci->dev,
ATI_DESC_LIST_SIZE,
&dma->desc_buf) < 0)
return -ENOMEM;
@ -1284,7 +1284,7 @@ static int snd_atiixp_pcm_new(struct atiixp *chip)
chip->pcmdevs[ATI_PCMDEV_ANALOG] = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
&chip->pci->dev,
64*1024, 128*1024);
err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
@ -1317,7 +1317,7 @@ static int snd_atiixp_pcm_new(struct atiixp *chip)
chip->pcmdevs[ATI_PCMDEV_DIGITAL] = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
&chip->pci->dev,
64*1024, 128*1024);
/* pre-select AC97 SPDIF slots 10/11 */

View File

@ -321,7 +321,7 @@ static int atiixp_build_dma_packets(struct atiixp_modem *chip,
return -ENOMEM;
if (dma->desc_buf.area == NULL) {
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev,
ATI_DESC_LIST_SIZE, &dma->desc_buf) < 0)
return -ENOMEM;
dma->period_bytes = dma->periods = 0; /* clear */
@ -995,7 +995,7 @@ static int snd_atiixp_pcm_new(struct atiixp_modem *chip)
chip->pcmdevs[ATI_PCMDEV_ANALOG] = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
&chip->pci->dev,
64*1024, 128*1024);
return 0;

View File

@ -436,7 +436,6 @@ static const struct snd_pcm_ops snd_vortex_playback_ops = {
.prepare = snd_vortex_pcm_prepare,
.trigger = snd_vortex_pcm_trigger,
.pointer = snd_vortex_pcm_pointer,
.page = snd_pcm_sgbuf_ops_page,
};
/*
@ -638,7 +637,7 @@ static int snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
/* pre-allocation of Scatter-Gather buffers */
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(chip->pci_dev),
&chip->pci_dev,
0x10000, 0x10000);
switch (VORTEX_PCM_TYPE(pcm)) {

View File

@ -613,7 +613,7 @@ static int snd_aw2_new_pcm(struct aw2 *chip)
/* Preallocate continuous pages. */
snd_pcm_lib_preallocate_pages_for_all(pcm_playback_ana,
SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
&chip->pci->dev,
64 * 1024, 64 * 1024);
err = snd_pcm_new(chip->card, "Audiowerk2 digital playback", 1, 1, 0,
@ -645,7 +645,7 @@ static int snd_aw2_new_pcm(struct aw2 *chip)
/* Preallocate continuous pages. */
snd_pcm_lib_preallocate_pages_for_all(pcm_playback_num,
SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
&chip->pci->dev,
64 * 1024, 64 * 1024);
err = snd_pcm_new(chip->card, "Audiowerk2 capture", 2, 0, 1,
@ -678,7 +678,7 @@ static int snd_aw2_new_pcm(struct aw2 *chip)
/* Preallocate continuous pages. */
snd_pcm_lib_preallocate_pages_for_all(pcm_capture,
SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
&chip->pci->dev,
64 * 1024, 64 * 1024);
/* Create control */

View File

@ -2135,8 +2135,8 @@ snd_azf3328_pcm(struct snd_azf3328 *chip)
chip->pcm[AZF_CODEC_CAPTURE] = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
64*1024, 64*1024);
&chip->pci->dev,
64*1024, 64*1024);
err = snd_pcm_new(chip->card, "AZF3328 I2S OUT", AZF_PCMDEV_I2S_OUT,
1, 0, &pcm);
@ -2151,8 +2151,8 @@ snd_azf3328_pcm(struct snd_azf3328 *chip)
chip->pcm[AZF_CODEC_I2S_OUT] = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
64*1024, 64*1024);
&chip->pci->dev,
64*1024, 64*1024);
return 0;
}

View File

@ -217,7 +217,7 @@ static int snd_bt87x_create_risc(struct snd_bt87x *chip, struct snd_pcm_substrea
__le32 *risc;
if (chip->dma_risc.area == NULL) {
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev,
PAGE_ALIGN(MAX_RISC_SIZE), &chip->dma_risc) < 0)
return -ENOMEM;
}
@ -545,7 +545,6 @@ static const struct snd_pcm_ops snd_bt87x_pcm_ops = {
.prepare = snd_bt87x_prepare,
.trigger = snd_bt87x_trigger,
.pointer = snd_bt87x_pointer,
.page = snd_pcm_sgbuf_ops_page,
};
static int snd_bt87x_capture_volume_info(struct snd_kcontrol *kcontrol,
@ -701,7 +700,7 @@ static int snd_bt87x_pcm(struct snd_bt87x *chip, int device, char *name)
strcpy(pcm->name, name);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_bt87x_pcm_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(chip->pci),
&chip->pci->dev,
128 * 1024,
ALIGN(255 * 4092, 1024));
return 0;

View File

@ -1389,7 +1389,7 @@ static int snd_ca0106_pcm(struct snd_ca0106 *emu, int device)
substream;
substream = substream->next) {
snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(emu->pci),
&emu->pci->dev,
64*1024, 64*1024);
}
@ -1397,7 +1397,7 @@ static int snd_ca0106_pcm(struct snd_ca0106 *emu, int device)
substream;
substream = substream->next) {
snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(emu->pci),
&emu->pci->dev,
64*1024, 64*1024);
}
@ -1692,7 +1692,7 @@ static int snd_ca0106_create(int dev, struct snd_card *card,
chip->irq = pci->irq;
/* This stores the periods table. */
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev,
1024, &chip->buffer) < 0) {
snd_ca0106_free(chip);
return -ENOMEM;

View File

@ -1902,7 +1902,7 @@ static int snd_cmipci_pcm_new(struct cmipci *cm, int device)
cm->pcm = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(cm->pci), 64*1024, 128*1024);
&cm->pci->dev, 64*1024, 128*1024);
return 0;
}
@ -1924,7 +1924,7 @@ static int snd_cmipci_pcm2_new(struct cmipci *cm, int device)
cm->pcm2 = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(cm->pci), 64*1024, 128*1024);
&cm->pci->dev, 64*1024, 128*1024);
return 0;
}
@ -1947,7 +1947,7 @@ static int snd_cmipci_pcm_spdif_new(struct cmipci *cm, int device)
cm->pcm_spdif = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(cm->pci), 64*1024, 128*1024);
&cm->pci->dev, 64*1024, 128*1024);
err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
snd_pcm_alt_chmaps, cm->max_channels, 0,

View File

@ -975,7 +975,8 @@ static int snd_cs4281_pcm(struct cs4281 *chip, int device)
chip->pcm = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 512*1024);
&chip->pci->dev,
64*1024, 512*1024);
return 0;
}

View File

@ -1494,7 +1494,7 @@ static int _cs46xx_playback_open_channel (struct snd_pcm_substream *substream,in
cpcm = kzalloc(sizeof(*cpcm), GFP_KERNEL);
if (cpcm == NULL)
return -ENOMEM;
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev,
PAGE_SIZE, &cpcm->hw_buf) < 0) {
kfree(cpcm);
return -ENOMEM;
@ -1582,7 +1582,7 @@ static int snd_cs46xx_capture_open(struct snd_pcm_substream *substream)
{
struct snd_cs46xx *chip = snd_pcm_substream_chip(substream);
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev,
PAGE_SIZE, &chip->capt.hw_buf) < 0)
return -ENOMEM;
chip->capt.substream = substream;
@ -1784,7 +1784,8 @@ int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device)
chip->pcm = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
&chip->pci->dev,
64*1024, 256*1024);
return 0;
}
@ -1809,7 +1810,8 @@ int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device)
chip->pcm_rear = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
&chip->pci->dev,
64*1024, 256*1024);
return 0;
}
@ -1832,7 +1834,8 @@ int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device)
chip->pcm_center_lfe = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
&chip->pci->dev,
64*1024, 256*1024);
return 0;
}
@ -1855,7 +1858,8 @@ int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device)
chip->pcm_iec958 = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
&chip->pci->dev,
64*1024, 256*1024);
return 0;
}

View File

@ -117,7 +117,7 @@ static int cs5535audio_build_dma_packets(struct cs5535audio *cs5535au,
if (dma->desc_buf.area == NULL) {
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(cs5535au->pci),
&cs5535au->pci->dev,
CS5535AUDIO_DESC_LIST_SIZE+1,
&dma->desc_buf) < 0)
return -ENOMEM;
@ -432,8 +432,8 @@ int snd_cs5535audio_pcm(struct cs5535audio *cs5535au)
strcpy(pcm->name, "CS5535 Audio");
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(cs5535au->pci),
64*1024, 128*1024);
&cs5535au->pci->dev,
64*1024, 128*1024);
cs5535au->pcm = pcm;
return 0;

View File

@ -379,7 +379,6 @@ static const struct snd_pcm_ops ct_pcm_playback_ops = {
.prepare = ct_pcm_playback_prepare,
.trigger = ct_pcm_playback_trigger,
.pointer = ct_pcm_playback_pointer,
.page = snd_pcm_sgbuf_ops_page,
};
/* PCM operators for capture */
@ -392,7 +391,6 @@ static const struct snd_pcm_ops ct_pcm_capture_ops = {
.prepare = ct_pcm_capture_prepare,
.trigger = ct_pcm_capture_trigger,
.pointer = ct_pcm_capture_pointer,
.page = snd_pcm_sgbuf_ops_page,
};
static const struct snd_pcm_chmap_elem surround_map[] = {
@ -452,7 +450,8 @@ int ct_alsa_pcm_create(struct ct_atc *atc,
SNDRV_PCM_STREAM_CAPTURE, &ct_pcm_capture_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(atc->pci), 128*1024, 128*1024);
&atc->pci->dev,
128*1024, 128*1024);
chs = 2;
switch (device) {

View File

@ -183,7 +183,7 @@ int ct_vm_create(struct ct_vm **rvm, struct pci_dev *pci)
/* Allocate page table pages */
for (i = 0; i < CT_PTP_NUM; i++) {
err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(pci),
&pci->dev,
PAGE_SIZE, &vm->ptp[i]);
if (err < 0)
break;

View File

@ -324,7 +324,7 @@ static int pcm_open(struct snd_pcm_substream *substream,
/* Finally allocate a page for the scatter-gather list */
if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
&chip->pci->dev,
PAGE_SIZE, &pipe->sgpage)) < 0) {
dev_err(chip->card->dev, "s-g list allocation failed\n");
return err;
@ -824,7 +824,6 @@ static const struct snd_pcm_ops analog_playback_ops = {
.prepare = pcm_prepare,
.trigger = pcm_trigger,
.pointer = pcm_pointer,
.page = snd_pcm_sgbuf_ops_page,
};
static const struct snd_pcm_ops analog_capture_ops = {
.open = pcm_analog_in_open,
@ -835,7 +834,6 @@ static const struct snd_pcm_ops analog_capture_ops = {
.prepare = pcm_prepare,
.trigger = pcm_trigger,
.pointer = pcm_pointer,
.page = snd_pcm_sgbuf_ops_page,
};
#ifdef ECHOCARD_HAS_DIGITAL_IO
#ifndef ECHOCARD_HAS_VMIXER
@ -848,7 +846,6 @@ static const struct snd_pcm_ops digital_playback_ops = {
.prepare = pcm_prepare,
.trigger = pcm_trigger,
.pointer = pcm_pointer,
.page = snd_pcm_sgbuf_ops_page,
};
#endif /* !ECHOCARD_HAS_VMIXER */
static const struct snd_pcm_ops digital_capture_ops = {
@ -860,7 +857,6 @@ static const struct snd_pcm_ops digital_capture_ops = {
.prepare = pcm_prepare,
.trigger = pcm_trigger,
.pointer = pcm_pointer,
.page = snd_pcm_sgbuf_ops_page,
};
#endif /* ECHOCARD_HAS_DIGITAL_IO */
@ -869,7 +865,7 @@ static const struct snd_pcm_ops digital_capture_ops = {
/* Preallocate memory only for the first substream because it's the most
* used one
*/
static int snd_echo_preallocate_pages(struct snd_pcm *pcm, struct device *dev)
static void snd_echo_preallocate_pages(struct snd_pcm *pcm, struct device *dev)
{
struct snd_pcm_substream *ss;
int stream;
@ -880,8 +876,6 @@ static int snd_echo_preallocate_pages(struct snd_pcm *pcm, struct device *dev)
dev,
ss->number ? 0 : 128<<10,
256<<10);
return 0;
}
@ -908,8 +902,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip)
strcpy(pcm->name, chip->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops);
if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
return err;
snd_echo_preallocate_pages(pcm, &chip->pci->dev);
#ifdef ECHOCARD_HAS_DIGITAL_IO
/* PCM#1 Digital inputs, no outputs */
@ -920,8 +913,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip)
chip->digital_pcm = pcm;
strcpy(pcm->name, chip->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops);
if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
return err;
snd_echo_preallocate_pages(pcm, &chip->pci->dev);
#endif /* ECHOCARD_HAS_DIGITAL_IO */
#else /* ECHOCARD_HAS_VMIXER */
@ -941,8 +933,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip)
strcpy(pcm->name, chip->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops);
if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
return err;
snd_echo_preallocate_pages(pcm, &chip->pci->dev);
#ifdef ECHOCARD_HAS_DIGITAL_IO
/* PCM#1 Digital i/o */
@ -955,8 +946,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip)
strcpy(pcm->name, chip->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &digital_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops);
if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
return err;
snd_echo_preallocate_pages(pcm, &chip->pci->dev);
#endif /* ECHOCARD_HAS_DIGITAL_IO */
#endif /* ECHOCARD_HAS_VMIXER */
@ -1958,7 +1948,7 @@ static int snd_echo_create(struct snd_card *card,
/* Create the DSP comm page - this is the area of memory used for most
of the communication with the DSP, which accesses it via bus mastering */
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev,
sizeof(struct comm_page),
&chip->commpage_dma_buf) < 0) {
dev_err(chip->card->dev, "cannot allocate the comm page\n");

View File

@ -124,8 +124,9 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
goto error;
/* This stores the periods table. */
if (emu->card_capabilities->ca0151_chip) { /* P16V */
if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
1024, &emu->p16v_buffer)) < 0)
err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev,
1024, &emu->p16v_buffer);
if (err < 0)
goto error;
}

View File

@ -877,7 +877,7 @@ static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device)
emu->pcm = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(emu->pci),
&emu->pci->dev,
32*1024, 32*1024);
return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2,
@ -936,8 +936,8 @@ static int snd_emu10k1x_create(struct snd_card *card,
}
chip->irq = pci->irq;
if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
4 * 1024, &chip->dma_buffer) < 0) {
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev,
4 * 1024, &chip->dma_buffer) < 0) {
snd_emu10k1x_free(chip);
return -ENOMEM;
}

View File

@ -2464,7 +2464,7 @@ int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size)
}
if (size > 0) {
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci),
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &emu->pci->dev,
size * 2, &emu->fx8010.etram_pages) < 0)
return -ENOMEM;
memset(emu->fx8010.etram_pages.area, 0, size * 2);

View File

@ -1366,7 +1366,6 @@ static const struct snd_pcm_ops snd_emu10k1_playback_ops = {
.prepare = snd_emu10k1_playback_prepare,
.trigger = snd_emu10k1_playback_trigger,
.pointer = snd_emu10k1_playback_pointer,
.page = snd_pcm_sgbuf_ops_page,
};
static const struct snd_pcm_ops snd_emu10k1_capture_ops = {
@ -1390,7 +1389,6 @@ static const struct snd_pcm_ops snd_emu10k1_efx_playback_ops = {
.prepare = snd_emu10k1_efx_playback_prepare,
.trigger = snd_emu10k1_efx_playback_trigger,
.pointer = snd_emu10k1_efx_playback_pointer,
.page = snd_pcm_sgbuf_ops_page,
};
int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device)
@ -1414,12 +1412,12 @@ int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device)
for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)
snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(emu->pci),
&emu->pci->dev,
64*1024, 64*1024);
for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next)
snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(emu->pci),
&emu->pci->dev,
64*1024, 64*1024);
return 0;
@ -1445,7 +1443,7 @@ int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device)
for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)
snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(emu->pci),
&emu->pci->dev,
64*1024, 64*1024);
return 0;
@ -1480,7 +1478,7 @@ int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device)
emu->pcm_mic = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(emu->pci),
&emu->pci->dev,
64*1024, 64*1024);
return 0;
@ -1855,7 +1853,7 @@ int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device)
return err;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(emu->pci),
&emu->pci->dev,
64*1024, 64*1024);
return 0;

View File

@ -387,7 +387,7 @@ int snd_emu10k1_alloc_pages_maybe_wider(struct snd_emu10k1 *emu, size_t size,
}
return snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(emu->pci), size, dmab);
&emu->pci->dev, size, dmab);
}
/*
@ -477,7 +477,7 @@ static void __synth_free_pages(struct snd_emu10k1 *emu, int first_page,
int page;
dmab.dev.type = SNDRV_DMA_TYPE_DEV;
dmab.dev.dev = snd_dma_pci_data(emu->pci);
dmab.dev.dev = &emu->pci->dev;
for (page = first_page; page <= last_page; page++) {
if (emu->page_ptr_table[page] == NULL)

View File

@ -643,7 +643,7 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device)
substream;
substream = substream->next) {
snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(emu->pci),
&emu->pci->dev,
(65536 - 64) * 8,
(65536 - 64) * 8);
/*
@ -656,7 +656,7 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device)
substream;
substream = substream->next) {
snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(emu->pci),
&emu->pci->dev,
65536 - 64, 65536 - 64);
/*
dev_dbg(emu->card->dev,

View File

@ -1275,7 +1275,8 @@ static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device)
ensoniq->pcm1 = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(ensoniq->pci), 64*1024, 128*1024);
&ensoniq->pci->dev,
64*1024, 128*1024);
#ifdef CHIP1370
err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
@ -1307,7 +1308,8 @@ static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device)
ensoniq->pcm2 = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(ensoniq->pci), 64*1024, 128*1024);
&ensoniq->pci->dev,
64*1024, 128*1024);
#ifdef CHIP1370
err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
@ -2095,7 +2097,7 @@ static int snd_ensoniq_create(struct snd_card *card,
}
ensoniq->irq = pci->irq;
#ifdef CHIP1370
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev,
16, &ensoniq->dma_bug) < 0) {
dev_err(card->dev, "unable to allocate space for phantom area - dma_bug\n");
snd_ensoniq_free(ensoniq);

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