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