summaryrefslogtreecommitdiffstats
path: root/sound/core/seq/seq_ports.h
blob: b111382f697aa6c6ce7b9bc0d2ff68deda804855 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 *   ALSA sequencer Ports 
 *   Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
 */
#ifndef __SND_SEQ_PORTS_H
#define __SND_SEQ_PORTS_H

#include <sound/seq_kernel.h>
#include "seq_lock.h"

/* list of 'exported' ports */

/* Client ports that are not exported are still accessible, but are
 anonymous ports. 
 
 If a port supports SUBSCRIPTION, that port can send events to all
 subscribersto a special address, with address
 (queue==SNDRV_SEQ_ADDRESS_SUBSCRIBERS). The message is then send to all
 recipients that are registered in the subscription list. A typical
 application for these SUBSCRIPTION events is handling of incoming MIDI
 data. The port doesn't 'know' what other clients are interested in this
 message. If for instance a MIDI recording application would like to receive
 the events from that port, it will first have to subscribe with that port.
 
*/

struct snd_seq_subscribers {
	struct snd_seq_port_subscribe info;	/* additional info */
	struct list_head src_list;	/* link of sources */
	struct list_head dest_list;	/* link of destinations */
	atomic_t ref_count;
};

struct snd_seq_port_subs_info {
	struct list_head list_head;	/* list of subscribed ports */
	unsigned int count;		/* count of subscribers */
	unsigned int exclusive: 1;	/* exclusive mode */
	struct rw_semaphore list_mutex;
	rwlock_t list_lock;
	int (*open)(void *private_data, struct snd_seq_port_subscribe *info);
	int (*close)(void *private_data, struct snd_seq_port_subscribe *info);
};

/* context for converting from legacy control event to UMP packet */
struct snd_seq_ump_midi2_bank {
	bool rpn_set;
	bool nrpn_set;
	bool bank_set;
	unsigned char cc_rpn_msb, cc_rpn_lsb;
	unsigned char cc_nrpn_msb, cc_nrpn_lsb;
	unsigned char cc_data_msb, cc_data_lsb;
	unsigned char cc_bank_msb, cc_bank_lsb;
};

struct snd_seq_client_port {

	struct snd_seq_addr addr;	/* client/port number */
	struct module *owner;		/* owner of this port */
	char name[64];			/* port name */	
	struct list_head list;		/* port list */
	snd_use_lock_t use_lock;

	/* subscribers */
	struct snd_seq_port_subs_info c_src;	/* read (sender) list */
	struct snd_seq_port_subs_info c_dest;	/* write (dest) list */

	int (*event_input)(struct snd_seq_event *ev, int direct, void *private_data,
			   int atomic, int hop);
	void (*private_free)(void *private_data);
	void *private_data;
	unsigned int closing : 1;
	unsigned int timestamping: 1;
	unsigned int time_real: 1;
	int time_queue;
	
	/* capability, inport, output, sync */
	unsigned int capability;	/* port capability bits */
	unsigned int type;		/* port type bits */

	/* supported channels */
	int midi_channels;
	int midi_voices;
	int synth_voices;
		
	/* UMP direction and group */
	unsigned char direction;
	unsigned char ump_group;

#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
	struct snd_seq_ump_midi2_bank midi2_bank[16]; /* per channel */
#endif
};

struct snd_seq_client;

/* return pointer to port structure and lock port */
struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client, int num);

/* search for next port - port is locked if found */
struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *client,
						       struct snd_seq_port_info *pinfo);

/* unlock the port */
#define snd_seq_port_unlock(port) snd_use_lock_free(&(port)->use_lock)

/* create a port, port number or a negative error code is returned */
int snd_seq_create_port(struct snd_seq_client *client, int port_index,
			struct snd_seq_client_port **port_ret);

/* delete a port */
int snd_seq_delete_port(struct snd_seq_client *client, int port);

/* delete all ports */
int snd_seq_delete_all_ports(struct snd_seq_client *client);

/* set port info fields */
int snd_seq_set_port_info(struct snd_seq_client_port *port,
			  struct snd_seq_port_info *info);

/* get port info fields */
int snd_seq_get_port_info(struct snd_seq_client_port *port,
			  struct snd_seq_port_info *info);

/* add subscriber to subscription list */
int snd_seq_port_connect(struct snd_seq_client *caller,
			 struct snd_seq_client *s, struct snd_seq_client_port *sp,
			 struct snd_seq_client *d, struct snd_seq_client_port *dp,
			 struct snd_seq_port_subscribe *info);

/* remove subscriber from subscription list */ 
int snd_seq_port_disconnect(struct snd_seq_client *caller,
			    struct snd_seq_client *s, struct snd_seq_client_port *sp,
			    struct snd_seq_client *d, struct snd_seq_client_port *dp,
			    struct snd_seq_port_subscribe *info);

/* subscribe port */
int snd_seq_port_subscribe(struct snd_seq_client_port *port,
			   struct snd_seq_port_subscribe *info);

/* get matched subscriber */
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