LCOV - code coverage report
Current view: top level - sound/core/seq - seq_ports.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 59 297 19.9 %
Date: 2022-04-01 14:58:12 Functions: 3 17 17.6 %
Branches: 14 130 10.8 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-or-later
       2                 :            : /*
       3                 :            :  *   ALSA sequencer Ports
       4                 :            :  *   Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
       5                 :            :  *                         Jaroslav Kysela <perex@perex.cz>
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <sound/core.h>
       9                 :            : #include <linux/slab.h>
      10                 :            : #include <linux/module.h>
      11                 :            : #include "seq_system.h"
      12                 :            : #include "seq_ports.h"
      13                 :            : #include "seq_clientmgr.h"
      14                 :            : 
      15                 :            : /*
      16                 :            : 
      17                 :            :    registration of client ports
      18                 :            : 
      19                 :            :  */
      20                 :            : 
      21                 :            : 
      22                 :            : /* 
      23                 :            : 
      24                 :            : NOTE: the current implementation of the port structure as a linked list is
      25                 :            : not optimal for clients that have many ports. For sending messages to all
      26                 :            : subscribers of a port we first need to find the address of the port
      27                 :            : structure, which means we have to traverse the list. A direct access table
      28                 :            : (array) would be better, but big preallocated arrays waste memory.
      29                 :            : 
      30                 :            : Possible actions:
      31                 :            : 
      32                 :            : 1) leave it this way, a client does normaly does not have more than a few
      33                 :            : ports
      34                 :            : 
      35                 :            : 2) replace the linked list of ports by a array of pointers which is
      36                 :            : dynamicly kmalloced. When a port is added or deleted we can simply allocate
      37                 :            : a new array, copy the corresponding pointers, and delete the old one. We
      38                 :            : then only need a pointer to this array, and an integer that tells us how
      39                 :            : much elements are in array.
      40                 :            : 
      41                 :            : */
      42                 :            : 
      43                 :            : /* return pointer to port structure - port is locked if found */
      44                 :          6 : struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client,
      45                 :            :                                                  int num)
      46                 :            : {
      47                 :          6 :         struct snd_seq_client_port *port;
      48                 :            : 
      49         [ +  - ]:          6 :         if (client == NULL)
      50                 :            :                 return NULL;
      51                 :          6 :         read_lock(&client->ports_lock);
      52         [ +  - ]:         12 :         list_for_each_entry(port, &client->ports_list_head, list) {
      53         [ +  + ]:         12 :                 if (port->addr.port == num) {
      54         [ +  - ]:          6 :                         if (port->closing)
      55                 :            :                                 break; /* deleting now */
      56                 :          6 :                         snd_use_lock_use(&port->use_lock);
      57                 :          6 :                         read_unlock(&client->ports_lock);
      58                 :          6 :                         return port;
      59                 :            :                 }
      60                 :            :         }
      61                 :          0 :         read_unlock(&client->ports_lock);
      62                 :          0 :         return NULL;            /* not found */
      63                 :            : }
      64                 :            : 
      65                 :            : 
      66                 :            : /* search for the next port - port is locked if found */
      67                 :          0 : struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *client,
      68                 :            :                                                        struct snd_seq_port_info *pinfo)
      69                 :            : {
      70                 :          0 :         int num;
      71                 :          0 :         struct snd_seq_client_port *port, *found;
      72                 :            : 
      73                 :          0 :         num = pinfo->addr.port;
      74                 :          0 :         found = NULL;
      75                 :          0 :         read_lock(&client->ports_lock);
      76         [ #  # ]:          0 :         list_for_each_entry(port, &client->ports_list_head, list) {
      77         [ #  # ]:          0 :                 if (port->addr.port < num)
      78                 :          0 :                         continue;
      79         [ #  # ]:          0 :                 if (port->addr.port == num) {
      80                 :            :                         found = port;
      81                 :            :                         break;
      82                 :            :                 }
      83   [ #  #  #  # ]:          0 :                 if (found == NULL || port->addr.port < found->addr.port)
      84                 :          0 :                         found = port;
      85                 :            :         }
      86         [ #  # ]:          0 :         if (found) {
      87         [ #  # ]:          0 :                 if (found->closing)
      88                 :            :                         found = NULL;
      89                 :            :                 else
      90                 :          0 :                         snd_use_lock_use(&found->use_lock);
      91                 :            :         }
      92                 :          0 :         read_unlock(&client->ports_lock);
      93                 :          0 :         return found;
      94                 :            : }
      95                 :            : 
      96                 :            : 
      97                 :            : /* initialize snd_seq_port_subs_info */
      98                 :         18 : static void port_subs_info_init(struct snd_seq_port_subs_info *grp)
      99                 :            : {
     100                 :         18 :         INIT_LIST_HEAD(&grp->list_head);
     101                 :         18 :         grp->count = 0;
     102                 :         18 :         grp->exclusive = 0;
     103                 :          9 :         rwlock_init(&grp->list_lock);
     104                 :          9 :         init_rwsem(&grp->list_mutex);
     105                 :         18 :         grp->open = NULL;
     106                 :         18 :         grp->close = NULL;
     107                 :            : }
     108                 :            : 
     109                 :            : 
     110                 :            : /* create a port, port number is returned (-1 on failure);
     111                 :            :  * the caller needs to unref the port via snd_seq_port_unlock() appropriately
     112                 :            :  */
     113                 :          9 : struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
     114                 :            :                                                 int port)
     115                 :            : {
     116                 :          9 :         struct snd_seq_client_port *new_port, *p;
     117                 :          9 :         int num = -1;
     118                 :            :         
     119                 :            :         /* sanity check */
     120         [ +  - ]:          9 :         if (snd_BUG_ON(!client))
     121                 :            :                 return NULL;
     122                 :            : 
     123         [ -  + ]:          9 :         if (client->num_ports >= SNDRV_SEQ_MAX_PORTS) {
     124                 :          0 :                 pr_warn("ALSA: seq: too many ports for client %d\n", client->number);
     125                 :          0 :                 return NULL;
     126                 :            :         }
     127                 :            : 
     128                 :            :         /* create a new port */
     129                 :          9 :         new_port = kzalloc(sizeof(*new_port), GFP_KERNEL);
     130         [ +  - ]:          9 :         if (!new_port)
     131                 :            :                 return NULL;    /* failure, out of memory */
     132                 :            :         /* init port data */
     133                 :          9 :         new_port->addr.client = client->number;
     134                 :          9 :         new_port->addr.port = -1;
     135                 :          9 :         new_port->owner = THIS_MODULE;
     136                 :          9 :         sprintf(new_port->name, "port-%d", num);
     137                 :          9 :         snd_use_lock_init(&new_port->use_lock);
     138                 :          9 :         port_subs_info_init(&new_port->c_src);
     139                 :          9 :         port_subs_info_init(&new_port->c_dest);
     140                 :          9 :         snd_use_lock_use(&new_port->use_lock);
     141                 :            : 
     142                 :          9 :         num = port >= 0 ? port : 0;
     143                 :          9 :         mutex_lock(&client->ports_mutex);
     144                 :          9 :         write_lock_irq(&client->ports_lock);
     145         [ +  + ]:         12 :         list_for_each_entry(p, &client->ports_list_head, list) {
     146         [ +  - ]:          3 :                 if (p->addr.port > num)
     147                 :            :                         break;
     148         [ -  + ]:          3 :                 if (port < 0) /* auto-probe mode */
     149                 :          0 :                         num = p->addr.port + 1;
     150                 :            :         }
     151                 :            :         /* insert the new port */
     152                 :          9 :         list_add_tail(&new_port->list, &p->list);
     153                 :          9 :         client->num_ports++;
     154                 :          9 :         new_port->addr.port = num;   /* store the port number in the port */
     155                 :          9 :         sprintf(new_port->name, "port-%d", num);
     156                 :          9 :         write_unlock_irq(&client->ports_lock);
     157                 :          9 :         mutex_unlock(&client->ports_mutex);
     158                 :            : 
     159                 :          9 :         return new_port;
     160                 :            : }
     161                 :            : 
     162                 :            : /* */
     163                 :            : static int subscribe_port(struct snd_seq_client *client,
     164                 :            :                           struct snd_seq_client_port *port,
     165                 :            :                           struct snd_seq_port_subs_info *grp,
     166                 :            :                           struct snd_seq_port_subscribe *info, int send_ack);
     167                 :            : static int unsubscribe_port(struct snd_seq_client *client,
     168                 :            :                             struct snd_seq_client_port *port,
     169                 :            :                             struct snd_seq_port_subs_info *grp,
     170                 :            :                             struct snd_seq_port_subscribe *info, int send_ack);
     171                 :            : 
     172                 :            : 
     173                 :            : static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr,
     174                 :            :                                                    struct snd_seq_client **cp)
     175                 :            : {
     176                 :            :         struct snd_seq_client_port *p;
     177                 :            :         *cp = snd_seq_client_use_ptr(addr->client);
     178                 :            :         if (*cp) {
     179                 :            :                 p = snd_seq_port_use_ptr(*cp, addr->port);
     180                 :            :                 if (! p) {
     181                 :            :                         snd_seq_client_unlock(*cp);
     182                 :            :                         *cp = NULL;
     183                 :            :                 }
     184                 :            :                 return p;
     185                 :            :         }
     186                 :            :         return NULL;
     187                 :            : }
     188                 :            : 
     189                 :            : static void delete_and_unsubscribe_port(struct snd_seq_client *client,
     190                 :            :                                         struct snd_seq_client_port *port,
     191                 :            :                                         struct snd_seq_subscribers *subs,
     192                 :            :                                         bool is_src, bool ack);
     193                 :            : 
     194                 :            : static inline struct snd_seq_subscribers *
     195                 :          0 : get_subscriber(struct list_head *p, bool is_src)
     196                 :            : {
     197                 :          0 :         if (is_src)
     198                 :          0 :                 return list_entry(p, struct snd_seq_subscribers, src_list);
     199                 :            :         else
     200                 :          0 :                 return list_entry(p, struct snd_seq_subscribers, dest_list);
     201                 :            : }
     202                 :            : 
     203                 :            : /*
     204                 :            :  * remove all subscribers on the list
     205                 :            :  * this is called from port_delete, for each src and dest list.
     206                 :            :  */
     207                 :          0 : static void clear_subscriber_list(struct snd_seq_client *client,
     208                 :            :                                   struct snd_seq_client_port *port,
     209                 :            :                                   struct snd_seq_port_subs_info *grp,
     210                 :            :                                   int is_src)
     211                 :            : {
     212                 :          0 :         struct list_head *p, *n;
     213                 :            : 
     214         [ #  # ]:          0 :         list_for_each_safe(p, n, &grp->list_head) {
     215                 :          0 :                 struct snd_seq_subscribers *subs;
     216                 :          0 :                 struct snd_seq_client *c;
     217                 :          0 :                 struct snd_seq_client_port *aport;
     218                 :            : 
     219         [ #  # ]:          0 :                 subs = get_subscriber(p, is_src);
     220         [ #  # ]:          0 :                 if (is_src)
     221                 :          0 :                         aport = get_client_port(&subs->info.dest, &c);
     222                 :            :                 else
     223                 :          0 :                         aport = get_client_port(&subs->info.sender, &c);
     224                 :          0 :                 delete_and_unsubscribe_port(client, port, subs, is_src, false);
     225                 :            : 
     226         [ #  # ]:          0 :                 if (!aport) {
     227                 :            :                         /* looks like the connected port is being deleted.
     228                 :            :                          * we decrease the counter, and when both ports are deleted
     229                 :            :                          * remove the subscriber info
     230                 :            :                          */
     231         [ #  # ]:          0 :                         if (atomic_dec_and_test(&subs->ref_count))
     232                 :          0 :                                 kfree(subs);
     233                 :          0 :                         continue;
     234                 :            :                 }
     235                 :            : 
     236                 :            :                 /* ok we got the connected port */
     237                 :          0 :                 delete_and_unsubscribe_port(c, aport, subs, !is_src, true);
     238                 :          0 :                 kfree(subs);
     239                 :          0 :                 snd_seq_port_unlock(aport);
     240                 :          0 :                 snd_seq_client_unlock(c);
     241                 :            :         }
     242                 :          0 : }
     243                 :            : 
     244                 :            : /* delete port data */
     245                 :          0 : static int port_delete(struct snd_seq_client *client,
     246                 :            :                        struct snd_seq_client_port *port)
     247                 :            : {
     248                 :            :         /* set closing flag and wait for all port access are gone */
     249                 :          0 :         port->closing = 1;
     250                 :          0 :         snd_use_lock_sync(&port->use_lock); 
     251                 :            : 
     252                 :            :         /* clear subscribers info */
     253                 :          0 :         clear_subscriber_list(client, port, &port->c_src, true);
     254                 :          0 :         clear_subscriber_list(client, port, &port->c_dest, false);
     255                 :            : 
     256         [ #  # ]:          0 :         if (port->private_free)
     257                 :          0 :                 port->private_free(port->private_data);
     258                 :            : 
     259                 :          0 :         snd_BUG_ON(port->c_src.count != 0);
     260                 :          0 :         snd_BUG_ON(port->c_dest.count != 0);
     261                 :            : 
     262                 :          0 :         kfree(port);
     263                 :          0 :         return 0;
     264                 :            : }
     265                 :            : 
     266                 :            : 
     267                 :            : /* delete a port with the given port id */
     268                 :          0 : int snd_seq_delete_port(struct snd_seq_client *client, int port)
     269                 :            : {
     270                 :          0 :         struct snd_seq_client_port *found = NULL, *p;
     271                 :            : 
     272                 :          0 :         mutex_lock(&client->ports_mutex);
     273                 :          0 :         write_lock_irq(&client->ports_lock);
     274         [ #  # ]:          0 :         list_for_each_entry(p, &client->ports_list_head, list) {
     275         [ #  # ]:          0 :                 if (p->addr.port == port) {
     276                 :            :                         /* ok found.  delete from the list at first */
     277                 :          0 :                         list_del(&p->list);
     278                 :          0 :                         client->num_ports--;
     279                 :          0 :                         found = p;
     280                 :          0 :                         break;
     281                 :            :                 }
     282                 :            :         }
     283                 :          0 :         write_unlock_irq(&client->ports_lock);
     284                 :          0 :         mutex_unlock(&client->ports_mutex);
     285         [ #  # ]:          0 :         if (found)
     286                 :          0 :                 return port_delete(client, found);
     287                 :            :         else
     288                 :            :                 return -ENOENT;
     289                 :            : }
     290                 :            : 
     291                 :            : /* delete the all ports belonging to the given client */
     292                 :          0 : int snd_seq_delete_all_ports(struct snd_seq_client *client)
     293                 :            : {
     294                 :          0 :         struct list_head deleted_list;
     295                 :          0 :         struct snd_seq_client_port *port, *tmp;
     296                 :            :         
     297                 :            :         /* move the port list to deleted_list, and
     298                 :            :          * clear the port list in the client data.
     299                 :            :          */
     300                 :          0 :         mutex_lock(&client->ports_mutex);
     301                 :          0 :         write_lock_irq(&client->ports_lock);
     302         [ #  # ]:          0 :         if (! list_empty(&client->ports_list_head)) {
     303                 :          0 :                 list_add(&deleted_list, &client->ports_list_head);
     304                 :          0 :                 list_del_init(&client->ports_list_head);
     305                 :            :         } else {
     306                 :          0 :                 INIT_LIST_HEAD(&deleted_list);
     307                 :            :         }
     308                 :          0 :         client->num_ports = 0;
     309                 :          0 :         write_unlock_irq(&client->ports_lock);
     310                 :            : 
     311                 :            :         /* remove each port in deleted_list */
     312         [ #  # ]:          0 :         list_for_each_entry_safe(port, tmp, &deleted_list, list) {
     313                 :          0 :                 list_del(&port->list);
     314                 :          0 :                 snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port);
     315                 :          0 :                 port_delete(client, port);
     316                 :            :         }
     317                 :          0 :         mutex_unlock(&client->ports_mutex);
     318                 :          0 :         return 0;
     319                 :            : }
     320                 :            : 
     321                 :            : /* set port info fields */
     322                 :          9 : int snd_seq_set_port_info(struct snd_seq_client_port * port,
     323                 :            :                           struct snd_seq_port_info * info)
     324                 :            : {
     325         [ +  - ]:          9 :         if (snd_BUG_ON(!port || !info))
     326                 :            :                 return -EINVAL;
     327                 :            : 
     328                 :            :         /* set port name */
     329         [ +  - ]:          9 :         if (info->name[0])
     330                 :          9 :                 strlcpy(port->name, info->name, sizeof(port->name));
     331                 :            :         
     332                 :            :         /* set capabilities */
     333                 :          9 :         port->capability = info->capability;
     334                 :            :         
     335                 :            :         /* get port type */
     336                 :          9 :         port->type = info->type;
     337                 :            : 
     338                 :            :         /* information about supported channels/voices */
     339                 :          9 :         port->midi_channels = info->midi_channels;
     340                 :          9 :         port->midi_voices = info->midi_voices;
     341                 :          9 :         port->synth_voices = info->synth_voices;
     342                 :            : 
     343                 :            :         /* timestamping */
     344                 :          9 :         port->timestamping = (info->flags & SNDRV_SEQ_PORT_FLG_TIMESTAMP) ? 1 : 0;
     345                 :          9 :         port->time_real = (info->flags & SNDRV_SEQ_PORT_FLG_TIME_REAL) ? 1 : 0;
     346                 :          9 :         port->time_queue = info->time_queue;
     347                 :            : 
     348                 :          9 :         return 0;
     349                 :            : }
     350                 :            : 
     351                 :            : /* get port info fields */
     352                 :          0 : int snd_seq_get_port_info(struct snd_seq_client_port * port,
     353                 :            :                           struct snd_seq_port_info * info)
     354                 :            : {
     355         [ #  # ]:          0 :         if (snd_BUG_ON(!port || !info))
     356                 :            :                 return -EINVAL;
     357                 :            : 
     358                 :            :         /* get port name */
     359                 :          0 :         strlcpy(info->name, port->name, sizeof(info->name));
     360                 :            :         
     361                 :            :         /* get capabilities */
     362                 :          0 :         info->capability = port->capability;
     363                 :            : 
     364                 :            :         /* get port type */
     365                 :          0 :         info->type = port->type;
     366                 :            : 
     367                 :            :         /* information about supported channels/voices */
     368                 :          0 :         info->midi_channels = port->midi_channels;
     369                 :          0 :         info->midi_voices = port->midi_voices;
     370                 :          0 :         info->synth_voices = port->synth_voices;
     371                 :            : 
     372                 :            :         /* get subscriber counts */
     373                 :          0 :         info->read_use = port->c_src.count;
     374                 :          0 :         info->write_use = port->c_dest.count;
     375                 :            :         
     376                 :            :         /* timestamping */
     377                 :          0 :         info->flags = 0;
     378         [ #  # ]:          0 :         if (port->timestamping) {
     379                 :          0 :                 info->flags |= SNDRV_SEQ_PORT_FLG_TIMESTAMP;
     380         [ #  # ]:          0 :                 if (port->time_real)
     381                 :          0 :                         info->flags |= SNDRV_SEQ_PORT_FLG_TIME_REAL;
     382                 :          0 :                 info->time_queue = port->time_queue;
     383                 :            :         }
     384                 :            : 
     385                 :            :         return 0;
     386                 :            : }
     387                 :            : 
     388                 :            : 
     389                 :            : 
     390                 :            : /*
     391                 :            :  * call callback functions (if any):
     392                 :            :  * the callbacks are invoked only when the first (for connection) or
     393                 :            :  * the last subscription (for disconnection) is done.  Second or later
     394                 :            :  * subscription results in increment of counter, but no callback is
     395                 :            :  * invoked.
     396                 :            :  * This feature is useful if these callbacks are associated with
     397                 :            :  * initialization or termination of devices (see seq_midi.c).
     398                 :            :  */
     399                 :            : 
     400                 :            : static int subscribe_port(struct snd_seq_client *client,
     401                 :            :                           struct snd_seq_client_port *port,
     402                 :            :                           struct snd_seq_port_subs_info *grp,
     403                 :            :                           struct snd_seq_port_subscribe *info,
     404                 :            :                           int send_ack)
     405                 :            : {
     406                 :            :         int err = 0;
     407                 :            : 
     408                 :            :         if (!try_module_get(port->owner))
     409                 :            :                 return -EFAULT;
     410                 :            :         grp->count++;
     411                 :            :         if (grp->open && grp->count == 1) {
     412                 :            :                 err = grp->open(port->private_data, info);
     413                 :            :                 if (err < 0) {
     414                 :            :                         module_put(port->owner);
     415                 :            :                         grp->count--;
     416                 :            :                 }
     417                 :            :         }
     418                 :            :         if (err >= 0 && send_ack && client->type == USER_CLIENT)
     419                 :            :                 snd_seq_client_notify_subscription(port->addr.client, port->addr.port,
     420                 :            :                                                    info, SNDRV_SEQ_EVENT_PORT_SUBSCRIBED);
     421                 :            : 
     422                 :            :         return err;
     423                 :            : }
     424                 :            : 
     425                 :            : static int unsubscribe_port(struct snd_seq_client *client,
     426                 :            :                             struct snd_seq_client_port *port,
     427                 :            :                             struct snd_seq_port_subs_info *grp,
     428                 :            :                             struct snd_seq_port_subscribe *info,
     429                 :            :                             int send_ack)
     430                 :            : {
     431                 :            :         int err = 0;
     432                 :            : 
     433                 :            :         if (! grp->count)
     434                 :            :                 return -EINVAL;
     435                 :            :         grp->count--;
     436                 :            :         if (grp->close && grp->count == 0)
     437                 :            :                 err = grp->close(port->private_data, info);
     438                 :            :         if (send_ack && client->type == USER_CLIENT)
     439                 :            :                 snd_seq_client_notify_subscription(port->addr.client, port->addr.port,
     440                 :            :                                                    info, SNDRV_SEQ_EVENT_PORT_UNSUBSCRIBED);
     441                 :            :         module_put(port->owner);
     442                 :            :         return err;
     443                 :            : }
     444                 :            : 
     445                 :            : 
     446                 :            : 
     447                 :            : /* check if both addresses are identical */
     448                 :          0 : static inline int addr_match(struct snd_seq_addr *r, struct snd_seq_addr *s)
     449                 :            : {
     450   [ #  #  #  #  :          0 :         return (r->client == s->client) && (r->port == s->port);
                   #  # ]
     451                 :            : }
     452                 :            : 
     453                 :            : /* check the two subscribe info match */
     454                 :            : /* if flags is zero, checks only sender and destination addresses */
     455                 :          0 : static int match_subs_info(struct snd_seq_port_subscribe *r,
     456                 :            :                            struct snd_seq_port_subscribe *s)
     457                 :            : {
     458         [ #  # ]:          0 :         if (addr_match(&r->sender, &s->sender) &&
     459         [ #  # ]:          0 :             addr_match(&r->dest, &s->dest)) {
     460   [ #  #  #  # ]:          0 :                 if (r->flags && r->flags == s->flags)
     461                 :          0 :                         return r->queue == s->queue;
     462         [ #  # ]:          0 :                 else if (! r->flags)
     463                 :          0 :                         return 1;
     464                 :            :         }
     465                 :            :         return 0;
     466                 :            : }
     467                 :            : 
     468                 :          0 : static int check_and_subscribe_port(struct snd_seq_client *client,
     469                 :            :                                     struct snd_seq_client_port *port,
     470                 :            :                                     struct snd_seq_subscribers *subs,
     471                 :            :                                     bool is_src, bool exclusive, bool ack)
     472                 :            : {
     473                 :          0 :         struct snd_seq_port_subs_info *grp;
     474                 :          0 :         struct list_head *p;
     475                 :          0 :         struct snd_seq_subscribers *s;
     476                 :          0 :         int err;
     477                 :            : 
     478         [ #  # ]:          0 :         grp = is_src ? &port->c_src : &port->c_dest;
     479                 :          0 :         err = -EBUSY;
     480                 :          0 :         down_write(&grp->list_mutex);
     481         [ #  # ]:          0 :         if (exclusive) {
     482         [ #  # ]:          0 :                 if (!list_empty(&grp->list_head))
     483                 :          0 :                         goto __error;
     484                 :            :         } else {
     485         [ #  # ]:          0 :                 if (grp->exclusive)
     486                 :          0 :                         goto __error;
     487                 :            :                 /* check whether already exists */
     488         [ #  # ]:          0 :                 list_for_each(p, &grp->list_head) {
     489         [ #  # ]:          0 :                         s = get_subscriber(p, is_src);
     490         [ #  # ]:          0 :                         if (match_subs_info(&subs->info, &s->info))
     491                 :          0 :                                 goto __error;
     492                 :            :                 }
     493                 :            :         }
     494                 :            : 
     495                 :          0 :         err = subscribe_port(client, port, grp, &subs->info, ack);
     496         [ #  # ]:          0 :         if (err < 0) {
     497                 :          0 :                 grp->exclusive = 0;
     498                 :          0 :                 goto __error;
     499                 :            :         }
     500                 :            : 
     501                 :            :         /* add to list */
     502                 :          0 :         write_lock_irq(&grp->list_lock);
     503         [ #  # ]:          0 :         if (is_src)
     504                 :          0 :                 list_add_tail(&subs->src_list, &grp->list_head);
     505                 :            :         else
     506                 :          0 :                 list_add_tail(&subs->dest_list, &grp->list_head);
     507                 :          0 :         grp->exclusive = exclusive;
     508                 :          0 :         atomic_inc(&subs->ref_count);
     509                 :          0 :         write_unlock_irq(&grp->list_lock);
     510                 :          0 :         err = 0;
     511                 :            : 
     512                 :          0 :  __error:
     513                 :          0 :         up_write(&grp->list_mutex);
     514                 :          0 :         return err;
     515                 :            : }
     516                 :            : 
     517                 :          0 : static void delete_and_unsubscribe_port(struct snd_seq_client *client,
     518                 :            :                                         struct snd_seq_client_port *port,
     519                 :            :                                         struct snd_seq_subscribers *subs,
     520                 :            :                                         bool is_src, bool ack)
     521                 :            : {
     522                 :          0 :         struct snd_seq_port_subs_info *grp;
     523                 :          0 :         struct list_head *list;
     524                 :          0 :         bool empty;
     525                 :            : 
     526         [ #  # ]:          0 :         grp = is_src ? &port->c_src : &port->c_dest;
     527         [ #  # ]:          0 :         list = is_src ? &subs->src_list : &subs->dest_list;
     528                 :          0 :         down_write(&grp->list_mutex);
     529                 :          0 :         write_lock_irq(&grp->list_lock);
     530         [ #  # ]:          0 :         empty = list_empty(list);
     531         [ #  # ]:          0 :         if (!empty)
     532                 :          0 :                 list_del_init(list);
     533                 :          0 :         grp->exclusive = 0;
     534                 :          0 :         write_unlock_irq(&grp->list_lock);
     535                 :            : 
     536         [ #  # ]:          0 :         if (!empty)
     537                 :          0 :                 unsubscribe_port(client, port, grp, &subs->info, ack);
     538                 :          0 :         up_write(&grp->list_mutex);
     539                 :          0 : }
     540                 :            : 
     541                 :            : /* connect two ports */
     542                 :          0 : int snd_seq_port_connect(struct snd_seq_client *connector,
     543                 :            :                          struct snd_seq_client *src_client,
     544                 :            :                          struct snd_seq_client_port *src_port,
     545                 :            :                          struct snd_seq_client *dest_client,
     546                 :            :                          struct snd_seq_client_port *dest_port,
     547                 :            :                          struct snd_seq_port_subscribe *info)
     548                 :            : {
     549                 :          0 :         struct snd_seq_subscribers *subs;
     550                 :          0 :         bool exclusive;
     551                 :          0 :         int err;
     552                 :            : 
     553                 :          0 :         subs = kzalloc(sizeof(*subs), GFP_KERNEL);
     554         [ #  # ]:          0 :         if (!subs)
     555                 :            :                 return -ENOMEM;
     556                 :            : 
     557                 :          0 :         subs->info = *info;
     558                 :          0 :         atomic_set(&subs->ref_count, 0);
     559                 :          0 :         INIT_LIST_HEAD(&subs->src_list);
     560                 :          0 :         INIT_LIST_HEAD(&subs->dest_list);
     561                 :            : 
     562                 :          0 :         exclusive = !!(info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE);
     563                 :            : 
     564                 :          0 :         err = check_and_subscribe_port(src_client, src_port, subs, true,
     565                 :            :                                        exclusive,
     566                 :          0 :                                        connector->number != src_client->number);
     567         [ #  # ]:          0 :         if (err < 0)
     568                 :          0 :                 goto error;
     569                 :          0 :         err = check_and_subscribe_port(dest_client, dest_port, subs, false,
     570                 :            :                                        exclusive,
     571                 :          0 :                                        connector->number != dest_client->number);
     572         [ #  # ]:          0 :         if (err < 0)
     573                 :          0 :                 goto error_dest;
     574                 :            : 
     575                 :            :         return 0;
     576                 :            : 
     577                 :            :  error_dest:
     578                 :          0 :         delete_and_unsubscribe_port(src_client, src_port, subs, true,
     579                 :          0 :                                     connector->number != src_client->number);
     580                 :          0 :  error:
     581                 :          0 :         kfree(subs);
     582                 :          0 :         return err;
     583                 :            : }
     584                 :            : 
     585                 :            : /* remove the connection */
     586                 :          0 : int snd_seq_port_disconnect(struct snd_seq_client *connector,
     587                 :            :                             struct snd_seq_client *src_client,
     588                 :            :                             struct snd_seq_client_port *src_port,
     589                 :            :                             struct snd_seq_client *dest_client,
     590                 :            :                             struct snd_seq_client_port *dest_port,
     591                 :            :                             struct snd_seq_port_subscribe *info)
     592                 :            : {
     593                 :          0 :         struct snd_seq_port_subs_info *src = &src_port->c_src;
     594                 :          0 :         struct snd_seq_subscribers *subs;
     595                 :          0 :         int err = -ENOENT;
     596                 :            : 
     597                 :          0 :         down_write(&src->list_mutex);
     598                 :            :         /* look for the connection */
     599         [ #  # ]:          0 :         list_for_each_entry(subs, &src->list_head, src_list) {
     600         [ #  # ]:          0 :                 if (match_subs_info(info, &subs->info)) {
     601                 :          0 :                         atomic_dec(&subs->ref_count); /* mark as not ready */
     602                 :          0 :                         err = 0;
     603                 :          0 :                         break;
     604                 :            :                 }
     605                 :            :         }
     606                 :          0 :         up_write(&src->list_mutex);
     607         [ #  # ]:          0 :         if (err < 0)
     608                 :            :                 return err;
     609                 :            : 
     610                 :          0 :         delete_and_unsubscribe_port(src_client, src_port, subs, true,
     611                 :          0 :                                     connector->number != src_client->number);
     612                 :          0 :         delete_and_unsubscribe_port(dest_client, dest_port, subs, false,
     613                 :          0 :                                     connector->number != dest_client->number);
     614                 :          0 :         kfree(subs);
     615                 :          0 :         return 0;
     616                 :            : }
     617                 :            : 
     618                 :            : 
     619                 :            : /* get matched subscriber */
     620                 :          0 : int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
     621                 :            :                                   struct snd_seq_addr *dest_addr,
     622                 :            :                                   struct snd_seq_port_subscribe *subs)
     623                 :            : {
     624                 :          0 :         struct snd_seq_subscribers *s;
     625                 :          0 :         int err = -ENOENT;
     626                 :            : 
     627                 :          0 :         down_read(&src_grp->list_mutex);
     628         [ #  # ]:          0 :         list_for_each_entry(s, &src_grp->list_head, src_list) {
     629         [ #  # ]:          0 :                 if (addr_match(dest_addr, &s->info.dest)) {
     630                 :          0 :                         *subs = s->info;
     631                 :          0 :                         err = 0;
     632                 :          0 :                         break;
     633                 :            :                 }
     634                 :            :         }
     635                 :          0 :         up_read(&src_grp->list_mutex);
     636                 :          0 :         return err;
     637                 :            : }
     638                 :            : 
     639                 :            : /*
     640                 :            :  * Attach a device driver that wants to receive events from the
     641                 :            :  * sequencer.  Returns the new port number on success.
     642                 :            :  * A driver that wants to receive the events converted to midi, will
     643                 :            :  * use snd_seq_midisynth_register_port().
     644                 :            :  */
     645                 :            : /* exported */
     646                 :          0 : int snd_seq_event_port_attach(int client,
     647                 :            :                               struct snd_seq_port_callback *pcbp,
     648                 :            :                               int cap, int type, int midi_channels,
     649                 :            :                               int midi_voices, char *portname)
     650                 :            : {
     651                 :          0 :         struct snd_seq_port_info portinfo;
     652                 :          0 :         int  ret;
     653                 :            : 
     654                 :            :         /* Set up the port */
     655                 :          0 :         memset(&portinfo, 0, sizeof(portinfo));
     656                 :          0 :         portinfo.addr.client = client;
     657         [ #  # ]:          0 :         strlcpy(portinfo.name, portname ? portname : "Unnamed port",
     658                 :            :                 sizeof(portinfo.name));
     659                 :            : 
     660                 :          0 :         portinfo.capability = cap;
     661                 :          0 :         portinfo.type = type;
     662                 :          0 :         portinfo.kernel = pcbp;
     663                 :          0 :         portinfo.midi_channels = midi_channels;
     664                 :          0 :         portinfo.midi_voices = midi_voices;
     665                 :            : 
     666                 :            :         /* Create it */
     667                 :          0 :         ret = snd_seq_kernel_client_ctl(client,
     668                 :            :                                         SNDRV_SEQ_IOCTL_CREATE_PORT,
     669                 :            :                                         &portinfo);
     670                 :            : 
     671         [ #  # ]:          0 :         if (ret >= 0)
     672                 :          0 :                 ret = portinfo.addr.port;
     673                 :            : 
     674                 :          0 :         return ret;
     675                 :            : }
     676                 :            : EXPORT_SYMBOL(snd_seq_event_port_attach);
     677                 :            : 
     678                 :            : /*
     679                 :            :  * Detach the driver from a port.
     680                 :            :  */
     681                 :            : /* exported */
     682                 :          0 : int snd_seq_event_port_detach(int client, int port)
     683                 :            : {
     684                 :          0 :         struct snd_seq_port_info portinfo;
     685                 :          0 :         int  err;
     686                 :            : 
     687                 :          0 :         memset(&portinfo, 0, sizeof(portinfo));
     688                 :          0 :         portinfo.addr.client = client;
     689                 :          0 :         portinfo.addr.port   = port;
     690                 :          0 :         err = snd_seq_kernel_client_ctl(client,
     691                 :            :                                         SNDRV_SEQ_IOCTL_DELETE_PORT,
     692                 :            :                                         &portinfo);
     693                 :            : 
     694                 :          0 :         return err;
     695                 :            : }
     696                 :            : EXPORT_SYMBOL(snd_seq_event_port_detach);

Generated by: LCOV version 1.14