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 ...
这个提交包含在:
@@ -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
|
||||
|
在新工单中引用
屏蔽一个用户