diff options
author | Andrzej Pietrasiewicz <andrzej.p@samsung.com> | 2014-07-22 13:58:43 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2014-08-20 15:05:21 -0400 |
commit | 0854611a19ae4dfa56569e6f640017a1d2dd3312 (patch) | |
tree | 5a505fe0a5180c66ceff90ca3539471fbada5ade | |
parent | bcec9784dd78abfa9d8ca8b7144f6e37ea6abfd5 (diff) |
usb: gadget: f_uac1: add configfs support
Add support for using f_uac1 function as a component of a gadget
composed with configfs.
Tested-by: Sebastian Reimers <sebastian.reimers@googlemail.com>
Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r-- | Documentation/ABI/testing/configfs-usb-gadget-uac1 | 12 | ||||
-rw-r--r-- | drivers/usb/gadget/function/f_uac1.c | 158 | ||||
-rw-r--r-- | drivers/usb/gadget/function/u_uac1.h | 7 |
3 files changed, 176 insertions, 1 deletions
diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uac1 b/Documentation/ABI/testing/configfs-usb-gadget-uac1 new file mode 100644 index 000000000000..8ba9a123316e --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-uac1 | |||
@@ -0,0 +1,12 @@ | |||
1 | What: /config/usb-gadget/gadget/functions/uac1.name | ||
2 | Date: Sep 2014 | ||
3 | KernelVersion: 3.18 | ||
4 | Description: | ||
5 | The attributes: | ||
6 | |||
7 | audio_buf_size - audio buffer size | ||
8 | fn_cap - capture pcm device file name | ||
9 | fn_cntl - control device file name | ||
10 | fn_play - playback pcm device file name | ||
11 | req_buf_size - ISO OUT endpoint request buffer size | ||
12 | req_count - ISO OUT endpoint request count | ||
diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index 9a6c7ec66757..f7b203293205 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c | |||
@@ -760,12 +760,150 @@ static int control_selector_init(struct f_audio *audio) | |||
760 | return 0; | 760 | return 0; |
761 | } | 761 | } |
762 | 762 | ||
763 | static inline struct f_uac1_opts *to_f_uac1_opts(struct config_item *item) | ||
764 | { | ||
765 | return container_of(to_config_group(item), struct f_uac1_opts, | ||
766 | func_inst.group); | ||
767 | } | ||
768 | |||
769 | CONFIGFS_ATTR_STRUCT(f_uac1_opts); | ||
770 | CONFIGFS_ATTR_OPS(f_uac1_opts); | ||
771 | |||
772 | static void f_uac1_attr_release(struct config_item *item) | ||
773 | { | ||
774 | struct f_uac1_opts *opts = to_f_uac1_opts(item); | ||
775 | |||
776 | usb_put_function_instance(&opts->func_inst); | ||
777 | } | ||
778 | |||
779 | static struct configfs_item_operations f_uac1_item_ops = { | ||
780 | .release = f_uac1_attr_release, | ||
781 | .show_attribute = f_uac1_opts_attr_show, | ||
782 | .store_attribute = f_uac1_opts_attr_store, | ||
783 | }; | ||
784 | |||
785 | #define UAC1_INT_ATTRIBUTE(name) \ | ||
786 | static ssize_t f_uac1_opts_##name##_show(struct f_uac1_opts *opts, \ | ||
787 | char *page) \ | ||
788 | { \ | ||
789 | int result; \ | ||
790 | \ | ||
791 | mutex_lock(&opts->lock); \ | ||
792 | result = sprintf(page, "%u\n", opts->name); \ | ||
793 | mutex_unlock(&opts->lock); \ | ||
794 | \ | ||
795 | return result; \ | ||
796 | } \ | ||
797 | \ | ||
798 | static ssize_t f_uac1_opts_##name##_store(struct f_uac1_opts *opts, \ | ||
799 | const char *page, size_t len) \ | ||
800 | { \ | ||
801 | int ret; \ | ||
802 | u32 num; \ | ||
803 | \ | ||
804 | mutex_lock(&opts->lock); \ | ||
805 | if (opts->refcnt) { \ | ||
806 | ret = -EBUSY; \ | ||
807 | goto end; \ | ||
808 | } \ | ||
809 | \ | ||
810 | ret = kstrtou32(page, 0, &num); \ | ||
811 | if (ret) \ | ||
812 | goto end; \ | ||
813 | \ | ||
814 | opts->name = num; \ | ||
815 | ret = len; \ | ||
816 | \ | ||
817 | end: \ | ||
818 | mutex_unlock(&opts->lock); \ | ||
819 | return ret; \ | ||
820 | } \ | ||
821 | \ | ||
822 | static struct f_uac1_opts_attribute f_uac1_opts_##name = \ | ||
823 | __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \ | ||
824 | f_uac1_opts_##name##_show, \ | ||
825 | f_uac1_opts_##name##_store) | ||
826 | |||
827 | UAC1_INT_ATTRIBUTE(req_buf_size); | ||
828 | UAC1_INT_ATTRIBUTE(req_count); | ||
829 | UAC1_INT_ATTRIBUTE(audio_buf_size); | ||
830 | |||
831 | #define UAC1_STR_ATTRIBUTE(name) \ | ||
832 | static ssize_t f_uac1_opts_##name##_show(struct f_uac1_opts *opts, \ | ||
833 | char *page) \ | ||
834 | { \ | ||
835 | int result; \ | ||
836 | \ | ||
837 | mutex_lock(&opts->lock); \ | ||
838 | result = sprintf(page, "%s\n", opts->name); \ | ||
839 | mutex_unlock(&opts->lock); \ | ||
840 | \ | ||
841 | return result; \ | ||
842 | } \ | ||
843 | \ | ||
844 | static ssize_t f_uac1_opts_##name##_store(struct f_uac1_opts *opts, \ | ||
845 | const char *page, size_t len) \ | ||
846 | { \ | ||
847 | int ret = -EBUSY; \ | ||
848 | char *tmp; \ | ||
849 | \ | ||
850 | mutex_lock(&opts->lock); \ | ||
851 | if (opts->refcnt) \ | ||
852 | goto end; \ | ||
853 | \ | ||
854 | tmp = kstrndup(page, len, GFP_KERNEL); \ | ||
855 | if (tmp) { \ | ||
856 | ret = -ENOMEM; \ | ||
857 | goto end; \ | ||
858 | } \ | ||
859 | if (opts->name##_alloc) \ | ||
860 | kfree(opts->name); \ | ||
861 | opts->name##_alloc = true; \ | ||
862 | opts->name = tmp; \ | ||
863 | ret = len; \ | ||
864 | \ | ||
865 | end: \ | ||
866 | mutex_unlock(&opts->lock); \ | ||
867 | return ret; \ | ||
868 | } \ | ||
869 | \ | ||
870 | static struct f_uac1_opts_attribute f_uac1_opts_##name = \ | ||
871 | __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \ | ||
872 | f_uac1_opts_##name##_show, \ | ||
873 | f_uac1_opts_##name##_store) | ||
874 | |||
875 | UAC1_STR_ATTRIBUTE(fn_play); | ||
876 | UAC1_STR_ATTRIBUTE(fn_cap); | ||
877 | UAC1_STR_ATTRIBUTE(fn_cntl); | ||
878 | |||
879 | static struct configfs_attribute *f_uac1_attrs[] = { | ||
880 | &f_uac1_opts_req_buf_size.attr, | ||
881 | &f_uac1_opts_req_count.attr, | ||
882 | &f_uac1_opts_audio_buf_size.attr, | ||
883 | &f_uac1_opts_fn_play.attr, | ||
884 | &f_uac1_opts_fn_cap.attr, | ||
885 | &f_uac1_opts_fn_cntl.attr, | ||
886 | NULL, | ||
887 | }; | ||
888 | |||
889 | static struct config_item_type f_uac1_func_type = { | ||
890 | .ct_item_ops = &f_uac1_item_ops, | ||
891 | .ct_attrs = f_uac1_attrs, | ||
892 | .ct_owner = THIS_MODULE, | ||
893 | }; | ||
894 | |||
763 | static void f_audio_free_inst(struct usb_function_instance *f) | 895 | static void f_audio_free_inst(struct usb_function_instance *f) |
764 | { | 896 | { |
765 | struct f_uac1_opts *opts; | 897 | struct f_uac1_opts *opts; |
766 | 898 | ||
767 | opts = container_of(f, struct f_uac1_opts, func_inst); | 899 | opts = container_of(f, struct f_uac1_opts, func_inst); |
768 | gaudio_cleanup(opts->card); | 900 | gaudio_cleanup(opts->card); |
901 | if (opts->fn_play_alloc) | ||
902 | kfree(opts->fn_play); | ||
903 | if (opts->fn_cap_alloc) | ||
904 | kfree(opts->fn_cap); | ||
905 | if (opts->fn_cntl_alloc) | ||
906 | kfree(opts->fn_cntl); | ||
769 | kfree(opts); | 907 | kfree(opts); |
770 | } | 908 | } |
771 | 909 | ||
@@ -777,16 +915,31 @@ static struct usb_function_instance *f_audio_alloc_inst(void) | |||
777 | if (!opts) | 915 | if (!opts) |
778 | return ERR_PTR(-ENOMEM); | 916 | return ERR_PTR(-ENOMEM); |
779 | 917 | ||
918 | mutex_init(&opts->lock); | ||
780 | opts->func_inst.free_func_inst = f_audio_free_inst; | 919 | opts->func_inst.free_func_inst = f_audio_free_inst; |
781 | 920 | ||
921 | config_group_init_type_name(&opts->func_inst.group, "", | ||
922 | &f_uac1_func_type); | ||
923 | |||
924 | opts->req_buf_size = UAC1_OUT_EP_MAX_PACKET_SIZE; | ||
925 | opts->req_count = UAC1_REQ_COUNT; | ||
926 | opts->audio_buf_size = UAC1_AUDIO_BUF_SIZE; | ||
927 | opts->fn_play = FILE_PCM_PLAYBACK; | ||
928 | opts->fn_cap = FILE_PCM_CAPTURE; | ||
929 | opts->fn_cntl = FILE_CONTROL; | ||
782 | return &opts->func_inst; | 930 | return &opts->func_inst; |
783 | } | 931 | } |
784 | 932 | ||
785 | static void f_audio_free(struct usb_function *f) | 933 | static void f_audio_free(struct usb_function *f) |
786 | { | 934 | { |
787 | struct f_audio *audio = func_to_audio(f); | 935 | struct f_audio *audio = func_to_audio(f); |
936 | struct f_uac1_opts *opts; | ||
788 | 937 | ||
938 | opts = container_of(f->fi, struct f_uac1_opts, func_inst); | ||
789 | kfree(audio); | 939 | kfree(audio); |
940 | mutex_lock(&opts->lock); | ||
941 | --opts->refcnt; | ||
942 | mutex_unlock(&opts->lock); | ||
790 | } | 943 | } |
791 | 944 | ||
792 | static void f_audio_unbind(struct usb_configuration *c, struct usb_function *f) | 945 | static void f_audio_unbind(struct usb_configuration *c, struct usb_function *f) |
@@ -797,6 +950,7 @@ static void f_audio_unbind(struct usb_configuration *c, struct usb_function *f) | |||
797 | static struct usb_function *f_audio_alloc(struct usb_function_instance *fi) | 950 | static struct usb_function *f_audio_alloc(struct usb_function_instance *fi) |
798 | { | 951 | { |
799 | struct f_audio *audio; | 952 | struct f_audio *audio; |
953 | struct f_uac1_opts *opts; | ||
800 | 954 | ||
801 | /* allocate and initialize one new instance */ | 955 | /* allocate and initialize one new instance */ |
802 | audio = kzalloc(sizeof(*audio), GFP_KERNEL); | 956 | audio = kzalloc(sizeof(*audio), GFP_KERNEL); |
@@ -805,6 +959,10 @@ static struct usb_function *f_audio_alloc(struct usb_function_instance *fi) | |||
805 | 959 | ||
806 | audio->card.func.name = "g_audio"; | 960 | audio->card.func.name = "g_audio"; |
807 | 961 | ||
962 | opts = container_of(fi, struct f_uac1_opts, func_inst); | ||
963 | mutex_lock(&opts->lock); | ||
964 | ++opts->refcnt; | ||
965 | mutex_unlock(&opts->lock); | ||
808 | INIT_LIST_HEAD(&audio->play_queue); | 966 | INIT_LIST_HEAD(&audio->play_queue); |
809 | spin_lock_init(&audio->lock); | 967 | spin_lock_init(&audio->lock); |
810 | 968 | ||
diff --git a/drivers/usb/gadget/function/u_uac1.h b/drivers/usb/gadget/function/u_uac1.h index 214441d96fe1..f8b17fe82efe 100644 --- a/drivers/usb/gadget/function/u_uac1.h +++ b/drivers/usb/gadget/function/u_uac1.h | |||
@@ -66,8 +66,13 @@ struct f_uac1_opts { | |||
66 | char *fn_play; | 66 | char *fn_play; |
67 | char *fn_cap; | 67 | char *fn_cap; |
68 | char *fn_cntl; | 68 | char *fn_cntl; |
69 | bool bound; | 69 | unsigned bound:1; |
70 | unsigned fn_play_alloc:1; | ||
71 | unsigned fn_cap_alloc:1; | ||
72 | unsigned fn_cntl_alloc:1; | ||
70 | struct gaudio *card; | 73 | struct gaudio *card; |
74 | struct mutex lock; | ||
75 | int refcnt; | ||
71 | }; | 76 | }; |
72 | 77 | ||
73 | int gaudio_setup(struct gaudio *card); | 78 | int gaudio_setup(struct gaudio *card); |