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

Pull sound updates from Takashi Iwai:
 "The most significant changes at this cycle are the Sound Open Firmware
  support from Intel for the common DSP framework along with its support
  for Intel platforms. It's a door opened to a real "free" firmware (in
  the sense of FOSS), and other parties show interests in it.

  In addition to SOF, we've got a bunch of updates and fixes as usual.
  Some highlights are below.

  ALSA core:
   - Cleanups and fixes in ALSA timer code to cover some races spotted
     by syzkaller
   - Cleanups and fixes in ALSA sequencer code to cover some races,
     again unsurprisingly, spotted by syzkaller
   - Optimize the common page allocation helper with alloc_pages_exact()

  ASoC:
   - Add SOF core support, as well as Intel SOF platform support
   - Generic card driver improvements: support for MCLK/sample rate
     ratio and pin switches
   - A big set of improvements to TLV320AIC32x4 drivers
   - New drivers for Freescale audio mixers, several Intel machines,
     several Mediatek machines, Meson G12A, Spreadtrum compressed audio
     and DMA devices

  HD-audio:
   - A few Realtek codec fixes for reducing pop noises
   - Quirks for Chromebooks
   - Workaround for faulty connection report on AMD/Nvidia HDMI

  Others:
   - A quirk for Focusrite Scarlett Solo USB-audio
   - Add support for MOTU 8pre FireWire
   - 24bit sample format support in aloop
   - GUS patch format support (finally, over a decade) in native emux
     synth code"

* tag 'sound-5.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (375 commits)
  ASoC: SOF: Fix unused variable warnings
  ALSA: line6: toneport: Fix broken usage of timer for delayed execution
  ALSA: aica: Fix a long-time build breakage
  ALSA: hda/realtek - Support low power consumption for ALC256
  ASoC: stm32: i2s: update pcm hardware constraints
  ASoC: codec: hdac_hdmi: no checking monitor in hw_params
  ASoC: mediatek: mt6358: save PGA for mixer control
  ASoC: mediatek: mt6358: save output volume for mixer controls
  ASoC: mediatek: mt6358: initialize setting when ramping volume
  ASoC: SOF: core: fix undefined nocodec reference
  ASoC: SOF: xtensa: fix undefined references
  ASoC: SOF: Propagate sof_get_ctrl_copy_params() error properly
  ALSA: hdea/realtek - Headset fixup for System76 Gazelle (gaze14)
  ALSA: hda/intel: add CometLake PCI IDs
  ALSA: hda/realtek - Support low power consumption for ALC295
  ASoC: rockchip: Fix an uninitialized variable compile warning
  ASoC: SOF: Fix a compile warning with CONFIG_PCI=n
  ASoC: da7219: Fix a compile warning at CONFIG_COMMON_CLK=n
  ASoC: sound/soc/sof/: fix kconfig dependency warning
  ASoC: stm32: spdifrx: change trace level on iec control
  ...
这个提交包含在:
Linus Torvalds
2019-05-09 08:26:55 -07:00
当前提交 e57ccca1ba
修改 321 个文件,包含 30105 行新增3213 行删除

查看文件

