diff options
| author | Andrzej Pietrasiewicz <andrzej.p@samsung.com> | 2014-09-08 19:02:10 -0400 |
|---|---|---|
| committer | Felipe Balbi <balbi@ti.com> | 2014-09-09 10:49:16 -0400 |
| commit | 6d11ed76c45dd7c8322c2d03575f2164cc725c18 (patch) | |
| tree | 8d01c8280f47d8838b4e22f6877c563b877aa078 | |
| parent | 3a83c16ef0e03e2ca2f1ce547a7cba53a62d0e0d (diff) | |
usb: gadget: f_uvc: convert f_uvc to new function interface
Use the new function registration interface. It is required
in order to integrate configfs support.
Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Tested-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
[Updated copyright years]
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
| -rw-r--r-- | drivers/usb/gadget/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/usb/gadget/function/Makefile | 2 | ||||
| -rw-r--r-- | drivers/usb/gadget/function/f_uvc.c | 204 | ||||
| -rw-r--r-- | drivers/usb/gadget/function/u_uvc.h | 39 | ||||
| -rw-r--r-- | drivers/usb/gadget/legacy/webcam.c | 1 |
5 files changed, 219 insertions, 30 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 68302aa604be..c4880fc0d86e 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig | |||
| @@ -187,6 +187,9 @@ config USB_F_UAC1 | |||
| 187 | config USB_F_UAC2 | 187 | config USB_F_UAC2 |
| 188 | tristate | 188 | tristate |
| 189 | 189 | ||
| 190 | config USB_F_UVC | ||
| 191 | tristate | ||
| 192 | |||
| 190 | choice | 193 | choice |
| 191 | tristate "USB Gadget Drivers" | 194 | tristate "USB Gadget Drivers" |
| 192 | default USB_ETH | 195 | default USB_ETH |
diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index a49fdf7b59e1..90701aa5a826 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile | |||
| @@ -36,3 +36,5 @@ usb_f_uac1-y := f_uac1.o u_uac1.o | |||
| 36 | obj-$(CONFIG_USB_F_UAC1) += usb_f_uac1.o | 36 | obj-$(CONFIG_USB_F_UAC1) += usb_f_uac1.o |
| 37 | usb_f_uac2-y := f_uac2.o | 37 | usb_f_uac2-y := f_uac2.o |
| 38 | obj-$(CONFIG_USB_F_UAC2) += usb_f_uac2.o | 38 | obj-$(CONFIG_USB_F_UAC2) += usb_f_uac2.o |
| 39 | usb_f_uvc-y := f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o | ||
| 40 | obj-$(CONFIG_USB_F_UVC) += usb_f_uvc.o | ||
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 825080d271a7..fe50a9b4fa8f 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
| 14 | #include <linux/module.h> | ||
| 14 | #include <linux/device.h> | 15 | #include <linux/device.h> |
| 15 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
| 16 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
| @@ -29,11 +30,14 @@ | |||
| 29 | #include "uvc.h" | 30 | #include "uvc.h" |
| 30 | #include "uvc_v4l2.h" | 31 | #include "uvc_v4l2.h" |
| 31 | #include "uvc_video.h" | 32 | #include "uvc_video.h" |
| 33 | #include "u_uvc.h" | ||
| 32 | 34 | ||
| 33 | unsigned int uvc_gadget_trace_param; | 35 | unsigned int uvc_gadget_trace_param; |
| 36 | #ifdef USBF_UVC_INCLUDED | ||
| 34 | static unsigned int streaming_interval; | 37 | static unsigned int streaming_interval; |
| 35 | static unsigned int streaming_maxpacket; | 38 | static unsigned int streaming_maxpacket; |
| 36 | static unsigned int streaming_maxburst; | 39 | static unsigned int streaming_maxburst; |
| 40 | #endif | ||
| 37 | 41 | ||
| 38 | /* -------------------------------------------------------------------------- | 42 | /* -------------------------------------------------------------------------- |
| 39 | * Function descriptors | 43 | * Function descriptors |
| @@ -65,7 +69,7 @@ static struct usb_gadget_strings *uvc_function_strings[] = { | |||
| 65 | 69 | ||
| 66 | #define UVC_STATUS_MAX_PACKET_SIZE 16 /* 16 bytes status */ | 70 | #define UVC_STATUS_MAX_PACKET_SIZE 16 /* 16 bytes status */ |
| 67 | 71 | ||
| 68 | static struct usb_interface_assoc_descriptor uvc_iad __initdata = { | 72 | static struct usb_interface_assoc_descriptor uvc_iad = { |
| 69 | .bLength = sizeof(uvc_iad), | 73 | .bLength = sizeof(uvc_iad), |
| 70 | .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, | 74 | .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, |
| 71 | .bFirstInterface = 0, | 75 | .bFirstInterface = 0, |
| @@ -76,7 +80,7 @@ static struct usb_interface_assoc_descriptor uvc_iad __initdata = { | |||
| 76 | .iFunction = 0, | 80 | .iFunction = 0, |
| 77 | }; | 81 | }; |
| 78 | 82 | ||
| 79 | static struct usb_interface_descriptor uvc_control_intf __initdata = { | 83 | static struct usb_interface_descriptor uvc_control_intf = { |
| 80 | .bLength = USB_DT_INTERFACE_SIZE, | 84 | .bLength = USB_DT_INTERFACE_SIZE, |
| 81 | .bDescriptorType = USB_DT_INTERFACE, | 85 | .bDescriptorType = USB_DT_INTERFACE, |
| 82 | .bInterfaceNumber = UVC_INTF_VIDEO_CONTROL, | 86 | .bInterfaceNumber = UVC_INTF_VIDEO_CONTROL, |
| @@ -88,7 +92,7 @@ static struct usb_interface_descriptor uvc_control_intf __initdata = { | |||
| 88 | .iInterface = 0, | 92 | .iInterface = 0, |
| 89 | }; | 93 | }; |
| 90 | 94 | ||
| 91 | static struct usb_endpoint_descriptor uvc_control_ep __initdata = { | 95 | static struct usb_endpoint_descriptor uvc_control_ep = { |
| 92 | .bLength = USB_DT_ENDPOINT_SIZE, | 96 | .bLength = USB_DT_ENDPOINT_SIZE, |
| 93 | .bDescriptorType = USB_DT_ENDPOINT, | 97 | .bDescriptorType = USB_DT_ENDPOINT, |
| 94 | .bEndpointAddress = USB_DIR_IN, | 98 | .bEndpointAddress = USB_DIR_IN, |
| @@ -97,7 +101,7 @@ static struct usb_endpoint_descriptor uvc_control_ep __initdata = { | |||
| 97 | .bInterval = 8, | 101 | .bInterval = 8, |
| 98 | }; | 102 | }; |
| 99 | 103 | ||
| 100 | static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = { | 104 | static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp = { |
| 101 | .bLength = sizeof(uvc_ss_control_comp), | 105 | .bLength = sizeof(uvc_ss_control_comp), |
| 102 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, | 106 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, |
| 103 | /* The following 3 values can be tweaked if necessary. */ | 107 | /* The following 3 values can be tweaked if necessary. */ |
| @@ -106,14 +110,14 @@ static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = { | |||
| 106 | .wBytesPerInterval = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE), | 110 | .wBytesPerInterval = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE), |
| 107 | }; | 111 | }; |
| 108 | 112 | ||
| 109 | static struct uvc_control_endpoint_descriptor uvc_control_cs_ep __initdata = { | 113 | static struct uvc_control_endpoint_descriptor uvc_control_cs_ep = { |
| 110 | .bLength = UVC_DT_CONTROL_ENDPOINT_SIZE, | 114 | .bLength = UVC_DT_CONTROL_ENDPOINT_SIZE, |
| 111 | .bDescriptorType = USB_DT_CS_ENDPOINT, | 115 | .bDescriptorType = USB_DT_CS_ENDPOINT, |
| 112 | .bDescriptorSubType = UVC_EP_INTERRUPT, | 116 | .bDescriptorSubType = UVC_EP_INTERRUPT, |
| 113 | .wMaxTransferSize = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE), | 117 | .wMaxTransferSize = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE), |
| 114 | }; | 118 | }; |
| 115 | 119 | ||
| 116 | static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = { | 120 | static struct usb_interface_descriptor uvc_streaming_intf_alt0 = { |
| 117 | .bLength = USB_DT_INTERFACE_SIZE, | 121 | .bLength = USB_DT_INTERFACE_SIZE, |
| 118 | .bDescriptorType = USB_DT_INTERFACE, | 122 | .bDescriptorType = USB_DT_INTERFACE, |
| 119 | .bInterfaceNumber = UVC_INTF_VIDEO_STREAMING, | 123 | .bInterfaceNumber = UVC_INTF_VIDEO_STREAMING, |
| @@ -125,7 +129,7 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = { | |||
| 125 | .iInterface = 0, | 129 | .iInterface = 0, |
| 126 | }; | 130 | }; |
| 127 | 131 | ||
| 128 | static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = { | 132 | static struct usb_interface_descriptor uvc_streaming_intf_alt1 = { |
| 129 | .bLength = USB_DT_INTERFACE_SIZE, | 133 | .bLength = USB_DT_INTERFACE_SIZE, |
| 130 | .bDescriptorType = USB_DT_INTERFACE, | 134 | .bDescriptorType = USB_DT_INTERFACE, |
| 131 | .bInterfaceNumber = UVC_INTF_VIDEO_STREAMING, | 135 | .bInterfaceNumber = UVC_INTF_VIDEO_STREAMING, |
| @@ -137,7 +141,7 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = { | |||
| 137 | .iInterface = 0, | 141 | .iInterface = 0, |
| 138 | }; | 142 | }; |
| 139 | 143 | ||
| 140 | static struct usb_endpoint_descriptor uvc_fs_streaming_ep __initdata = { | 144 | static struct usb_endpoint_descriptor uvc_fs_streaming_ep = { |
| 141 | .bLength = USB_DT_ENDPOINT_SIZE, | 145 | .bLength = USB_DT_ENDPOINT_SIZE, |
| 142 | .bDescriptorType = USB_DT_ENDPOINT, | 146 | .bDescriptorType = USB_DT_ENDPOINT, |
| 143 | .bEndpointAddress = USB_DIR_IN, | 147 | .bEndpointAddress = USB_DIR_IN, |
| @@ -148,7 +152,7 @@ static struct usb_endpoint_descriptor uvc_fs_streaming_ep __initdata = { | |||
| 148 | */ | 152 | */ |
| 149 | }; | 153 | }; |
| 150 | 154 | ||
| 151 | static struct usb_endpoint_descriptor uvc_hs_streaming_ep __initdata = { | 155 | static struct usb_endpoint_descriptor uvc_hs_streaming_ep = { |
| 152 | .bLength = USB_DT_ENDPOINT_SIZE, | 156 | .bLength = USB_DT_ENDPOINT_SIZE, |
| 153 | .bDescriptorType = USB_DT_ENDPOINT, | 157 | .bDescriptorType = USB_DT_ENDPOINT, |
| 154 | .bEndpointAddress = USB_DIR_IN, | 158 | .bEndpointAddress = USB_DIR_IN, |
| @@ -159,7 +163,7 @@ static struct usb_endpoint_descriptor uvc_hs_streaming_ep __initdata = { | |||
| 159 | */ | 163 | */ |
| 160 | }; | 164 | }; |
| 161 | 165 | ||
| 162 | static struct usb_endpoint_descriptor uvc_ss_streaming_ep __initdata = { | 166 | static struct usb_endpoint_descriptor uvc_ss_streaming_ep = { |
| 163 | .bLength = USB_DT_ENDPOINT_SIZE, | 167 | .bLength = USB_DT_ENDPOINT_SIZE, |
| 164 | .bDescriptorType = USB_DT_ENDPOINT, | 168 | .bDescriptorType = USB_DT_ENDPOINT, |
| 165 | 169 | ||
| @@ -171,7 +175,7 @@ static struct usb_endpoint_descriptor uvc_ss_streaming_ep __initdata = { | |||
| 171 | */ | 175 | */ |
| 172 | }; | 176 | }; |
| 173 | 177 | ||
| 174 | static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp __initdata = { | 178 | static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = { |
| 175 | .bLength = sizeof(uvc_ss_streaming_comp), | 179 | .bLength = sizeof(uvc_ss_streaming_comp), |
| 176 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, | 180 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, |
| 177 | /* The bMaxBurst, bmAttributes and wBytesPerInterval values will be | 181 | /* The bMaxBurst, bmAttributes and wBytesPerInterval values will be |
| @@ -198,6 +202,16 @@ static const struct usb_descriptor_header * const uvc_ss_streaming[] = { | |||
| 198 | NULL, | 202 | NULL, |
| 199 | }; | 203 | }; |
| 200 | 204 | ||
| 205 | #ifndef USBF_UVC_INCLUDED | ||
| 206 | |||
| 207 | void uvc_set_trace_param(unsigned int trace) | ||
| 208 | { | ||
| 209 | uvc_gadget_trace_param = trace; | ||
| 210 | } | ||
| 211 | EXPORT_SYMBOL(uvc_set_trace_param); | ||
| 212 | |||
| 213 | #endif | ||
| 214 | |||
| 201 | /* -------------------------------------------------------------------------- | 215 | /* -------------------------------------------------------------------------- |
| 202 | * Control requests | 216 | * Control requests |
| 203 | */ | 217 | */ |
| @@ -432,7 +446,7 @@ uvc_register_video(struct uvc_device *uvc) | |||
| 432 | } \ | 446 | } \ |
| 433 | } while (0) | 447 | } while (0) |
| 434 | 448 | ||
| 435 | static struct usb_descriptor_header ** __init | 449 | static struct usb_descriptor_header ** |
| 436 | uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) | 450 | uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) |
| 437 | { | 451 | { |
| 438 | struct uvc_input_header_descriptor *uvc_streaming_header; | 452 | struct uvc_input_header_descriptor *uvc_streaming_header; |
| @@ -552,6 +566,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) | |||
| 552 | return hdr; | 566 | return hdr; |
| 553 | } | 567 | } |
| 554 | 568 | ||
| 569 | #ifdef USBF_UVC_INCLUDED | ||
| 555 | static void | 570 | static void |
| 556 | uvc_function_unbind(struct usb_configuration *c, struct usb_function *f) | 571 | uvc_function_unbind(struct usb_configuration *c, struct usb_function *f) |
| 557 | { | 572 | { |
| @@ -573,8 +588,9 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f) | |||
| 573 | 588 | ||
| 574 | kfree(uvc); | 589 | kfree(uvc); |
| 575 | } | 590 | } |
| 591 | #endif | ||
| 576 | 592 | ||
| 577 | static int __init | 593 | static int |
| 578 | uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | 594 | uvc_function_bind(struct usb_configuration *c, struct usb_function *f) |
| 579 | { | 595 | { |
| 580 | struct usb_composite_dev *cdev = c->cdev; | 596 | struct usb_composite_dev *cdev = c->cdev; |
| @@ -582,10 +598,14 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | |||
| 582 | unsigned int max_packet_mult; | 598 | unsigned int max_packet_mult; |
| 583 | unsigned int max_packet_size; | 599 | unsigned int max_packet_size; |
| 584 | struct usb_ep *ep; | 600 | struct usb_ep *ep; |
| 601 | #ifndef USBF_UVC_INCLUDED | ||
| 602 | struct f_uvc_opts *opts; | ||
| 603 | #endif | ||
| 585 | int ret = -EINVAL; | 604 | int ret = -EINVAL; |
| 586 | 605 | ||
| 587 | INFO(cdev, "uvc_function_bind\n"); | 606 | INFO(cdev, "uvc_function_bind\n"); |
| 588 | 607 | ||
| 608 | #ifdef USBF_UVC_INCLUDED | ||
| 589 | /* Sanity check the streaming endpoint module parameters. | 609 | /* Sanity check the streaming endpoint module parameters. |
| 590 | */ | 610 | */ |
| 591 | streaming_interval = clamp(streaming_interval, 1U, 16U); | 611 | streaming_interval = clamp(streaming_interval, 1U, 16U); |
| @@ -622,6 +642,46 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | |||
| 622 | uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst; | 642 | uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst; |
| 623 | uvc_ss_streaming_comp.wBytesPerInterval = | 643 | uvc_ss_streaming_comp.wBytesPerInterval = |
| 624 | max_packet_size * max_packet_mult * streaming_maxburst; | 644 | max_packet_size * max_packet_mult * streaming_maxburst; |
| 645 | #else | ||
| 646 | opts = to_f_uvc_opts(f->fi); | ||
| 647 | /* Sanity check the streaming endpoint module parameters. | ||
| 648 | */ | ||
| 649 | opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U); | ||
| 650 | opts->streaming_maxpacket = clamp(opts->streaming_maxpacket, 1U, 3072U); | ||
| 651 | opts->streaming_maxburst = min(opts->streaming_maxburst, 15U); | ||
| 652 | |||
| 653 | /* Fill in the FS/HS/SS Video Streaming specific descriptors from the | ||
| 654 | * module parameters. | ||
| 655 | * | ||
| 656 | * NOTE: We assume that the user knows what they are doing and won't | ||
| 657 | * give parameters that their UDC doesn't support. | ||
| 658 | */ | ||
| 659 | if (opts->streaming_maxpacket <= 1024) { | ||
| 660 | max_packet_mult = 1; | ||
| 661 | max_packet_size = opts->streaming_maxpacket; | ||
| 662 | } else if (opts->streaming_maxpacket <= 2048) { | ||
| 663 | max_packet_mult = 2; | ||
| 664 | max_packet_size = opts->streaming_maxpacket / 2; | ||
| 665 | } else { | ||
| 666 | max_packet_mult = 3; | ||
| 667 | max_packet_size = opts->streaming_maxpacket / 3; | ||
| 668 | } | ||
| 669 | |||
| 670 | uvc_fs_streaming_ep.wMaxPacketSize = | ||
| 671 | min(opts->streaming_maxpacket, 1023U); | ||
| 672 | uvc_fs_streaming_ep.bInterval = opts->streaming_interval; | ||
| 673 | |||
| 674 | uvc_hs_streaming_ep.wMaxPacketSize = max_packet_size; | ||
| 675 | uvc_hs_streaming_ep.wMaxPacketSize |= ((max_packet_mult - 1) << 11); | ||
| 676 | uvc_hs_streaming_ep.bInterval = opts->streaming_interval; | ||
| 677 | |||
| 678 | uvc_ss_streaming_ep.wMaxPacketSize = max_packet_size; | ||
| 679 | uvc_ss_streaming_ep.bInterval = opts->streaming_interval; | ||
| 680 | uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1; | ||
| 681 | uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst; | ||
| 682 | uvc_ss_streaming_comp.wBytesPerInterval = | ||
| 683 | max_packet_size * max_packet_mult * opts->streaming_maxburst; | ||
| 684 | #endif | ||
| 625 | 685 | ||
| 626 | /* Allocate endpoints. */ | 686 | /* Allocate endpoints. */ |
| 627 | ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep); | 687 | ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep); |
| @@ -651,6 +711,23 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | |||
| 651 | uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address; | 711 | uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address; |
| 652 | uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address; | 712 | uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address; |
| 653 | 713 | ||
| 714 | /* String descriptors are global, we only need to allocate string IDs | ||
| 715 | * for the first UVC function. UVC functions beyond the first (if any) | ||
| 716 | * will reuse the same IDs. | ||
| 717 | */ | ||
| 718 | if (uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id == 0) { | ||
| 719 | ret = usb_string_ids_tab(c->cdev, uvc_en_us_strings); | ||
| 720 | if (ret) | ||
| 721 | goto error; | ||
| 722 | uvc_iad.iFunction = | ||
| 723 | uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id; | ||
| 724 | uvc_control_intf.iInterface = | ||
| 725 | uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id; | ||
| 726 | ret = uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id; | ||
| 727 | uvc_streaming_intf_alt0.iInterface = ret; | ||
| 728 | uvc_streaming_intf_alt1.iInterface = ret; | ||
| 729 | } | ||
| 730 | |||
| 654 | /* Allocate interface IDs. */ | 731 | /* Allocate interface IDs. */ |
| 655 | if ((ret = usb_interface_id(c, f)) < 0) | 732 | if ((ret = usb_interface_id(c, f)) < 0) |
| 656 | goto error; | 733 | goto error; |
| @@ -730,6 +807,7 @@ error: | |||
| 730 | * USB gadget function | 807 | * USB gadget function |
| 731 | */ | 808 | */ |
| 732 | 809 | ||
| 810 | #ifdef USBF_UVC_INCLUDED | ||
| 733 | /** | 811 | /** |
| 734 | * uvc_bind_config - add a UVC function to a configuration | 812 | * uvc_bind_config - add a UVC function to a configuration |
| 735 | * @c: the configuration to support the UVC instance | 813 | * @c: the configuration to support the UVC instance |
| @@ -796,23 +874,6 @@ uvc_bind_config(struct usb_configuration *c, | |||
| 796 | uvc->desc.hs_streaming = hs_streaming; | 874 | uvc->desc.hs_streaming = hs_streaming; |
| 797 | uvc->desc.ss_streaming = ss_streaming; | 875 | uvc->desc.ss_streaming = ss_streaming; |
| 798 | 876 | ||
| 799 | /* String descriptors are global, we only need to allocate string IDs | ||
| 800 | * for the first UVC function. UVC functions beyond the first (if any) | ||
| 801 | * will reuse the same IDs. | ||
| 802 | */ | ||
| 803 | if (uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id == 0) { | ||
| 804 | ret = usb_string_ids_tab(c->cdev, uvc_en_us_strings); | ||
| 805 | if (ret) | ||
| 806 | goto error; | ||
| 807 | uvc_iad.iFunction = | ||
| 808 | uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id; | ||
| 809 | uvc_control_intf.iInterface = | ||
| 810 | uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id; | ||
| 811 | ret = uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id; | ||
| 812 | uvc_streaming_intf_alt0.iInterface = ret; | ||
| 813 | uvc_streaming_intf_alt1.iInterface = ret; | ||
| 814 | } | ||
| 815 | |||
| 816 | /* Register the function. */ | 877 | /* Register the function. */ |
| 817 | uvc->func.name = "uvc"; | 878 | uvc->func.name = "uvc"; |
| 818 | uvc->func.strings = uvc_function_strings; | 879 | uvc->func.strings = uvc_function_strings; |
| @@ -834,4 +895,87 @@ error: | |||
| 834 | return ret; | 895 | return ret; |
| 835 | } | 896 | } |
| 836 | 897 | ||
| 898 | #else | ||
| 899 | |||
| 900 | static void uvc_free_inst(struct usb_function_instance *f) | ||
| 901 | { | ||
| 902 | struct f_uvc_opts *opts = to_f_uvc_opts(f); | ||
| 903 | |||
| 904 | kfree(opts); | ||
| 905 | } | ||
| 906 | |||
| 907 | static struct usb_function_instance *uvc_alloc_inst(void) | ||
| 908 | { | ||
| 909 | struct f_uvc_opts *opts; | ||
| 910 | |||
| 911 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); | ||
| 912 | if (!opts) | ||
| 913 | return ERR_PTR(-ENOMEM); | ||
| 914 | opts->func_inst.free_func_inst = uvc_free_inst; | ||
| 915 | |||
| 916 | return &opts->func_inst; | ||
| 917 | } | ||
| 918 | |||
| 919 | static void uvc_free(struct usb_function *f) | ||
| 920 | { | ||
| 921 | struct uvc_device *uvc = to_uvc(f); | ||
| 922 | |||
| 923 | kfree(uvc); | ||
| 924 | } | ||
| 925 | |||
| 926 | static void uvc_unbind(struct usb_configuration *c, struct usb_function *f) | ||
| 927 | { | ||
| 928 | struct usb_composite_dev *cdev = c->cdev; | ||
| 929 | struct uvc_device *uvc = to_uvc(f); | ||
| 930 | |||
| 931 | INFO(cdev, "%s\n", __func__); | ||
| 932 | |||
| 933 | video_unregister_device(uvc->vdev); | ||
| 934 | v4l2_device_unregister(&uvc->v4l2_dev); | ||
| 935 | uvc->control_ep->driver_data = NULL; | ||
| 936 | uvc->video.ep->driver_data = NULL; | ||
| 937 | |||
| 938 | uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = 0; | ||
| 939 | usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); | ||
| 940 | kfree(uvc->control_buf); | ||
| 941 | |||
| 942 | usb_free_all_descriptors(f); | ||
| 943 | } | ||
| 944 | |||
| 945 | struct usb_function *uvc_alloc(struct usb_function_instance *fi) | ||
| 946 | { | ||
| 947 | struct uvc_device *uvc; | ||
| 948 | struct f_uvc_opts *opts; | ||
| 949 | |||
| 950 | uvc = kzalloc(sizeof(*uvc), GFP_KERNEL); | ||
| 951 | if (uvc == NULL) | ||
| 952 | return ERR_PTR(-ENOMEM); | ||
| 953 | |||
| 954 | uvc->state = UVC_STATE_DISCONNECTED; | ||
| 955 | opts = to_f_uvc_opts(fi); | ||
| 956 | |||
| 957 | uvc->desc.fs_control = opts->fs_control; | ||
| 958 | uvc->desc.ss_control = opts->ss_control; | ||
| 959 | uvc->desc.fs_streaming = opts->fs_streaming; | ||
| 960 | uvc->desc.hs_streaming = opts->hs_streaming; | ||
| 961 | uvc->desc.ss_streaming = opts->ss_streaming; | ||
| 962 | |||
| 963 | /* Register the function. */ | ||
| 964 | uvc->func.name = "uvc"; | ||
| 965 | uvc->func.strings = uvc_function_strings; | ||
| 966 | uvc->func.bind = uvc_function_bind; | ||
| 967 | uvc->func.unbind = uvc_unbind; | ||
| 968 | uvc->func.get_alt = uvc_function_get_alt; | ||
| 969 | uvc->func.set_alt = uvc_function_set_alt; | ||
| 970 | uvc->func.disable = uvc_function_disable; | ||
| 971 | uvc->func.setup = uvc_function_setup; | ||
| 972 | uvc->func.free_func = uvc_free; | ||
| 973 | |||
| 974 | return &uvc->func; | ||
| 975 | } | ||
| 976 | |||
| 977 | DECLARE_USB_FUNCTION_INIT(uvc, uvc_alloc_inst, uvc_alloc); | ||
| 978 | MODULE_LICENSE("GPL"); | ||
| 979 | MODULE_AUTHOR("Laurent Pinchart"); | ||
| 837 | 980 | ||
| 981 | #endif | ||
diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h new file mode 100644 index 000000000000..2a8dfdff0332 --- /dev/null +++ b/drivers/usb/gadget/function/u_uvc.h | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | /* | ||
| 2 | * u_uvc.h | ||
| 3 | * | ||
| 4 | * Utility definitions for the uvc function | ||
| 5 | * | ||
| 6 | * Copyright (c) 2013-2014 Samsung Electronics Co., Ltd. | ||
| 7 | * http://www.samsung.com | ||
| 8 | * | ||
| 9 | * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify | ||
| 12 | * it under the terms of the GNU General Public License version 2 as | ||
| 13 | * published by the Free Software Foundation. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #ifndef U_UVC_H | ||
| 17 | #define U_UVC_H | ||
| 18 | |||
| 19 | #include <linux/usb/composite.h> | ||
| 20 | |||
| 21 | #define to_f_uvc_opts(f) container_of(f, struct f_uvc_opts, func_inst) | ||
| 22 | |||
| 23 | struct f_uvc_opts { | ||
| 24 | struct usb_function_instance func_inst; | ||
| 25 | unsigned int uvc_gadget_trace_param; | ||
| 26 | unsigned int streaming_interval; | ||
| 27 | unsigned int streaming_maxpacket; | ||
| 28 | unsigned int streaming_maxburst; | ||
| 29 | const struct uvc_descriptor_header * const *fs_control; | ||
| 30 | const struct uvc_descriptor_header * const *ss_control; | ||
| 31 | const struct uvc_descriptor_header * const *fs_streaming; | ||
| 32 | const struct uvc_descriptor_header * const *hs_streaming; | ||
| 33 | const struct uvc_descriptor_header * const *ss_streaming; | ||
| 34 | }; | ||
| 35 | |||
| 36 | void uvc_set_trace_param(unsigned int trace); | ||
| 37 | |||
| 38 | #endif /* U_UVC_H */ | ||
| 39 | |||
diff --git a/drivers/usb/gadget/legacy/webcam.c b/drivers/usb/gadget/legacy/webcam.c index 5d02849b1f67..50d27dbdbfa9 100644 --- a/drivers/usb/gadget/legacy/webcam.c +++ b/drivers/usb/gadget/legacy/webcam.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | * the runtime footprint, and giving us at least some parts of what | 22 | * the runtime footprint, and giving us at least some parts of what |
| 23 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. | 23 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. |
| 24 | */ | 24 | */ |
| 25 | #define USBF_UVC_INCLUDED | ||
| 25 | #include "f_uvc.c" | 26 | #include "f_uvc.c" |
| 26 | 27 | ||
| 27 | USB_GADGET_COMPOSITE_OPTIONS(); | 28 | USB_GADGET_COMPOSITE_OPTIONS(); |
