@@ -173,10 +173,6 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
173173}
174174
175175/* */
176- enum group_type {
177- SRC_LIST , DEST_LIST
178- };
179-
180176static int subscribe_port (struct snd_seq_client * client ,
181177 struct snd_seq_client_port * port ,
182178 struct snd_seq_port_subs_info * grp ,
@@ -203,14 +199,28 @@ static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr,
203199 return NULL ;
204200}
205201
202+ static void delete_and_unsubscribe_port (struct snd_seq_client * client ,
203+ struct snd_seq_client_port * port ,
204+ struct snd_seq_subscribers * subs ,
205+ bool is_src , bool ack );
206+
207+ static inline struct snd_seq_subscribers *
208+ get_subscriber (struct list_head * p , bool is_src )
209+ {
210+ if (is_src )
211+ return list_entry (p , struct snd_seq_subscribers , src_list );
212+ else
213+ return list_entry (p , struct snd_seq_subscribers , dest_list );
214+ }
215+
206216/*
207217 * remove all subscribers on the list
208218 * this is called from port_delete, for each src and dest list.
209219 */
210220static void clear_subscriber_list (struct snd_seq_client * client ,
211221 struct snd_seq_client_port * port ,
212222 struct snd_seq_port_subs_info * grp ,
213- int grptype )
223+ int is_src )
214224{
215225 struct list_head * p , * n ;
216226
@@ -219,37 +229,28 @@ static void clear_subscriber_list(struct snd_seq_client *client,
219229 struct snd_seq_client * c ;
220230 struct snd_seq_client_port * aport ;
221231
222- if ( grptype == SRC_LIST ) {
223- subs = list_entry ( p , struct snd_seq_subscribers , src_list );
232+ subs = get_subscriber ( p , is_src );
233+ if ( is_src )
224234 aport = get_client_port (& subs -> info .dest , & c );
225- } else {
226- subs = list_entry (p , struct snd_seq_subscribers , dest_list );
235+ else
227236 aport = get_client_port (& subs -> info .sender , & c );
228- }
229- list_del (p );
230- unsubscribe_port (client , port , grp , & subs -> info , 0 );
237+ delete_and_unsubscribe_port (client , port , subs , is_src , false);
238+
231239 if (!aport ) {
232240 /* looks like the connected port is being deleted.
233241 * we decrease the counter, and when both ports are deleted
234242 * remove the subscriber info
235243 */
236244 if (atomic_dec_and_test (& subs -> ref_count ))
237245 kfree (subs );
238- } else {
239- /* ok we got the connected port */
240- struct snd_seq_port_subs_info * agrp ;
241- agrp = (grptype == SRC_LIST ) ? & aport -> c_dest : & aport -> c_src ;
242- down_write (& agrp -> list_mutex );
243- if (grptype == SRC_LIST )
244- list_del (& subs -> dest_list );
245- else
246- list_del (& subs -> src_list );
247- up_write (& agrp -> list_mutex );
248- unsubscribe_port (c , aport , agrp , & subs -> info , 1 );
249- kfree (subs );
250- snd_seq_port_unlock (aport );
251- snd_seq_client_unlock (c );
246+ continue ;
252247 }
248+
249+ /* ok we got the connected port */
250+ delete_and_unsubscribe_port (c , aport , subs , !is_src , true);
251+ kfree (subs );
252+ snd_seq_port_unlock (aport );
253+ snd_seq_client_unlock (c );
253254 }
254255}
255256
@@ -262,8 +263,8 @@ static int port_delete(struct snd_seq_client *client,
262263 snd_use_lock_sync (& port -> use_lock );
263264
264265 /* clear subscribers info */
265- clear_subscriber_list (client , port , & port -> c_src , SRC_LIST );
266- clear_subscriber_list (client , port , & port -> c_dest , DEST_LIST );
266+ clear_subscriber_list (client , port , & port -> c_src , true );
267+ clear_subscriber_list (client , port , & port -> c_dest , false );
267268
268269 if (port -> private_free )
269270 port -> private_free (port -> private_data );
@@ -479,85 +480,120 @@ static int match_subs_info(struct snd_seq_port_subscribe *r,
479480 return 0 ;
480481}
481482
482-
483- /* connect two ports */
484- int snd_seq_port_connect (struct snd_seq_client * connector ,
485- struct snd_seq_client * src_client ,
486- struct snd_seq_client_port * src_port ,
487- struct snd_seq_client * dest_client ,
488- struct snd_seq_client_port * dest_port ,
489- struct snd_seq_port_subscribe * info )
483+ static int check_and_subscribe_port (struct snd_seq_client * client ,
484+ struct snd_seq_client_port * port ,
485+ struct snd_seq_subscribers * subs ,
486+ bool is_src , bool exclusive , bool ack )
490487{
491- struct snd_seq_port_subs_info * src = & src_port -> c_src ;
492- struct snd_seq_port_subs_info * dest = & dest_port -> c_dest ;
493- struct snd_seq_subscribers * subs , * s ;
494- int err , src_called = 0 ;
495- unsigned long flags ;
496- int exclusive ;
488+ struct snd_seq_port_subs_info * grp ;
489+ struct list_head * p ;
490+ struct snd_seq_subscribers * s ;
491+ int err ;
497492
498- subs = kzalloc (sizeof (* subs ), GFP_KERNEL );
499- if (! subs )
500- return - ENOMEM ;
501-
502- subs -> info = * info ;
503- atomic_set (& subs -> ref_count , 2 );
504-
505- down_write (& src -> list_mutex );
506- down_write_nested (& dest -> list_mutex , SINGLE_DEPTH_NESTING );
507-
508- exclusive = info -> flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE ? 1 : 0 ;
493+ grp = is_src ? & port -> c_src : & port -> c_dest ;
509494 err = - EBUSY ;
495+ down_write (& grp -> list_mutex );
510496 if (exclusive ) {
511- if (! list_empty (& src -> list_head ) || ! list_empty ( & dest -> list_head ))
497+ if (!list_empty (& grp -> list_head ))
512498 goto __error ;
513499 } else {
514- if (src -> exclusive || dest -> exclusive )
500+ if (grp -> exclusive )
515501 goto __error ;
516502 /* check whether already exists */
517- list_for_each_entry (s , & src -> list_head , src_list ) {
518- if (match_subs_info (info , & s -> info ))
519- goto __error ;
520- }
521- list_for_each_entry (s , & dest -> list_head , dest_list ) {
522- if (match_subs_info (info , & s -> info ))
503+ list_for_each (p , & grp -> list_head ) {
504+ s = get_subscriber (p , is_src );
505+ if (match_subs_info (& subs -> info , & s -> info ))
523506 goto __error ;
524507 }
525508 }
526509
527- if ((err = subscribe_port (src_client , src_port , src , info ,
528- connector -> number != src_client -> number )) < 0 )
529- goto __error ;
530- src_called = 1 ;
531-
532- if ((err = subscribe_port (dest_client , dest_port , dest , info ,
533- connector -> number != dest_client -> number )) < 0 )
510+ err = subscribe_port (client , port , grp , & subs -> info , ack );
511+ if (err < 0 ) {
512+ grp -> exclusive = 0 ;
534513 goto __error ;
514+ }
535515
536516 /* add to list */
537- write_lock_irqsave (& src -> list_lock , flags );
538- // write_lock(&dest->list_lock); // no other lock yet
539- list_add_tail (& subs -> src_list , & src -> list_head );
540- list_add_tail (& subs -> dest_list , & dest -> list_head );
541- // write_unlock(&dest->list_lock); // no other lock yet
542- write_unlock_irqrestore (& src -> list_lock , flags );
517+ write_lock_irq (& grp -> list_lock );
518+ if (is_src )
519+ list_add_tail (& subs -> src_list , & grp -> list_head );
520+ else
521+ list_add_tail (& subs -> dest_list , & grp -> list_head );
522+ grp -> exclusive = exclusive ;
523+ atomic_inc (& subs -> ref_count );
524+ write_unlock_irq (& grp -> list_lock );
525+ err = 0 ;
526+
527+ __error :
528+ up_write (& grp -> list_mutex );
529+ return err ;
530+ }
543531
544- src -> exclusive = dest -> exclusive = exclusive ;
532+ static void delete_and_unsubscribe_port (struct snd_seq_client * client ,
533+ struct snd_seq_client_port * port ,
534+ struct snd_seq_subscribers * subs ,
535+ bool is_src , bool ack )
536+ {
537+ struct snd_seq_port_subs_info * grp ;
538+
539+ grp = is_src ? & port -> c_src : & port -> c_dest ;
540+ down_write (& grp -> list_mutex );
541+ write_lock_irq (& grp -> list_lock );
542+ if (is_src )
543+ list_del (& subs -> src_list );
544+ else
545+ list_del (& subs -> dest_list );
546+ grp -> exclusive = 0 ;
547+ write_unlock_irq (& grp -> list_lock );
548+ up_write (& grp -> list_mutex );
549+
550+ unsubscribe_port (client , port , grp , & subs -> info , ack );
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 ;
545586
546- up_write (& dest -> list_mutex );
547- up_write (& src -> list_mutex );
548587 return 0 ;
549588
550- __error :
551- if ( src_called )
552- unsubscribe_port ( src_client , src_port , src , info ,
553- connector -> number != src_client -> number );
589+ error_dest :
590+ delete_and_unsubscribe_port ( src_client , src_port , subs , true,
591+ connector -> number != src_client -> number );
592+ error :
554593 kfree (subs );
555- up_write (& dest -> list_mutex );
556- up_write (& src -> list_mutex );
557594 return err ;
558595}
559596
560-
561597/* remove the connection */
562598int snd_seq_port_disconnect (struct snd_seq_client * connector ,
563599 struct snd_seq_client * src_client ,
@@ -567,37 +603,28 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
567603 struct snd_seq_port_subscribe * info )
568604{
569605 struct snd_seq_port_subs_info * src = & src_port -> c_src ;
570- struct snd_seq_port_subs_info * dest = & dest_port -> c_dest ;
571606 struct snd_seq_subscribers * subs ;
572607 int err = - ENOENT ;
573- unsigned long flags ;
574608
575609 down_write (& src -> list_mutex );
576- down_write_nested (& dest -> list_mutex , SINGLE_DEPTH_NESTING );
577-
578610 /* look for the connection */
579611 list_for_each_entry (subs , & src -> list_head , src_list ) {
580612 if (match_subs_info (info , & subs -> info )) {
581- write_lock_irqsave (& src -> list_lock , flags );
582- // write_lock(&dest->list_lock); // no lock yet
583- list_del (& subs -> src_list );
584- list_del (& subs -> dest_list );
585- // write_unlock(&dest->list_lock);
586- write_unlock_irqrestore (& src -> list_lock , flags );
587- src -> exclusive = dest -> exclusive = 0 ;
588- unsubscribe_port (src_client , src_port , src , info ,
589- connector -> number != src_client -> number );
590- unsubscribe_port (dest_client , dest_port , dest , info ,
591- connector -> number != dest_client -> number );
592- kfree (subs );
613+ atomic_dec (& subs -> ref_count ); /* mark as not ready */
593614 err = 0 ;
594615 break ;
595616 }
596617 }
597-
598- up_write (& dest -> list_mutex );
599618 up_write (& src -> list_mutex );
600- return err ;
619+ if (err < 0 )
620+ return err ;
621+
622+ delete_and_unsubscribe_port (src_client , src_port , subs , true,
623+ connector -> number != src_client -> number );
624+ delete_and_unsubscribe_port (dest_client , dest_port , subs , false,
625+ connector -> number != dest_client -> number );
626+ kfree (subs );
627+ return 0 ;
601628}
602629
603630
0 commit comments