@@ -49,8 +49,7 @@ static const struct file_operations snd_shutdown_f_ops;
/* locked for registering/using */
static DECLARE_BITMAP(snd_cards_lock, SNDRV_CARDS);
struct snd_card *snd_cards[SNDRV_CARDS];
EXPORT_SYMBOL(snd_cards);
static struct snd_card *snd_cards[SNDRV_CARDS];
static DEFINE_MUTEX(snd_card_mutex);
@@ -268,6 +267,26 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
}
EXPORT_SYMBOL(snd_card_new);
/**
* snd_card_ref - Get the card object from the index
* @idx: the card index
*
* Returns a card object corresponding to the given index or NULL if not found.
* Release the object via snd_card_unref().
*/
struct snd_card *snd_card_ref(int idx)
{
struct snd_card *card;
mutex_lock(&snd_card_mutex);
card = snd_cards[idx];
if (card)
get_device(&card->card_dev);
mutex_unlock(&snd_card_mutex);
return card;
}
EXPORT_SYMBOL_GPL(snd_card_ref);
/* return non-zero if a card is already locked */
int snd_card_locked(int card)
{

查看文件

@@ -30,53 +30,6 @@
#endif
#include <sound/memalloc.h>
/*
*
* Generic memory allocators
*
*/
/**
* snd_malloc_pages - allocate pages with the given size
* @size: the size to allocate in bytes
* @gfp_flags: the allocation conditions, GFP_XXX
*
* Allocates the physically contiguous pages with the given size.
*
* Return: The pointer of the buffer, or %NULL if no enough memory.
*/
void *snd_malloc_pages(size_t size, gfp_t gfp_flags)
{
int pg;
if (WARN_ON(!size))
return NULL;
if (WARN_ON(!gfp_flags))
return NULL;
gfp_flags |= __GFP_COMP; /* compound page lets parts be mapped */
pg = get_order(size);
return (void *) __get_free_pages(gfp_flags, pg);
}
EXPORT_SYMBOL(snd_malloc_pages);
/**
* snd_free_pages - release the pages
* @ptr: the buffer pointer to release
* @size: the allocated buffer size
*
* Releases the buffer allocated via snd_malloc_pages().
*/
void snd_free_pages(void *ptr, size_t size)
{
int pg;
if (ptr == NULL)
return;
pg = get_order(size);
free_pages((unsigned long) ptr, pg);
}
EXPORT_SYMBOL(snd_free_pages);
/*
*
* Bus-specific memory allocators
@@ -190,8 +143,8 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
dmab->bytes = 0;
switch (type) {
case SNDRV_DMA_TYPE_CONTINUOUS:
dmab->area = snd_malloc_pages(size,
(__force gfp_t)(unsigned long)device);
dmab->area = alloc_pages_exact(size,
(__force gfp_t)(unsigned long)device);
dmab->addr = 0;
break;
#ifdef CONFIG_HAS_DMA
@@ -275,7 +228,7 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
{
switch (dmab->dev.type) {
case SNDRV_DMA_TYPE_CONTINUOUS:
snd_free_pages(dmab->area, dmab->bytes);
free_pages_exact(dmab->area, dmab->bytes);
break;
#ifdef CONFIG_HAS_DMA
#ifdef CONFIG_GENERIC_ALLOCATOR

查看文件

@@ -1403,24 +1403,32 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
static int __init alsa_mixer_oss_init(void)
{
struct snd_card *card;
int idx;
snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler;
for (idx = 0; idx < SNDRV_CARDS; idx++) {
if (snd_cards[idx])
snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_REGISTER);
card = snd_card_ref(idx);
if (card) {
snd_mixer_oss_notify_handler(card, SND_MIXER_OSS_NOTIFY_REGISTER);
snd_card_unref(card);
}
}
return 0;
}
static void __exit alsa_mixer_oss_exit(void)
{
struct snd_card *card;
int idx;
snd_mixer_oss_notify_callback = NULL;
for (idx = 0; idx < SNDRV_CARDS; idx++) {
if (snd_cards[idx])
snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_FREE);
card = snd_card_ref(idx);
if (card) {
snd_mixer_oss_notify_handler(card, SND_MIXER_OSS_NOTIFY_FREE);
snd_card_unref(card);
}
}
}

查看文件

@@ -959,22 +959,22 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
return -ENOMEM;
size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status));
runtime->status = snd_malloc_pages(size, GFP_KERNEL);
runtime->status = alloc_pages_exact(size, GFP_KERNEL);
if (runtime->status == NULL) {
kfree(runtime);
return -ENOMEM;
}
memset((void*)runtime->status, 0, size);
memset(runtime->status, 0, size);
size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control));
runtime->control = snd_malloc_pages(size, GFP_KERNEL);
runtime->control = alloc_pages_exact(size, GFP_KERNEL);
if (runtime->control == NULL) {
snd_free_pages((void*)runtime->status,
free_pages_exact(runtime->status,
PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));
kfree(runtime);
return -ENOMEM;
}
memset((void*)runtime->control, 0, size);
memset(runtime->control, 0, size);
init_waitqueue_head(&runtime->sleep);
init_waitqueue_head(&runtime->tsleep);
@@ -1000,9 +1000,9 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
runtime = substream->runtime;
if (runtime->private_free != NULL)
runtime->private_free(runtime);
snd_free_pages((void*)runtime->status,
free_pages_exact(runtime->status,
PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));
snd_free_pages((void*)runtime->control,
free_pages_exact(runtime->control,
PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
kfree(runtime->hw_constraints.rules);
/* Avoid concurrent access to runtime via PCM timer interface */

查看文件

@@ -30,6 +30,7 @@
#include <sound/rawmidi.h>
#include <sound/seq_kernel.h>
#include <sound/info.h>
#include "../seq_clientmgr.h"
/* max. applications */
#define SNDRV_SEQ_OSS_MAX_CLIENTS 16
@@ -150,11 +151,16 @@ snd_seq_oss_dispatch(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int a
return snd_seq_kernel_client_dispatch(dp->cseq, ev, atomic, hop);
}
/* ioctl */
/* ioctl for writeq */
static inline int
snd_seq_oss_control(struct seq_oss_devinfo *dp, unsigned int type, void *arg)
{
return snd_seq_kernel_client_ctl(dp->cseq, type, arg);
int err;
snd_seq_client_ioctl_lock(dp->cseq);
err = snd_seq_kernel_client_ctl(dp->cseq, type, arg);
snd_seq_client_ioctl_unlock(dp->cseq);
return err;
}
/* fill the addresses in header */

查看文件

@@ -180,14 +180,11 @@ insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt)
return 0; /* invalid event - no need to insert queue */
event.time.tick = snd_seq_oss_timer_cur_tick(dp->timer);
if (dp->timer->realtime || !dp->timer->running) {
if (dp->timer->realtime || !dp->timer->running)
snd_seq_oss_dispatch(dp, &event, 0, 0);
} else {
if (is_nonblock_mode(dp->file_mode))
rc = snd_seq_kernel_client_enqueue(dp->cseq, &event, 0, 0);
else
rc = snd_seq_kernel_client_enqueue_blocking(dp->cseq, &event, opt, 0, 0);
}
else
rc = snd_seq_kernel_client_enqueue(dp->cseq, &event, opt,
!is_nonblock_mode(dp->file_mode));
return rc;
}

