cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

seq_system.c (4930B)


      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 */
     47static int sysclient = -1;
     48
     49/* port id numbers for this client */
     50static int announce_port = -1;
     51
     52
     53
     54/* fill standard header data, source port & channel are filled in */
     55static int setheader(struct snd_seq_event * ev, int client, int port)
     56{
     57	if (announce_port < 0)
     58		return -ENODEV;
     59
     60	memset(ev, 0, sizeof(struct snd_seq_event));
     61
     62	ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
     63	ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED;
     64
     65	ev->source.client = sysclient;
     66	ev->source.port = announce_port;
     67	ev->dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
     68
     69	/* fill data */
     70	/*ev->data.addr.queue = SNDRV_SEQ_ADDRESS_UNKNOWN;*/
     71	ev->data.addr.client = client;
     72	ev->data.addr.port = port;
     73
     74	return 0;
     75}
     76
     77
     78/* entry points for broadcasting system events */
     79void snd_seq_system_broadcast(int client, int port, int type)
     80{
     81	struct snd_seq_event ev;
     82	
     83	if (setheader(&ev, client, port) < 0)
     84		return;
     85	ev.type = type;
     86	snd_seq_kernel_client_dispatch(sysclient, &ev, 0, 0);
     87}
     88
     89/* entry points for broadcasting system events */
     90int snd_seq_system_notify(int client, int port, struct snd_seq_event *ev)
     91{
     92	ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
     93	ev->source.client = sysclient;
     94	ev->source.port = announce_port;
     95	ev->dest.client = client;
     96	ev->dest.port = port;
     97	return snd_seq_kernel_client_dispatch(sysclient, ev, 0, 0);
     98}
     99
    100/* call-back handler for timer events */
    101static int event_input_timer(struct snd_seq_event * ev, int direct, void *private_data, int atomic, int hop)
    102{
    103	return snd_seq_control_queue(ev, atomic, hop);
    104}
    105
    106/* register our internal client */
    107int __init snd_seq_system_client_init(void)
    108{
    109	struct snd_seq_port_callback pcallbacks;
    110	struct snd_seq_port_info *port;
    111	int err;
    112
    113	port = kzalloc(sizeof(*port), GFP_KERNEL);
    114	if (!port)
    115		return -ENOMEM;
    116
    117	memset(&pcallbacks, 0, sizeof(pcallbacks));
    118	pcallbacks.owner = THIS_MODULE;
    119	pcallbacks.event_input = event_input_timer;
    120
    121	/* register client */
    122	sysclient = snd_seq_create_kernel_client(NULL, 0, "System");
    123	if (sysclient < 0) {
    124		kfree(port);
    125		return sysclient;
    126	}
    127
    128	/* register timer */
    129	strcpy(port->name, "Timer");
    130	port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* accept queue control */
    131	port->capability |= SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast */
    132	port->kernel = &pcallbacks;
    133	port->type = 0;
    134	port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
    135	port->addr.client = sysclient;
    136	port->addr.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
    137	err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT,
    138					port);
    139	if (err < 0)
    140		goto error_port;
    141
    142	/* register announcement port */
    143	strcpy(port->name, "Announce");
    144	port->capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast only */
    145	port->kernel = NULL;
    146	port->type = 0;
    147	port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
    148	port->addr.client = sysclient;
    149	port->addr.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
    150	err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT,
    151					port);
    152	if (err < 0)
    153		goto error_port;
    154	announce_port = port->addr.port;
    155
    156	kfree(port);
    157	return 0;
    158
    159 error_port:
    160	snd_seq_system_client_done();
    161	kfree(port);
    162	return err;
    163}
    164
    165
    166/* unregister our internal client */
    167void snd_seq_system_client_done(void)
    168{
    169	int oldsysclient = sysclient;
    170
    171	if (oldsysclient >= 0) {
    172		sysclient = -1;
    173		announce_port = -1;
    174		snd_seq_delete_kernel_client(oldsysclient);
    175	}
    176}