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