LCOV - code coverage report
Current view: top level - sound/core/seq - seq_system.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 50 74 67.6 %
Date: 2022-04-01 14:58:12 Functions: 2 5 40.0 %
Branches: 6 14 42.9 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-or-later
       2                 :            : /*
       3                 :            :  *   ALSA sequencer System services Client
       4                 :            :  *   Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl>
       5                 :            :  */
       6                 :            : 
       7                 :            : #include <linux/init.h>
       8                 :            : #include <linux/export.h>
       9                 :            : #include <linux/slab.h>
      10                 :            : #include <sound/core.h>
      11                 :            : #include "seq_system.h"
      12                 :            : #include "seq_timer.h"
      13                 :            : #include "seq_queue.h"
      14                 :            : 
      15                 :            : /* internal client that provide system services, access to timer etc. */
      16                 :            : 
      17                 :            : /*
      18                 :            :  * Port "Timer"
      19                 :            :  *      - send tempo /start/stop etc. events to this port to manipulate the 
      20                 :            :  *        queue's timer. The queue address is specified in
      21                 :            :  *        data.queue.queue.
      22                 :            :  *      - this port supports subscription. The received timer events are 
      23                 :            :  *        broadcasted to all subscribed clients. The modified tempo
      24                 :            :  *        value is stored on data.queue.value.
      25                 :            :  *        The modifier client/port is not send.
      26                 :            :  *
      27                 :            :  * Port "Announce"
      28                 :            :  *      - does not receive message
      29                 :            :  *      - supports supscription. For each client or port attaching to or 
      30                 :            :  *        detaching from the system an announcement is send to the subscribed
      31                 :            :  *        clients.
      32                 :            :  *
      33                 :            :  * Idea: the subscription mechanism might also work handy for distributing 
      34                 :            :  * synchronisation and timing information. In this case we would ideally have
      35                 :            :  * a list of subscribers for each type of sync (time, tick), for each timing
      36                 :            :  * queue.
      37                 :            :  *
      38                 :            :  * NOTE: the queue to be started, stopped, etc. must be specified
      39                 :            :  *       in data.queue.addr.queue field.  queue is used only for
      40                 :            :  *       scheduling, and no longer referred as affected queue.
      41                 :            :  *       They are used only for timer broadcast (see above).
      42                 :            :  *                                                      -- iwai
      43                 :            :  */
      44                 :            : 
      45                 :            : 
      46                 :            : /* client id of our system client */
      47                 :            : static int sysclient = -1;
      48                 :            : 
      49                 :            : /* port id numbers for this client */
      50                 :            : static int announce_port = -1;
      51                 :            : 
      52                 :            : 
      53                 :            : 
      54                 :            : /* fill standard header data, source port & channel are filled in */
      55                 :         15 : static int setheader(struct snd_seq_event * ev, int client, int port)
      56                 :            : {
      57                 :         15 :         if (announce_port < 0)
      58                 :            :                 return -ENODEV;
      59                 :            : 
      60                 :          6 :         memset(ev, 0, sizeof(struct snd_seq_event));
      61                 :            : 
      62                 :          6 :         ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
      63                 :          6 :         ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED;
      64                 :            : 
      65                 :          6 :         ev->source.client = sysclient;
      66                 :          6 :         ev->source.port = announce_port;
      67                 :          6 :         ev->dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
      68                 :            : 
      69                 :            :         /* fill data */
      70                 :            :         /*ev->data.addr.queue = SNDRV_SEQ_ADDRESS_UNKNOWN;*/
      71                 :          6 :         ev->data.addr.client = client;
      72                 :          6 :         ev->data.addr.port = port;
      73                 :            : 
      74                 :          6 :         return 0;
      75                 :            : }
      76                 :            : 
      77                 :            : 
      78                 :            : /* entry points for broadcasting system events */
      79                 :         15 : void snd_seq_system_broadcast(int client, int port, int type)
      80                 :            : {
      81                 :         15 :         struct snd_seq_event ev;
      82                 :            :         
      83         [ +  + ]:         15 :         if (setheader(&ev, client, port) < 0)
      84                 :          9 :                 return;
      85                 :          6 :         ev.type = type;
      86                 :          6 :         snd_seq_kernel_client_dispatch(sysclient, &ev, 0, 0);
      87                 :            : }
      88                 :            : 
      89                 :            : /* entry points for broadcasting system events */
      90                 :          0 : int snd_seq_system_notify(int client, int port, struct snd_seq_event *ev)
      91                 :            : {
      92                 :          0 :         ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
      93                 :          0 :         ev->source.client = sysclient;
      94                 :          0 :         ev->source.port = announce_port;
      95                 :          0 :         ev->dest.client = client;
      96                 :          0 :         ev->dest.port = port;
      97                 :          0 :         return snd_seq_kernel_client_dispatch(sysclient, ev, 0, 0);
      98                 :            : }
      99                 :            : 
     100                 :            : /* call-back handler for timer events */
     101                 :          0 : static int event_input_timer(struct snd_seq_event * ev, int direct, void *private_data, int atomic, int hop)
     102                 :            : {
     103                 :          0 :         return snd_seq_control_queue(ev, atomic, hop);
     104                 :            : }
     105                 :            : 
     106                 :            : /* register our internal client */
     107                 :          3 : int __init snd_seq_system_client_init(void)
     108                 :            : {
     109                 :          3 :         struct snd_seq_port_callback pcallbacks;
     110                 :          3 :         struct snd_seq_port_info *port;
     111                 :          3 :         int err;
     112                 :            : 
     113                 :          3 :         port = kzalloc(sizeof(*port), GFP_KERNEL);
     114         [ +  - ]:          3 :         if (!port)
     115                 :            :                 return -ENOMEM;
     116                 :            : 
     117                 :          3 :         memset(&pcallbacks, 0, sizeof(pcallbacks));
     118                 :          3 :         pcallbacks.owner = THIS_MODULE;
     119                 :          3 :         pcallbacks.event_input = event_input_timer;
     120                 :            : 
     121                 :            :         /* register client */
     122                 :          3 :         sysclient = snd_seq_create_kernel_client(NULL, 0, "System");
     123         [ -  + ]:          3 :         if (sysclient < 0) {
     124                 :          0 :                 kfree(port);
     125                 :          0 :                 return sysclient;
     126                 :            :         }
     127                 :            : 
     128                 :            :         /* register timer */
     129                 :          3 :         strcpy(port->name, "Timer");
     130                 :          3 :         port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* accept queue control */
     131                 :          3 :         port->capability |= SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast */
     132                 :          3 :         port->kernel = &pcallbacks;
     133                 :          3 :         port->type = 0;
     134                 :          3 :         port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
     135                 :          3 :         port->addr.client = sysclient;
     136                 :          3 :         port->addr.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
     137                 :          3 :         err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT,
     138                 :            :                                         port);
     139         [ -  + ]:          3 :         if (err < 0)
     140                 :          0 :                 goto error_port;
     141                 :            : 
     142                 :            :         /* register announcement port */
     143                 :          3 :         strcpy(port->name, "Announce");
     144                 :          3 :         port->capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast only */
     145                 :          3 :         port->kernel = NULL;
     146                 :          3 :         port->type = 0;
     147                 :          3 :         port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
     148                 :          3 :         port->addr.client = sysclient;
     149                 :          3 :         port->addr.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
     150                 :          3 :         err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT,
     151                 :            :                                         port);
     152         [ -  + ]:          3 :         if (err < 0)
     153                 :          0 :                 goto error_port;
     154                 :          3 :         announce_port = port->addr.port;
     155                 :            : 
     156                 :          3 :         kfree(port);
     157                 :          3 :         return 0;
     158                 :            : 
     159                 :          0 :  error_port:
     160                 :          0 :         snd_seq_system_client_done();
     161                 :          0 :         kfree(port);
     162                 :          0 :         return err;
     163                 :            : }
     164                 :            : 
     165                 :            : 
     166                 :            : /* unregister our internal client */
     167                 :          0 : void snd_seq_system_client_done(void)
     168                 :            : {
     169                 :          0 :         int oldsysclient = sysclient;
     170                 :            : 
     171   [ #  #  #  # ]:          0 :         if (oldsysclient >= 0) {
     172                 :          0 :                 sysclient = -1;
     173                 :          0 :                 announce_port = -1;
     174                 :          0 :                 snd_seq_delete_kernel_client(oldsysclient);
     175                 :            :         }
     176                 :          0 : }

Generated by: LCOV version 1.14