查看文件

@@ -116,7 +116,7 @@ snd_seq_oss_writeq_sync(struct seq_oss_writeq *q)
rec->t.code = SEQ_SYNCTIMER;
rec->t.time = time;
q->sync_event_put = 1;
snd_seq_kernel_client_enqueue_blocking(dp->cseq, &ev, NULL, 0, 0);
snd_seq_kernel_client_enqueue(dp->cseq, &ev, NULL, true);
}
wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);

查看文件

@@ -179,6 +179,41 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
return client;
}
/* Take refcount and perform ioctl_mutex lock on the given client;
* used only for OSS sequencer
* Unlock via snd_seq_client_ioctl_unlock() below
*/
bool snd_seq_client_ioctl_lock(int clientid)
{
struct snd_seq_client *client;
client = snd_seq_client_use_ptr(clientid);
if (!client)
return false;
mutex_lock(&client->ioctl_mutex);
/* The client isn't unrefed here; see snd_seq_client_ioctl_unlock() */
return true;
}
EXPORT_SYMBOL_GPL(snd_seq_client_ioctl_lock);
/* Unlock and unref the given client; for OSS sequencer use only */
void snd_seq_client_ioctl_unlock(int clientid)
{
struct snd_seq_client *client;
client = snd_seq_client_use_ptr(clientid);
if (WARN_ON(!client))
return;
mutex_unlock(&client->ioctl_mutex);
/* The doubly unrefs below are intentional; the first one releases the
* leftover from snd_seq_client_ioctl_lock() above, and the second one
* is for releasing snd_seq_client_use_ptr() in this function
*/
snd_seq_client_unlock(client);
snd_seq_client_unlock(client);
}
EXPORT_SYMBOL_GPL(snd_seq_client_ioctl_unlock);
static void usage_alloc(struct snd_seq_usage *res, int num)
{
res->cur += num;
@@ -203,7 +238,6 @@ int __init client_init_data(void)
static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
{
unsigned long flags;
int c;
struct snd_seq_client *client;
@@ -224,7 +258,7 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
mutex_init(&client->ioctl_mutex);
/* find free slot in the client table */
spin_lock_irqsave(&clients_lock, flags);
spin_lock_irq(&clients_lock);
if (client_index < 0) {
for (c = SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN;
c < SNDRV_SEQ_MAX_CLIENTS;
@@ -232,17 +266,17 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
if (clienttab[c] || clienttablock[c])
continue;
clienttab[client->number = c] = client;
spin_unlock_irqrestore(&clients_lock, flags);
spin_unlock_irq(&clients_lock);
return client;
}
} else {
if (clienttab[client_index] == NULL && !clienttablock[client_index]) {
clienttab[client->number = client_index] = client;
spin_unlock_irqrestore(&clients_lock, flags);
spin_unlock_irq(&clients_lock);
return client;
}
}
spin_unlock_irqrestore(&clients_lock, flags);
spin_unlock_irq(&clients_lock);
snd_seq_pool_delete(&client->pool);
kfree(client);
return NULL; /* no free slot found or busy, return failure code */
@@ -251,23 +285,21 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
static int seq_free_client1(struct snd_seq_client *client)
{
unsigned long flags;
if (!client)
return 0;
spin_lock_irqsave(&clients_lock, flags);
spin_lock_irq(&clients_lock);
clienttablock[client->number] = 1;
clienttab[client->number] = NULL;
spin_unlock_irqrestore(&clients_lock, flags);
spin_unlock_irq(&clients_lock);
snd_seq_delete_all_ports(client);
snd_seq_queue_client_leave(client->number);
snd_use_lock_sync(&client->use_lock);
snd_seq_queue_client_termination(client->number);
if (client->pool)
snd_seq_pool_delete(&client->pool);
spin_lock_irqsave(&clients_lock, flags);
spin_lock_irq(&clients_lock);
clienttablock[client->number] = 0;
spin_unlock_irqrestore(&clients_lock, flags);
spin_unlock_irq(&clients_lock);
return 0;
}
@@ -1900,20 +1932,14 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client,
int result;
struct snd_seq_client *sender = NULL;
struct snd_seq_client_port *sport = NULL;
struct snd_seq_subscribers *p;
result = -EINVAL;
if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL)
goto __end;
if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL)
goto __end;
p = snd_seq_port_get_subscription(&sport->c_src, &subs->dest);
if (p) {
result = 0;
*subs = p->info;
} else
result = -ENOENT;
result = snd_seq_port_get_subscription(&sport->c_src, &subs->dest,
subs);
__end:
if (sport)
snd_seq_port_unlock(sport);
@@ -2227,12 +2253,13 @@ int snd_seq_delete_kernel_client(int client)
}
EXPORT_SYMBOL(snd_seq_delete_kernel_client);
/* skeleton to enqueue event, called from snd_seq_kernel_client_enqueue
* and snd_seq_kernel_client_enqueue_blocking
/*
* exported, called by kernel clients to enqueue events (w/o blocking)
*
* RETURN VALUE: zero if succeed, negative if error
*/
static int kernel_client_enqueue(int client, struct snd_seq_event *ev,
struct file *file, int blocking,
int atomic, int hop)
int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev,
struct file *file, bool blocking)
{
struct snd_seq_client *cptr;
int result;
@@ -2255,41 +2282,21 @@ static int kernel_client_enqueue(int client, struct snd_seq_event *ev,
if (cptr == NULL)
return -EINVAL;
if (! cptr->accept_output)
if (!cptr->accept_output) {
result = -EPERM;
else /* send it */
} else { /* send it */
mutex_lock(&cptr->ioctl_mutex);
result = snd_seq_client_enqueue_event(cptr, ev, file, blocking,
atomic, hop, NULL);
false, 0,
&cptr->ioctl_mutex);
mutex_unlock(&cptr->ioctl_mutex);
}
snd_seq_client_unlock(cptr);
return result;
}
/*
* exported, called by kernel clients to enqueue events (w/o blocking)
*
* RETURN VALUE: zero if succeed, negative if error
*/
int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event * ev,
int atomic, int hop)
{
return kernel_client_enqueue(client, ev, NULL, 0, atomic, hop);
}
EXPORT_SYMBOL(snd_seq_kernel_client_enqueue);
/*
* exported, called by kernel clients to enqueue events (with blocking)
*
* RETURN VALUE: zero if succeed, negative if error
*/
int snd_seq_kernel_client_enqueue_blocking(int client, struct snd_seq_event * ev,
struct file *file,
int atomic, int hop)
{
return kernel_client_enqueue(client, ev, file, 1, atomic, hop);
}
EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking);
/*
* exported, called by kernel clients to dispatch events directly to other
* clients, bypassing the queues. Event time-stamp will be updated.

查看文件

@@ -93,14 +93,14 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid);
/* dispatch event to client(s) */
int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop);
/* exported to other modules */
int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev, int atomic, int hop);
int snd_seq_kernel_client_enqueue_blocking(int client, struct snd_seq_event * ev,
struct file *file, int atomic, int hop);
int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table *wait);
int snd_seq_client_notify_subscription(int client, int port,
struct snd_seq_port_subscribe *info, int evtype);
/* only for OSS sequencer */
bool snd_seq_client_ioctl_lock(int clientid);
void snd_seq_client_ioctl_unlock(int clientid);
extern int seq_client_load[15];
#endif

