@@ -35,6 +35,14 @@ struct snd_usb_iface_ref {
3535 struct list_head list ;
3636};
3737
38+ /* clock refcounting */
39+ struct snd_usb_clock_ref {
40+ unsigned char clock ;
41+ atomic_t locked ;
42+ int rate ;
43+ struct list_head list ;
44+ };
45+
3846/*
3947 * snd_usb_endpoint is a model that abstracts everything related to an
4048 * USB endpoint and its streaming.
@@ -591,6 +599,25 @@ iface_ref_find(struct snd_usb_audio *chip, int iface)
591599 return ip ;
592600}
593601
602+ /* Similarly, a refcount object for clock */
603+ static struct snd_usb_clock_ref *
604+ clock_ref_find (struct snd_usb_audio * chip , int clock )
605+ {
606+ struct snd_usb_clock_ref * ref ;
607+
608+ list_for_each_entry (ref , & chip -> clock_ref_list , list )
609+ if (ref -> clock == clock )
610+ return ref ;
611+
612+ ref = kzalloc (sizeof (* ref ), GFP_KERNEL );
613+ if (!ref )
614+ return NULL ;
615+ ref -> clock = clock ;
616+ atomic_set (& ref -> locked , 0 );
617+ list_add_tail (& ref -> list , & chip -> clock_ref_list );
618+ return ref ;
619+ }
620+
594621/*
595622 * Get the existing endpoint object corresponding EP
596623 * Returns NULL if not present.
@@ -768,6 +795,14 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip,
768795 goto unlock ;
769796 }
770797
798+ if (fp -> protocol != UAC_VERSION_1 ) {
799+ ep -> clock_ref = clock_ref_find (chip , fp -> clock );
800+ if (!ep -> clock_ref ) {
801+ ep = NULL ;
802+ goto unlock ;
803+ }
804+ }
805+
771806 ep -> cur_audiofmt = fp ;
772807 ep -> cur_channels = fp -> channels ;
773808 ep -> cur_rate = params_rate (params );
@@ -777,7 +812,6 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip,
777812 ep -> cur_period_frames = params_period_size (params );
778813 ep -> cur_period_bytes = ep -> cur_period_frames * ep -> cur_frame_bytes ;
779814 ep -> cur_buffer_periods = params_periods (params );
780- ep -> cur_clock = fp -> clock ;
781815
782816 if (ep -> type == SND_USB_ENDPOINT_TYPE_SYNC )
783817 endpoint_set_syncinterval (chip , ep );
@@ -894,8 +928,8 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip,
894928 ep -> altsetting = 0 ;
895929 ep -> cur_audiofmt = NULL ;
896930 ep -> cur_rate = 0 ;
897- ep -> cur_clock = 0 ;
898931 ep -> iface_ref = NULL ;
932+ ep -> clock_ref = NULL ;
899933 usb_audio_dbg (chip , "EP 0x%x closed\n" , ep -> ep_num );
900934 }
901935 mutex_unlock (& chip -> mutex );
@@ -907,6 +941,8 @@ void snd_usb_endpoint_suspend(struct snd_usb_endpoint *ep)
907941 ep -> need_setup = true;
908942 if (ep -> iface_ref )
909943 ep -> iface_ref -> need_setup = true;
944+ if (ep -> clock_ref )
945+ ep -> clock_ref -> rate = 0 ;
910946}
911947
912948/*
@@ -1314,6 +1350,33 @@ static int snd_usb_endpoint_set_params(struct snd_usb_audio *chip,
13141350 return 0 ;
13151351}
13161352
1353+ static int init_sample_rate (struct snd_usb_audio * chip ,
1354+ struct snd_usb_endpoint * ep )
1355+ {
1356+ struct snd_usb_clock_ref * clock = ep -> clock_ref ;
1357+ int err ;
1358+
1359+ if (clock ) {
1360+ if (atomic_read (& clock -> locked ))
1361+ return 0 ;
1362+ if (clock -> rate == ep -> cur_rate )
1363+ return 0 ;
1364+ if (clock -> rate && clock -> rate != ep -> cur_rate ) {
1365+ usb_audio_dbg (chip , "Mismatched sample rate %d vs %d for EP 0x%x\n" ,
1366+ clock -> rate , ep -> cur_rate , ep -> ep_num );
1367+ return - EINVAL ;
1368+ }
1369+ }
1370+
1371+ err = snd_usb_init_sample_rate (chip , ep -> cur_audiofmt , ep -> cur_rate );
1372+ if (err < 0 )
1373+ return err ;
1374+
1375+ if (clock )
1376+ clock -> rate = ep -> cur_rate ;
1377+ return 0 ;
1378+ }
1379+
13171380/*
13181381 * snd_usb_endpoint_configure: Configure the endpoint
13191382 *
@@ -1343,8 +1406,7 @@ int snd_usb_endpoint_configure(struct snd_usb_audio *chip,
13431406 * to update at each EP configuration
13441407 */
13451408 if (ep -> cur_audiofmt -> protocol == UAC_VERSION_1 ) {
1346- err = snd_usb_init_sample_rate (chip , ep -> cur_audiofmt ,
1347- ep -> cur_rate );
1409+ err = init_sample_rate (chip , ep );
13481410 if (err < 0 )
13491411 goto unlock ;
13501412 }
@@ -1374,7 +1436,7 @@ int snd_usb_endpoint_configure(struct snd_usb_audio *chip,
13741436 if (err < 0 )
13751437 goto unlock ;
13761438
1377- err = snd_usb_init_sample_rate (chip , ep -> cur_audiofmt , ep -> cur_rate );
1439+ err = init_sample_rate (chip , ep );
13781440 if (err < 0 )
13791441 goto unlock ;
13801442
@@ -1407,15 +1469,15 @@ int snd_usb_endpoint_configure(struct snd_usb_audio *chip,
14071469/* get the current rate set to the given clock by any endpoint */
14081470int snd_usb_endpoint_get_clock_rate (struct snd_usb_audio * chip , int clock )
14091471{
1410- struct snd_usb_endpoint * ep ;
1472+ struct snd_usb_clock_ref * ref ;
14111473 int rate = 0 ;
14121474
14131475 if (!clock )
14141476 return 0 ;
14151477 mutex_lock (& chip -> mutex );
1416- list_for_each_entry (ep , & chip -> ep_list , list ) {
1417- if (ep -> cur_clock == clock && ep -> cur_rate ) {
1418- rate = ep -> cur_rate ;
1478+ list_for_each_entry (ref , & chip -> clock_ref_list , list ) {
1479+ if (ref -> clock == clock ) {
1480+ rate = ref -> rate ;
14191481 break ;
14201482 }
14211483 }
@@ -1456,6 +1518,9 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
14561518 if (atomic_inc_return (& ep -> running ) != 1 )
14571519 return 0 ;
14581520
1521+ if (ep -> clock_ref )
1522+ atomic_inc (& ep -> clock_ref -> locked );
1523+
14591524 ep -> active_mask = 0 ;
14601525 ep -> unlink_mask = 0 ;
14611526 ep -> phase = 0 ;
@@ -1565,6 +1630,9 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, bool keep_pending)
15651630 if (ep -> sync_source )
15661631 WRITE_ONCE (ep -> sync_source -> sync_sink , NULL );
15671632 stop_urbs (ep , false, keep_pending );
1633+ if (ep -> clock_ref )
1634+ if (!atomic_dec_return (& ep -> clock_ref -> locked ))
1635+ ep -> clock_ref -> rate = 0 ;
15681636 }
15691637}
15701638
@@ -1591,12 +1659,16 @@ void snd_usb_endpoint_free_all(struct snd_usb_audio *chip)
15911659{
15921660 struct snd_usb_endpoint * ep , * en ;
15931661 struct snd_usb_iface_ref * ip , * in ;
1662+ struct snd_usb_clock_ref * cp , * cn ;
15941663
15951664 list_for_each_entry_safe (ep , en , & chip -> ep_list , list )
15961665 kfree (ep );
15971666
15981667 list_for_each_entry_safe (ip , in , & chip -> iface_ref_list , list )
15991668 kfree (ip );
1669+
1670+ list_for_each_entry_safe (cp , cn , & chip -> clock_ref_list , list )
1671+ kfree (ip );
16001672}
16011673
16021674/*
0 commit comments