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 ...
这个提交包含在:
@@ -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(®ister_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(®ister_mutex);
|
||||
timeri = snd_timer_instance_new(owner, NULL);
|
||||
if (!timeri) {
|
||||
mutex_unlock(®ister_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(®ister_mutex);
|
||||
*ti = timeri;
|
||||
return err;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* open a master instance */
|
||||
mutex_lock(®ister_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(®ister_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(®ister_mutex);
|
||||
return -EBUSY;
|
||||
err = -EBUSY;
|
||||
timeri = NULL;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
if (timer->num_instances >= timer->max_instances) {
|
||||
mutex_unlock(®ister_mutex);
|
||||
return -EBUSY;
|
||||
err = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
timeri = snd_timer_instance_new(owner, timer);
|
||||
if (!timeri) {
|
||||
mutex_unlock(®ister_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(®ister_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(®ister_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 {
|
||||
|
在新工单中引用
屏蔽一个用户