Merge tag 'sound-5.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[sfrench/cifs-2.6.git] / sound / core / seq / seq_clientmgr.c
index a11bdc0350fcaeb33342fd65ab24d6d77986adc0..b3f593ee752e30dc7e98cfa04f333507d364f261 100644 (file)
@@ -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.