@@ -464,6 +464,49 @@ void uac2_update(struct usbd_class_data *const c_data,
464464 }
465465}
466466
467+ /* 5.2.2 Control Request Layout: "As a general rule, when an attribute value
468+ * is set, a Control will automatically adjust the passed value to the closest
469+ * available valid value."
470+ *
471+ * The values array must be sorted ascending with at least 1 element.
472+ */
473+ static uint32_t find_closest (const uint32_t input , const uint32_t * values ,
474+ const size_t values_count )
475+ {
476+ size_t i ;
477+
478+ __ASSERT_NO_MSG (values_count );
479+
480+ for (i = 0 ; i < values_count ; i ++ ) {
481+ if (input == values [i ]) {
482+ /* Exact match */
483+ return input ;
484+ } else if (input < values [i ]) {
485+ break ;
486+ }
487+ }
488+
489+ if (i == values_count ) {
490+ /* All values are smaller than input, return largest value */
491+ return values [i - 1 ];
492+ }
493+
494+ if (i == 0 ) {
495+ /* All values are larger than input, return smallest value */
496+ return values [i ];
497+ }
498+
499+ /* At this point values[i] is larger than input and values[i - 1] is
500+ * smaller than input, find and return the one that is closer, favoring
501+ * bigger value if input is exactly in the middle between the two.
502+ */
503+ if ((values [i ] - input ) > (input - values [i - 1 ])) {
504+ return values [i - 1 ];
505+ } else {
506+ return values [i ];
507+ }
508+ }
509+
467510/* Table 5-6: 4-byte Control CUR Parameter Block */
468511static void layout3_cur_response (struct net_buf * const buf , uint16_t length ,
469512 const uint32_t value )
@@ -475,6 +518,19 @@ static void layout3_cur_response(struct net_buf *const buf, uint16_t length,
475518 net_buf_add_mem (buf , tmp , MIN (length , 4 ));
476519}
477520
521+ static int layout3_cur_request (const struct net_buf * const buf , uint32_t * out )
522+ {
523+ uint8_t tmp [4 ];
524+
525+ if (buf -> len != 4 ) {
526+ return - EINVAL ;
527+ }
528+
529+ memcpy (tmp , buf -> data , sizeof (tmp ));
530+ * out = sys_get_le32 (tmp );
531+ return 0 ;
532+ }
533+
478534/* Table 5-7: 4-byte Control RANGE Parameter Block */
479535static void layout3_range_response (struct net_buf * const buf , uint16_t length ,
480536 const uint32_t * min , const uint32_t * max ,
@@ -522,7 +578,10 @@ static int get_clock_source_request(struct usbd_class_data *const c_data,
522578 const struct usb_setup_packet * const setup ,
523579 struct net_buf * const buf )
524580{
581+ const struct device * dev = usbd_class_get_private (c_data );
582+ struct uac2_ctx * ctx = dev -> data ;
525583 const uint32_t * frequencies ;
584+ const uint32_t clock_id = CONTROL_ENTITY_ID (setup );
526585 size_t count ;
527586
528587 /* Channel Number must be zero */
@@ -533,7 +592,7 @@ static int get_clock_source_request(struct usbd_class_data *const c_data,
533592 return 0 ;
534593 }
535594
536- count = clock_frequencies (c_data , CONTROL_ENTITY_ID ( setup ) , & frequencies );
595+ count = clock_frequencies (c_data , clock_id , & frequencies );
537596
538597 if (CONTROL_SELECTOR (setup ) == CS_SAM_FREQ_CONTROL ) {
539598 if (CONTROL_ATTRIBUTE (setup ) == CUR ) {
@@ -542,10 +601,15 @@ static int get_clock_source_request(struct usbd_class_data *const c_data,
542601 frequencies [0 ]);
543602 return 0 ;
544603 }
545- /* TODO: If there is more than one frequency supported,
546- * call registered application API to determine active
547- * sample rate.
548- */
604+
605+ if (ctx -> ops -> get_sample_rate ) {
606+ uint32_t hz ;
607+
608+ hz = ctx -> ops -> get_sample_rate (dev , clock_id ,
609+ ctx -> user_data );
610+ layout3_cur_response (buf , setup -> wLength , hz );
611+ return 0 ;
612+ }
549613 } else if (CONTROL_ATTRIBUTE (setup ) == RANGE ) {
550614 layout3_range_response (buf , setup -> wLength , frequencies ,
551615 frequencies , NULL , count );
@@ -560,6 +624,88 @@ static int get_clock_source_request(struct usbd_class_data *const c_data,
560624 return 0 ;
561625}
562626
627+ static int set_clock_source_request (struct usbd_class_data * const c_data ,
628+ const struct usb_setup_packet * const setup ,
629+ const struct net_buf * const buf )
630+ {
631+ const struct device * dev = usbd_class_get_private (c_data );
632+ struct uac2_ctx * ctx = dev -> data ;
633+ const uint32_t * frequencies ;
634+ const uint32_t clock_id = CONTROL_ENTITY_ID (setup );
635+ size_t count ;
636+
637+ /* Channel Number must be zero */
638+ if (CONTROL_CHANNEL_NUMBER (setup ) != 0 ) {
639+ LOG_DBG ("Clock source control with channel %d" ,
640+ CONTROL_CHANNEL_NUMBER (setup ));
641+ errno = - EINVAL ;
642+ return 0 ;
643+ }
644+
645+ count = clock_frequencies (c_data , clock_id , & frequencies );
646+
647+ if (CONTROL_SELECTOR (setup ) == CS_SAM_FREQ_CONTROL ) {
648+ if (CONTROL_ATTRIBUTE (setup ) == CUR ) {
649+ uint32_t requested , hz ;
650+ int err ;
651+
652+ err = layout3_cur_request (buf , & requested );
653+ if (err ) {
654+ errno = err ;
655+ return 0 ;
656+ }
657+
658+ hz = find_closest (requested , frequencies , count );
659+
660+ if (ctx -> ops -> set_sample_rate == NULL ) {
661+ /* The set_sample_rate() callback is optional
662+ * if there is only one supported sample rate.
663+ */
664+ if (count > 1 ) {
665+ errno = - ENOTSUP ;
666+ }
667+ return 0 ;
668+ }
669+
670+ err = ctx -> ops -> set_sample_rate (dev , clock_id , hz ,
671+ ctx -> user_data );
672+ if (err ) {
673+ errno = err ;
674+ }
675+
676+ return 0 ;
677+ }
678+ } else {
679+ LOG_DBG ("Unhandled clock control selector 0x%02x" ,
680+ CONTROL_SELECTOR (setup ));
681+ }
682+
683+ errno = - ENOTSUP ;
684+ return 0 ;
685+ }
686+
687+ static int uac2_control_to_dev (struct usbd_class_data * const c_data ,
688+ const struct usb_setup_packet * const setup ,
689+ const struct net_buf * const buf )
690+ {
691+ entity_type_t entity_type ;
692+
693+ if (CONTROL_ATTRIBUTE (setup ) != CUR ) {
694+ errno = - ENOTSUP ;
695+ return 0 ;
696+ }
697+
698+ if (setup -> bmRequestType == SET_CLASS_REQUEST_TYPE ) {
699+ entity_type = id_type (c_data , CONTROL_ENTITY_ID (setup ));
700+ if (entity_type == ENTITY_TYPE_CLOCK_SOURCE ) {
701+ return set_clock_source_request (c_data , setup , buf );
702+ }
703+ }
704+
705+ errno = - ENOTSUP ;
706+ return 0 ;
707+ }
708+
563709static int uac2_control_to_host (struct usbd_class_data * const c_data ,
564710 const struct usb_setup_packet * const setup ,
565711 struct net_buf * const buf )
@@ -720,6 +866,7 @@ static int uac2_init(struct usbd_class_data *const c_data)
720866
721867struct usbd_class_api uac2_api = {
722868 .update = uac2_update ,
869+ .control_to_dev = uac2_control_to_dev ,
723870 .control_to_host = uac2_control_to_host ,
724871 .request = uac2_request ,
725872 .sof = uac2_sof ,
0 commit comments