查看文件

@@ -98,18 +98,17 @@ static struct snd_seq_event_cell *fifo_cell_out(struct snd_seq_fifo *f);
void snd_seq_fifo_clear(struct snd_seq_fifo *f)
{
struct snd_seq_event_cell *cell;
unsigned long flags;
/* clear overflow flag */
atomic_set(&f->overflow, 0);
snd_use_lock_sync(&f->use_lock);
spin_lock_irqsave(&f->lock, flags);
spin_lock_irq(&f->lock);
/* drain the fifo */
while ((cell = fifo_cell_out(f)) != NULL) {
snd_seq_cell_free(cell);
}
spin_unlock_irqrestore(&f->lock, flags);
spin_unlock_irq(&f->lock);
}
@@ -195,9 +194,9 @@ int snd_seq_fifo_cell_out(struct snd_seq_fifo *f,
}
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&f->input_sleep, &wait);
spin_unlock_irq(&f->lock);
spin_unlock_irqrestore(&f->lock, flags);
schedule();
spin_lock_irq(&f->lock);
spin_lock_irqsave(&f->lock, flags);
remove_wait_queue(&f->input_sleep, &wait);
if (signal_pending(current)) {
spin_unlock_irqrestore(&f->lock, flags);
@@ -239,7 +238,6 @@ int snd_seq_fifo_poll_wait(struct snd_seq_fifo *f, struct file *file,
/* change the size of pool; all old events are removed */
int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
{
unsigned long flags;
struct snd_seq_pool *newpool, *oldpool;
struct snd_seq_event_cell *cell, *next, *oldhead;
@@ -255,7 +253,7 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
return -ENOMEM;
}
spin_lock_irqsave(&f->lock, flags);
spin_lock_irq(&f->lock);
/* remember old pool */
oldpool = f->pool;
oldhead = f->head;
@@ -265,7 +263,7 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
f->tail = NULL;
f->cells = 0;
/* NOTE: overflow flag is not cleared */
spin_unlock_irqrestore(&f->lock, flags);
spin_unlock_irq(&f->lock);
/* close the old pool and wait until all users are gone */
snd_seq_pool_mark_closing(oldpool);

查看文件

@@ -24,7 +24,7 @@
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/sched/signal.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <sound/core.h>
#include <sound/seq_kernel.h>
@@ -244,13 +244,13 @@ static int snd_seq_cell_alloc(struct snd_seq_pool *pool,
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&pool->output_sleep, &wait);
spin_unlock_irq(&pool->lock);
spin_unlock_irqrestore(&pool->lock, flags);
if (mutexp)
mutex_unlock(mutexp);
schedule();
if (mutexp)
mutex_lock(mutexp);
spin_lock_irq(&pool->lock);
spin_lock_irqsave(&pool->lock, flags);
remove_wait_queue(&pool->output_sleep, &wait);
/* interrupted? */
if (signal_pending(current)) {
@@ -384,21 +384,20 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
{
int cell;
struct snd_seq_event_cell *cellptr;
unsigned long flags;
if (snd_BUG_ON(!pool))
return -EINVAL;
cellptr = vmalloc(array_size(sizeof(struct snd_seq_event_cell),
pool->size));
cellptr = kvmalloc_array(sizeof(struct snd_seq_event_cell), pool->size,
GFP_KERNEL);
if (!cellptr)
return -ENOMEM;
/* add new cells to the free cell list */
spin_lock_irqsave(&pool->lock, flags);
spin_lock_irq(&pool->lock);
if (pool->ptr) {
spin_unlock_irqrestore(&pool->lock, flags);
vfree(cellptr);
spin_unlock_irq(&pool->lock);
kvfree(cellptr);
return 0;
}
@@ -416,7 +415,7 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
/* init statistics */
pool->max_used = 0;
pool->total_elements = pool->size;
spin_unlock_irqrestore(&pool->lock, flags);
spin_unlock_irq(&pool->lock);
return 0;
}
@@ -435,7 +434,6 @@ void snd_seq_pool_mark_closing(struct snd_seq_pool *pool)
/* remove events */
int snd_seq_pool_done(struct snd_seq_pool *pool)
{
unsigned long flags;
struct snd_seq_event_cell *ptr;
if (snd_BUG_ON(!pool))
@@ -449,18 +447,18 @@ int snd_seq_pool_done(struct snd_seq_pool *pool)
schedule_timeout_uninterruptible(1);
/* release all resources */
spin_lock_irqsave(&pool->lock, flags);
spin_lock_irq(&pool->lock);
ptr = pool->ptr;
pool->ptr = NULL;
pool->free = NULL;
pool->total_elements = 0;
spin_unlock_irqrestore(&pool->lock, flags);
spin_unlock_irq(&pool->lock);
vfree(ptr);
kvfree(ptr);
spin_lock_irqsave(&pool->lock, flags);
spin_lock_irq(&pool->lock);
pool->closing = 0;
spin_unlock_irqrestore(&pool->lock, flags);
spin_unlock_irq(&pool->lock);
return 0;
}

查看文件

@@ -128,7 +128,6 @@ static void port_subs_info_init(struct snd_seq_port_subs_info *grp)
struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
int port)
{
unsigned long flags;
struct snd_seq_client_port *new_port, *p;
int num = -1;
@@ -157,7 +156,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
num = port >= 0 ? port : 0;
mutex_lock(&client->ports_mutex);
write_lock_irqsave(&client->ports_lock, flags);
write_lock_irq(&client->ports_lock);
list_for_each_entry(p, &client->ports_list_head, list) {
if (p->addr.port > num)
break;
@@ -169,7 +168,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
client->num_ports++;
new_port->addr.port = num; /* store the port number in the port */
sprintf(new_port->name, "port-%d", num);
write_unlock_irqrestore(&client->ports_lock, flags);
write_unlock_irq(&client->ports_lock);
mutex_unlock(&client->ports_mutex);
return new_port;
@@ -283,11 +282,10 @@ static int port_delete(struct snd_seq_client *client,
/* delete a port with the given port id */
int snd_seq_delete_port(struct snd_seq_client *client, int port)
{
unsigned long flags;
struct snd_seq_client_port *found = NULL, *p;
mutex_lock(&client->ports_mutex);
write_lock_irqsave(&client->ports_lock, flags);
write_lock_irq(&client->ports_lock);
list_for_each_entry(p, &client->ports_list_head, list) {
if (p->addr.port == port) {
/* ok found. delete from the list at first */
@@ -297,7 +295,7 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port)
break;
}
}
write_unlock_irqrestore(&client->ports_lock, flags);
write_unlock_irq(&client->ports_lock);
mutex_unlock(&client->ports_mutex);
if (found)
return port_delete(client, found);
@@ -308,7 +306,6 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port)
/* delete the all ports belonging to the given client */
int snd_seq_delete_all_ports(struct snd_seq_client *client)
{
unsigned long flags;
struct list_head deleted_list;
struct snd_seq_client_port *port, *tmp;
@@ -316,7 +313,7 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
* clear the port list in the client data.
*/
mutex_lock(&client->ports_mutex);
write_lock_irqsave(&client->ports_lock, flags);
write_lock_irq(&client->ports_lock);
if (! list_empty(&client->ports_list_head)) {
list_add(&deleted_list, &client->ports_list_head);
list_del_init(&client->ports_list_head);
@@ -324,7 +321,7 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
INIT_LIST_HEAD(&deleted_list);
}
client->num_ports = 0;
write_unlock_irqrestore(&client->ports_lock, flags);
write_unlock_irq(&client->ports_lock);
/* remove each port in deleted_list */
list_for_each_entry_safe(port, tmp, &deleted_list, list) {
@@ -550,10 +547,10 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client,
list_del_init(list);
grp->exclusive = 0;
write_unlock_irq(&grp->list_lock);
up_write(&grp->list_mutex);
if (!empty)
unsubscribe_port(client, port, grp, &subs->info, ack);
up_write(&grp->list_mutex);
}
/* connect two ports */
@@ -635,20 +632,23 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
/* get matched subscriber */
struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
struct snd_seq_addr *dest_addr)
int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
struct snd_seq_addr *dest_addr,
struct snd_seq_port_subscribe *subs)
{
struct snd_seq_subscribers *s, *found = NULL;
struct snd_seq_subscribers *s;
int err = -ENOENT;
down_read(&src_grp->list_mutex);
list_for_each_entry(s, &src_grp->list_head, src_list) {
if (addr_match(dest_addr, &s->info.dest)) {
found = s;
*subs = s->info;
err = 0;
break;
}
}
up_read(&src_grp->list_mutex);
return found;
return err;
}
/*

查看文件

@@ -135,7 +135,8 @@ int snd_seq_port_subscribe(struct snd_seq_client_port *port,
struct snd_seq_port_subscribe *info);
/* get matched subscriber */
struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
struct snd_seq_addr *dest_addr);
int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
struct snd_seq_addr *dest_addr,
struct snd_seq_port_subscribe *subs);
#endif

查看文件

@@ -134,8 +134,11 @@ static struct snd_minor *autoload_device(unsigned int minor)
if (dev == SNDRV_MINOR_CONTROL) {
/* /dev/aloadC? */
int card = SNDRV_MINOR_CARD(minor);
if (snd_cards[card] == NULL)
struct snd_card *ref = snd_card_ref(card);
if (!ref)
snd_request_card(card);
else
snd_card_unref(ref);
} else if (dev == SNDRV_MINOR_GLOBAL) {
/* /dev/aloadSEQ */
snd_request_other(minor);

查看文件

@@ -38,6 +38,7 @@
/* internal flags */
#define SNDRV_TIMER_IFLG_PAUSED 0x00010000
#define SNDRV_TIMER_IFLG_DEAD 0x00020000
#if IS_ENABLED(CONFIG_SND_HRTIMER)
#define DEFAULT_TIMER_LIMIT 4
@@ -254,19 +255,20 @@ int snd_timer_open(struct snd_timer_instance **ti,
struct snd_timer_instance *timeri = NULL;
int err;
mutex_lock(&register_mutex);
if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) {
/* open a slave instance */
if (tid->dev_sclass <= SNDRV_TIMER_SCLASS_NONE ||
tid->dev_sclass > SNDRV_TIMER_SCLASS_OSS_SEQUENCER) {
pr_debug("ALSA: timer: invalid slave class %i\n",
tid->dev_sclass);
return -EINVAL;
err = -EINVAL;
goto unlock;
}
mutex_lock(&register_mutex);
timeri = snd_timer_instance_new(owner, NULL);
if (!timeri) {
mutex_unlock(&register_mutex);
return -ENOMEM;
err = -ENOMEM;
goto unlock;
}
timeri->slave_class = tid->dev_sclass;
timeri->slave_id = tid->device;
@@ -277,13 +279,10 @@ int snd_timer_open(struct snd_timer_instance **ti,
snd_timer_close_locked(timeri);
timeri = NULL;
}
mutex_unlock(&register_mutex);
*ti = timeri;
return err;
goto unlock;
}
/* open a master instance */
mutex_lock(&register_mutex);
timer = snd_timer_find(tid);
#ifdef CONFIG_MODULES
if (!timer) {
@@ -294,25 +293,26 @@ int snd_timer_open(struct snd_timer_instance **ti,
}
#endif
if (!timer) {
mutex_unlock(&register_mutex);
return -ENODEV;
err = -ENODEV;
goto unlock;
}
if (!list_empty(&timer->open_list_head)) {
timeri = list_entry(timer->open_list_head.next,
struct snd_timer_instance, open_list);
if (timeri->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) {
mutex_unlock(&register_mutex);
return -EBUSY;
err = -EBUSY;
timeri = NULL;
goto unlock;
}
}
if (timer->num_instances >= timer->max_instances) {
mutex_unlock(&register_mutex);
return -EBUSY;
err = -EBUSY;
goto unlock;
}
timeri = snd_timer_instance_new(owner, timer);
if (!timeri) {
mutex_unlock(&register_mutex);
return -ENOMEM;
err = -ENOMEM;
goto unlock;
}
/* take a card refcount for safe disconnection */
if (timer->card)
@@ -321,16 +321,16 @@ int snd_timer_open(struct snd_timer_instance **ti,
timeri->slave_id = slave_id;
if (list_empty(&timer->open_list_head) && timer->hw.open) {
int err = timer->hw.open(timer);
err = timer->hw.open(timer);
if (err) {
kfree(timeri->owner);
kfree(timeri);
timeri = NULL;
if (timer->card)
put_device(&timer->card->card_dev);
module_put(timer->module);
mutex_unlock(&register_mutex);
return err;
goto unlock;
}
}
@@ -341,6 +341,8 @@ int snd_timer_open(struct snd_timer_instance **ti,
snd_timer_close_locked(timeri);
timeri = NULL;
}
unlock:
mutex_unlock(&register_mutex);
*ti = timeri;
return err;
@@ -353,15 +355,20 @@ EXPORT_SYMBOL(snd_timer_open);
*/
static int snd_timer_close_locked(struct snd_timer_instance *timeri)
{
struct snd_timer *timer = NULL;
struct snd_timer *timer = timeri->timer;
struct snd_timer_instance *slave, *tmp;
if (timer) {
spin_lock_irq(&timer->lock);
timeri->flags |= SNDRV_TIMER_IFLG_DEAD;
spin_unlock_irq(&timer->lock);
}
list_del(&timeri->open_list);
/* force to stop the timer */
snd_timer_stop(timeri);
timer = timeri->timer;
if (timer) {
timer->num_instances--;
/* wait, until the active callback is finished */
@@ -497,6 +504,10 @@ static int snd_timer_start1(struct snd_timer_instance *timeri,
return -EINVAL;
spin_lock_irqsave(&timer->lock, flags);
if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) {
result = -EINVAL;
goto unlock;
}
if (timer->card && timer->card->shutdown) {
result = -ENODEV;
goto unlock;
@@ -541,11 +552,16 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri,
bool start)
{
unsigned long flags;
int err;
spin_lock_irqsave(&slave_active_lock, flags);
if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) {
err = -EINVAL;
goto unlock;
}
if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) {
spin_unlock_irqrestore(&slave_active_lock, flags);
return -EBUSY;
err = -EBUSY;
goto unlock;
}
timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
if (timeri->master && timeri->timer) {
@@ -556,8 +572,10 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri,
SNDRV_TIMER_EVENT_CONTINUE);
spin_unlock(&timeri->timer->lock);
}
err = 1; /* delayed start */
unlock:
spin_unlock_irqrestore(&slave_active_lock, flags);
return 1; /* delayed start */
return err;
}
/* stop/pause a master timer */
@@ -720,6 +738,46 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l
timer->sticks = ticks;
}
/* call callbacks in timer ack list */
static void snd_timer_process_callbacks(struct snd_timer *timer,
struct list_head *head)
{
struct snd_timer_instance *ti;
unsigned long resolution, ticks;
while (!list_empty(head)) {
ti = list_first_entry(head, struct snd_timer_instance,
ack_list);
/* remove from ack_list and make empty */
list_del_init(&ti->ack_list);
if (!(ti->flags & SNDRV_TIMER_IFLG_DEAD)) {
ticks = ti->pticks;
ti->pticks = 0;
resolution = ti->resolution;
ti->flags |= SNDRV_TIMER_IFLG_CALLBACK;
spin_unlock(&timer->lock);
if (ti->callback)
ti->callback(ti, resolution, ticks);
spin_lock(&timer->lock);
ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK;
}
}
}
/* clear pending instances from ack list */
static void snd_timer_clear_callbacks(struct snd_timer *timer,
struct list_head *head)
{
unsigned long flags;
spin_lock_irqsave(&timer->lock, flags);
while (!list_empty(head))
list_del_init(head->next);
spin_unlock_irqrestore(&timer->lock, flags);
}
/*
* timer tasklet
*
@@ -727,34 +785,15 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l
static void snd_timer_tasklet(unsigned long arg)
{
struct snd_timer *timer = (struct snd_timer *) arg;
struct snd_timer_instance *ti;
struct list_head *p;
unsigned long resolution, ticks;
unsigned long flags;
if (timer->card && timer->card->shutdown)
if (timer->card && timer->card->shutdown) {
snd_timer_clear_callbacks(timer, &timer->sack_list_head);
return;
}
spin_lock_irqsave(&timer->lock, flags);
/* now process all callbacks */
while (!list_empty(&timer->sack_list_head)) {
p = timer->sack_list_head.next; /* get first item */
ti = list_entry(p, struct snd_timer_instance, ack_list);
/* remove from ack_list and make empty */
list_del_init(p);
ticks = ti->pticks;
ti->pticks = 0;
resolution = ti->resolution;
ti->flags |= SNDRV_TIMER_IFLG_CALLBACK;
spin_unlock(&timer->lock);
if (ti->callback)
ti->callback(ti, resolution, ticks);
spin_lock(&timer->lock);
ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK;
}
snd_timer_process_callbacks(timer, &timer->sack_list_head);
spin_unlock_irqrestore(&timer->lock, flags);
}
@@ -767,16 +806,18 @@ static void snd_timer_tasklet(unsigned long arg)
void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
{
struct snd_timer_instance *ti, *ts, *tmp;
unsigned long resolution, ticks;
struct list_head *p, *ack_list_head;
unsigned long resolution;
struct list_head *ack_list_head;
unsigned long flags;
int use_tasklet = 0;
if (timer == NULL)
return;
if (timer->card && timer->card->shutdown)
if (timer->card && timer->card->shutdown) {
snd_timer_clear_callbacks(timer, &timer->ack_list_head);
return;
}
spin_lock_irqsave(&timer->lock, flags);
@@ -790,6 +831,8 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
*/
list_for_each_entry_safe(ti, tmp, &timer->active_list_head,
active_list) {
if (ti->flags & SNDRV_TIMER_IFLG_DEAD)
continue;
if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING))
continue;
ti->pticks += ticks_left;
@@ -839,23 +882,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
}
/* now process all fast callbacks */
while (!list_empty(&timer->ack_list_head)) {
p = timer->ack_list_head.next; /* get first item */
ti = list_entry(p, struct snd_timer_instance, ack_list);
/* remove from ack_list and make empty */
list_del_init(p);
ticks = ti->pticks;
ti->pticks = 0;
ti->flags |= SNDRV_TIMER_IFLG_CALLBACK;
spin_unlock(&timer->lock);
if (ti->callback)
ti->callback(ti, resolution, ticks);
spin_lock(&timer->lock);
ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK;
}
snd_timer_process_callbacks(timer, &timer->ack_list_head);
/* do we have any slow callbacks? */
use_tasklet = !list_empty(&timer->sack_list_head);
@@ -1882,7 +1909,10 @@ static int snd_timer_user_start(struct file *file)
snd_timer_stop(tu->timeri);
tu->timeri->lost = 0;
tu->last_resolution = 0;
return (err = snd_timer_start(tu->timeri, tu->ticks)) < 0 ? err : 0;
err = snd_timer_start(tu->timeri, tu->ticks);
if (err < 0)
return err;
return 0;
}
static int snd_timer_user_stop(struct file *file)
@@ -1893,7 +1923,10 @@ static int snd_timer_user_stop(struct file *file)
tu = file->private_data;
if (!tu->timeri)
return -EBADFD;
return (err = snd_timer_stop(tu->timeri)) < 0 ? err : 0;
err = snd_timer_stop(tu->timeri);
if (err < 0)
return err;
return 0;
}
static int snd_timer_user_continue(struct file *file)
@@ -1908,7 +1941,10 @@ static int snd_timer_user_continue(struct file *file)
if (!(tu->timeri->flags & SNDRV_TIMER_IFLG_PAUSED))
return snd_timer_user_start(file);
tu->timeri->lost = 0;
return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
err = snd_timer_continue(tu->timeri);
if (err < 0)
return err;
return 0;
}
static int snd_timer_user_pause(struct file *file)
@@ -1919,7 +1955,10 @@ static int snd_timer_user_pause(struct file *file)
tu = file->private_data;
if (!tu->timeri)
return -EBADFD;
return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0;
err = snd_timer_pause(tu->timeri);
if (err < 0)
return err;
return 0;
}
enum {