This source file includes following definitions.
- dummy_input
- dummy_free
- create_port
- register_client
- delete_client
- alsa_seq_dummy_init
- alsa_seq_dummy_exit
1
2
3
4
5
6
7 #include <linux/init.h>
8 #include <linux/slab.h>
9 #include <linux/module.h>
10 #include <sound/core.h>
11 #include "seq_clientmgr.h"
12 #include <sound/initval.h>
13 #include <sound/asoundef.h>
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 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
49 MODULE_DESCRIPTION("ALSA sequencer MIDI-through client");
50 MODULE_LICENSE("GPL");
51 MODULE_ALIAS("snd-seq-client-" __stringify(SNDRV_SEQ_CLIENT_DUMMY));
52
53 static int ports = 1;
54 static bool duplex;
55
56 module_param(ports, int, 0444);
57 MODULE_PARM_DESC(ports, "number of ports to be created");
58 module_param(duplex, bool, 0444);
59 MODULE_PARM_DESC(duplex, "create DUPLEX ports");
60
61 struct snd_seq_dummy_port {
62 int client;
63 int port;
64 int duplex;
65 int connect;
66 };
67
68 static int my_client = -1;
69
70
71
72
73 static int
74 dummy_input(struct snd_seq_event *ev, int direct, void *private_data,
75 int atomic, int hop)
76 {
77 struct snd_seq_dummy_port *p;
78 struct snd_seq_event tmpev;
79
80 p = private_data;
81 if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM ||
82 ev->type == SNDRV_SEQ_EVENT_KERNEL_ERROR)
83 return 0;
84 tmpev = *ev;
85 if (p->duplex)
86 tmpev.source.port = p->connect;
87 else
88 tmpev.source.port = p->port;
89 tmpev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
90 return snd_seq_kernel_client_dispatch(p->client, &tmpev, atomic, hop);
91 }
92
93
94
95
96 static void
97 dummy_free(void *private_data)
98 {
99 kfree(private_data);
100 }
101
102
103
104
105 static struct snd_seq_dummy_port __init *
106 create_port(int idx, int type)
107 {
108 struct snd_seq_port_info pinfo;
109 struct snd_seq_port_callback pcb;
110 struct snd_seq_dummy_port *rec;
111
112 if ((rec = kzalloc(sizeof(*rec), GFP_KERNEL)) == NULL)
113 return NULL;
114
115 rec->client = my_client;
116 rec->duplex = duplex;
117 rec->connect = 0;
118 memset(&pinfo, 0, sizeof(pinfo));
119 pinfo.addr.client = my_client;
120 if (duplex)
121 sprintf(pinfo.name, "Midi Through Port-%d:%c", idx,
122 (type ? 'B' : 'A'));
123 else
124 sprintf(pinfo.name, "Midi Through Port-%d", idx);
125 pinfo.capability = SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
126 pinfo.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
127 if (duplex)
128 pinfo.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
129 pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
130 | SNDRV_SEQ_PORT_TYPE_SOFTWARE
131 | SNDRV_SEQ_PORT_TYPE_PORT;
132 memset(&pcb, 0, sizeof(pcb));
133 pcb.owner = THIS_MODULE;
134 pcb.event_input = dummy_input;
135 pcb.private_free = dummy_free;
136 pcb.private_data = rec;
137 pinfo.kernel = &pcb;
138 if (snd_seq_kernel_client_ctl(my_client, SNDRV_SEQ_IOCTL_CREATE_PORT, &pinfo) < 0) {
139 kfree(rec);
140 return NULL;
141 }
142 rec->port = pinfo.addr.port;
143 return rec;
144 }
145
146
147
148
149 static int __init
150 register_client(void)
151 {
152 struct snd_seq_dummy_port *rec1, *rec2;
153 int i;
154
155 if (ports < 1) {
156 pr_err("ALSA: seq_dummy: invalid number of ports %d\n", ports);
157 return -EINVAL;
158 }
159
160
161 my_client = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_DUMMY,
162 "Midi Through");
163 if (my_client < 0)
164 return my_client;
165
166
167 for (i = 0; i < ports; i++) {
168 rec1 = create_port(i, 0);
169 if (rec1 == NULL) {
170 snd_seq_delete_kernel_client(my_client);
171 return -ENOMEM;
172 }
173 if (duplex) {
174 rec2 = create_port(i, 1);
175 if (rec2 == NULL) {
176 snd_seq_delete_kernel_client(my_client);
177 return -ENOMEM;
178 }
179 rec1->connect = rec2->port;
180 rec2->connect = rec1->port;
181 }
182 }
183
184 return 0;
185 }
186
187
188
189
190 static void __exit
191 delete_client(void)
192 {
193 if (my_client >= 0)
194 snd_seq_delete_kernel_client(my_client);
195 }
196
197
198
199
200
201 static int __init alsa_seq_dummy_init(void)
202 {
203 return register_client();
204 }
205
206 static void __exit alsa_seq_dummy_exit(void)
207 {
208 delete_client();
209 }
210
211 module_init(alsa_seq_dummy_init)
212 module_exit(alsa_seq_dummy_exit)