diff options
Diffstat (limited to 'drivers/usb/gadget/function/f_uvc.c')
-rw-r--r-- | drivers/usb/gadget/function/f_uvc.c | 136 |
1 files changed, 128 insertions, 8 deletions
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 945b3bd2ca98..76891adfba7a 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c | |||
@@ -27,10 +27,11 @@ | |||
27 | #include <media/v4l2-dev.h> | 27 | #include <media/v4l2-dev.h> |
28 | #include <media/v4l2-event.h> | 28 | #include <media/v4l2-event.h> |
29 | 29 | ||
30 | #include "u_uvc.h" | ||
30 | #include "uvc.h" | 31 | #include "uvc.h" |
32 | #include "uvc_configfs.h" | ||
31 | #include "uvc_v4l2.h" | 33 | #include "uvc_v4l2.h" |
32 | #include "uvc_video.h" | 34 | #include "uvc_video.h" |
33 | #include "u_uvc.h" | ||
34 | 35 | ||
35 | unsigned int uvc_gadget_trace_param; | 36 | unsigned int uvc_gadget_trace_param; |
36 | 37 | ||
@@ -509,6 +510,9 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) | |||
509 | break; | 510 | break; |
510 | } | 511 | } |
511 | 512 | ||
513 | if (!uvc_control_desc || !uvc_streaming_cls) | ||
514 | return ERR_PTR(-ENODEV); | ||
515 | |||
512 | /* Descriptors layout | 516 | /* Descriptors layout |
513 | * | 517 | * |
514 | * uvc_iad | 518 | * uvc_iad |
@@ -605,7 +609,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | |||
605 | 609 | ||
606 | INFO(cdev, "uvc_function_bind\n"); | 610 | INFO(cdev, "uvc_function_bind\n"); |
607 | 611 | ||
608 | opts = to_f_uvc_opts(f->fi); | 612 | opts = fi_to_f_uvc_opts(f->fi); |
609 | /* Sanity check the streaming endpoint module parameters. | 613 | /* Sanity check the streaming endpoint module parameters. |
610 | */ | 614 | */ |
611 | opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U); | 615 | opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U); |
@@ -700,10 +704,27 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | |||
700 | 704 | ||
701 | /* Copy descriptors */ | 705 | /* Copy descriptors */ |
702 | f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); | 706 | f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); |
703 | if (gadget_is_dualspeed(cdev->gadget)) | 707 | if (IS_ERR(f->fs_descriptors)) { |
708 | ret = PTR_ERR(f->fs_descriptors); | ||
709 | f->fs_descriptors = NULL; | ||
710 | goto error; | ||
711 | } | ||
712 | if (gadget_is_dualspeed(cdev->gadget)) { | ||
704 | f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH); | 713 | f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH); |
705 | if (gadget_is_superspeed(c->cdev->gadget)) | 714 | if (IS_ERR(f->hs_descriptors)) { |
715 | ret = PTR_ERR(f->hs_descriptors); | ||
716 | f->hs_descriptors = NULL; | ||
717 | goto error; | ||
718 | } | ||
719 | } | ||
720 | if (gadget_is_superspeed(c->cdev->gadget)) { | ||
706 | f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER); | 721 | f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER); |
722 | if (IS_ERR(f->ss_descriptors)) { | ||
723 | ret = PTR_ERR(f->ss_descriptors); | ||
724 | f->ss_descriptors = NULL; | ||
725 | goto error; | ||
726 | } | ||
727 | } | ||
707 | 728 | ||
708 | /* Preallocate control endpoint request. */ | 729 | /* Preallocate control endpoint request. */ |
709 | uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); | 730 | uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); |
@@ -766,27 +787,106 @@ error: | |||
766 | 787 | ||
767 | static void uvc_free_inst(struct usb_function_instance *f) | 788 | static void uvc_free_inst(struct usb_function_instance *f) |
768 | { | 789 | { |
769 | struct f_uvc_opts *opts = to_f_uvc_opts(f); | 790 | struct f_uvc_opts *opts = fi_to_f_uvc_opts(f); |
770 | 791 | ||
792 | mutex_destroy(&opts->lock); | ||
771 | kfree(opts); | 793 | kfree(opts); |
772 | } | 794 | } |
773 | 795 | ||
774 | static struct usb_function_instance *uvc_alloc_inst(void) | 796 | static struct usb_function_instance *uvc_alloc_inst(void) |
775 | { | 797 | { |
776 | struct f_uvc_opts *opts; | 798 | struct f_uvc_opts *opts; |
799 | struct uvc_camera_terminal_descriptor *cd; | ||
800 | struct uvc_processing_unit_descriptor *pd; | ||
801 | struct uvc_output_terminal_descriptor *od; | ||
802 | struct uvc_color_matching_descriptor *md; | ||
803 | struct uvc_descriptor_header **ctl_cls; | ||
777 | 804 | ||
778 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); | 805 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); |
779 | if (!opts) | 806 | if (!opts) |
780 | return ERR_PTR(-ENOMEM); | 807 | return ERR_PTR(-ENOMEM); |
781 | opts->func_inst.free_func_inst = uvc_free_inst; | 808 | opts->func_inst.free_func_inst = uvc_free_inst; |
782 | 809 | mutex_init(&opts->lock); | |
810 | |||
811 | cd = &opts->uvc_camera_terminal; | ||
812 | cd->bLength = UVC_DT_CAMERA_TERMINAL_SIZE(3); | ||
813 | cd->bDescriptorType = USB_DT_CS_INTERFACE; | ||
814 | cd->bDescriptorSubType = UVC_VC_INPUT_TERMINAL; | ||
815 | cd->bTerminalID = 1; | ||
816 | cd->wTerminalType = cpu_to_le16(0x0201); | ||
817 | cd->bAssocTerminal = 0; | ||
818 | cd->iTerminal = 0; | ||
819 | cd->wObjectiveFocalLengthMin = cpu_to_le16(0); | ||
820 | cd->wObjectiveFocalLengthMax = cpu_to_le16(0); | ||
821 | cd->wOcularFocalLength = cpu_to_le16(0); | ||
822 | cd->bControlSize = 3; | ||
823 | cd->bmControls[0] = 2; | ||
824 | cd->bmControls[1] = 0; | ||
825 | cd->bmControls[2] = 0; | ||
826 | |||
827 | pd = &opts->uvc_processing; | ||
828 | pd->bLength = UVC_DT_PROCESSING_UNIT_SIZE(2); | ||
829 | pd->bDescriptorType = USB_DT_CS_INTERFACE; | ||
830 | pd->bDescriptorSubType = UVC_VC_PROCESSING_UNIT; | ||
831 | pd->bUnitID = 2; | ||
832 | pd->bSourceID = 1; | ||
833 | pd->wMaxMultiplier = cpu_to_le16(16*1024); | ||
834 | pd->bControlSize = 2; | ||
835 | pd->bmControls[0] = 1; | ||
836 | pd->bmControls[1] = 0; | ||
837 | pd->iProcessing = 0; | ||
838 | |||
839 | od = &opts->uvc_output_terminal; | ||
840 | od->bLength = UVC_DT_OUTPUT_TERMINAL_SIZE; | ||
841 | od->bDescriptorType = USB_DT_CS_INTERFACE; | ||
842 | od->bDescriptorSubType = UVC_VC_OUTPUT_TERMINAL; | ||
843 | od->bTerminalID = 3; | ||
844 | od->wTerminalType = cpu_to_le16(0x0101); | ||
845 | od->bAssocTerminal = 0; | ||
846 | od->bSourceID = 2; | ||
847 | od->iTerminal = 0; | ||
848 | |||
849 | md = &opts->uvc_color_matching; | ||
850 | md->bLength = UVC_DT_COLOR_MATCHING_SIZE; | ||
851 | md->bDescriptorType = USB_DT_CS_INTERFACE; | ||
852 | md->bDescriptorSubType = UVC_VS_COLORFORMAT; | ||
853 | md->bColorPrimaries = 1; | ||
854 | md->bTransferCharacteristics = 1; | ||
855 | md->bMatrixCoefficients = 4; | ||
856 | |||
857 | /* Prepare fs control class descriptors for configfs-based gadgets */ | ||
858 | ctl_cls = opts->uvc_fs_control_cls; | ||
859 | ctl_cls[0] = NULL; /* assigned elsewhere by configfs */ | ||
860 | ctl_cls[1] = (struct uvc_descriptor_header *)cd; | ||
861 | ctl_cls[2] = (struct uvc_descriptor_header *)pd; | ||
862 | ctl_cls[3] = (struct uvc_descriptor_header *)od; | ||
863 | ctl_cls[4] = NULL; /* NULL-terminate */ | ||
864 | opts->fs_control = | ||
865 | (const struct uvc_descriptor_header * const *)ctl_cls; | ||
866 | |||
867 | /* Prepare hs control class descriptors for configfs-based gadgets */ | ||
868 | ctl_cls = opts->uvc_ss_control_cls; | ||
869 | ctl_cls[0] = NULL; /* assigned elsewhere by configfs */ | ||
870 | ctl_cls[1] = (struct uvc_descriptor_header *)cd; | ||
871 | ctl_cls[2] = (struct uvc_descriptor_header *)pd; | ||
872 | ctl_cls[3] = (struct uvc_descriptor_header *)od; | ||
873 | ctl_cls[4] = NULL; /* NULL-terminate */ | ||
874 | opts->ss_control = | ||
875 | (const struct uvc_descriptor_header * const *)ctl_cls; | ||
876 | |||
877 | opts->streaming_interval = 1; | ||
878 | opts->streaming_maxpacket = 1024; | ||
879 | |||
880 | uvcg_attach_configfs(opts); | ||
783 | return &opts->func_inst; | 881 | return &opts->func_inst; |
784 | } | 882 | } |
785 | 883 | ||
786 | static void uvc_free(struct usb_function *f) | 884 | static void uvc_free(struct usb_function *f) |
787 | { | 885 | { |
788 | struct uvc_device *uvc = to_uvc(f); | 886 | struct uvc_device *uvc = to_uvc(f); |
789 | 887 | struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts, | |
888 | func_inst); | ||
889 | --opts->refcnt; | ||
790 | kfree(uvc); | 890 | kfree(uvc); |
791 | } | 891 | } |
792 | 892 | ||
@@ -812,19 +912,39 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) | |||
812 | { | 912 | { |
813 | struct uvc_device *uvc; | 913 | struct uvc_device *uvc; |
814 | struct f_uvc_opts *opts; | 914 | struct f_uvc_opts *opts; |
915 | struct uvc_descriptor_header **strm_cls; | ||
815 | 916 | ||
816 | uvc = kzalloc(sizeof(*uvc), GFP_KERNEL); | 917 | uvc = kzalloc(sizeof(*uvc), GFP_KERNEL); |
817 | if (uvc == NULL) | 918 | if (uvc == NULL) |
818 | return ERR_PTR(-ENOMEM); | 919 | return ERR_PTR(-ENOMEM); |
819 | 920 | ||
820 | uvc->state = UVC_STATE_DISCONNECTED; | 921 | uvc->state = UVC_STATE_DISCONNECTED; |
821 | opts = to_f_uvc_opts(fi); | 922 | opts = fi_to_f_uvc_opts(fi); |
923 | |||
924 | mutex_lock(&opts->lock); | ||
925 | if (opts->uvc_fs_streaming_cls) { | ||
926 | strm_cls = opts->uvc_fs_streaming_cls; | ||
927 | opts->fs_streaming = | ||
928 | (const struct uvc_descriptor_header * const *)strm_cls; | ||
929 | } | ||
930 | if (opts->uvc_hs_streaming_cls) { | ||
931 | strm_cls = opts->uvc_hs_streaming_cls; | ||
932 | opts->hs_streaming = | ||
933 | (const struct uvc_descriptor_header * const *)strm_cls; | ||
934 | } | ||
935 | if (opts->uvc_ss_streaming_cls) { | ||
936 | strm_cls = opts->uvc_ss_streaming_cls; | ||
937 | opts->ss_streaming = | ||
938 | (const struct uvc_descriptor_header * const *)strm_cls; | ||
939 | } | ||
822 | 940 | ||
823 | uvc->desc.fs_control = opts->fs_control; | 941 | uvc->desc.fs_control = opts->fs_control; |
824 | uvc->desc.ss_control = opts->ss_control; | 942 | uvc->desc.ss_control = opts->ss_control; |
825 | uvc->desc.fs_streaming = opts->fs_streaming; | 943 | uvc->desc.fs_streaming = opts->fs_streaming; |
826 | uvc->desc.hs_streaming = opts->hs_streaming; | 944 | uvc->desc.hs_streaming = opts->hs_streaming; |
827 | uvc->desc.ss_streaming = opts->ss_streaming; | 945 | uvc->desc.ss_streaming = opts->ss_streaming; |
946 | ++opts->refcnt; | ||
947 | mutex_unlock(&opts->lock); | ||
828 | 948 | ||
829 | /* Register the function. */ | 949 | /* Register the function. */ |
830 | uvc->func.name = "uvc"; | 950 | uvc->func.name = "uvc"; |