Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: gadget: function: f_uac1: implement get_alt()

After commit 7e4da3fcf7c9 ("usb: gadget: composite:
Test get_alt() presence instead of set_alt()") f_uac1
function became broken because it doesn't have
get_alt() callback implementation and composite
framework never set altsetting 1 for audiostreaming
interface. On host site it looks like:

[424339.017711] 21:1:1: usb_set_interface failed (-32)

Since host can't set altsetting 1, it can't start
playing audio.

In order to fix it implemented get_alt along with
minor improvements (error conditions checking)
similar to what existing f_uac2 has.

Cc: Krzysztof Opasiak <k.opasiak@samsung.com>
Signed-off-by: Ruslan Bilovol <ruslan.bilovol@gmail.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>

authored by

Ruslan Bilovol and committed by
Felipe Balbi
1fc4926d d423b965

+39 -1
+39 -1
drivers/usb/gadget/function/f_uac1.c
··· 277 277 struct f_audio { 278 278 struct gaudio card; 279 279 280 + u8 ac_intf, ac_alt; 281 + u8 as_intf, as_alt; 282 + 280 283 /* endpoints handle full and/or high speeds */ 281 284 struct usb_ep *out_ep; 282 285 ··· 589 586 req_count = opts->req_count; 590 587 audio_buf_size = opts->audio_buf_size; 591 588 592 - if (intf == 1) { 589 + /* No i/f has more than 2 alt settings */ 590 + if (alt > 1) { 591 + ERROR(cdev, "%s:%d Error!\n", __func__, __LINE__); 592 + return -EINVAL; 593 + } 594 + 595 + if (intf == audio->ac_intf) { 596 + /* Control I/f has only 1 AltSetting - 0 */ 597 + if (alt) { 598 + ERROR(cdev, "%s:%d Error!\n", __func__, __LINE__); 599 + return -EINVAL; 600 + } 601 + return 0; 602 + } else if (intf == audio->as_intf) { 593 603 if (alt == 1) { 594 604 err = config_ep_by_speed(cdev->gadget, f, out_ep); 595 605 if (err) ··· 647 631 schedule_work(&audio->playback_work); 648 632 } 649 633 } 634 + audio->as_alt = alt; 650 635 } 651 636 652 637 return err; 638 + } 639 + 640 + static int f_audio_get_alt(struct usb_function *f, unsigned intf) 641 + { 642 + struct f_audio *audio = func_to_audio(f); 643 + struct usb_composite_dev *cdev = f->config->cdev; 644 + 645 + if (intf == audio->ac_intf) 646 + return audio->ac_alt; 647 + else if (intf == audio->as_intf) 648 + return audio->as_alt; 649 + else 650 + ERROR(cdev, "%s:%d Invalid Interface %d!\n", 651 + __func__, __LINE__, intf); 652 + 653 + return -EINVAL; 653 654 } 654 655 655 656 static void f_audio_disable(struct usb_function *f) ··· 735 702 if (status < 0) 736 703 goto fail; 737 704 ac_interface_desc.bInterfaceNumber = status; 705 + audio->ac_intf = status; 706 + audio->ac_alt = 0; 738 707 739 708 status = usb_interface_id(c, f); 740 709 if (status < 0) 741 710 goto fail; 742 711 as_interface_alt_0_desc.bInterfaceNumber = status; 743 712 as_interface_alt_1_desc.bInterfaceNumber = status; 713 + audio->as_intf = status; 714 + audio->as_alt = 0; 744 715 745 716 status = -ENODEV; 746 717 ··· 1003 966 audio->card.func.bind = f_audio_bind; 1004 967 audio->card.func.unbind = f_audio_unbind; 1005 968 audio->card.func.set_alt = f_audio_set_alt; 969 + audio->card.func.get_alt = f_audio_get_alt; 1006 970 audio->card.func.setup = f_audio_setup; 1007 971 audio->card.func.disable = f_audio_disable; 1008 972 audio->card.func.free_func = f_audio_free;