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