From b444aeea9de2d8e507f2301f9fed1eb64dcc7e1e Mon Sep 17 00:00:00 2001
From: Petr Cvek <petr.cvek@tul.cz>
Date: Wed, 3 Aug 2016 22:29:44 +0200
Subject: [PATCH] PXA27x UDC more endpoints for more gadgets + UVC gadget
 (configfs)

---
 drivers/usb/gadget/function/f_uvc.c     |  6 ++-
 drivers/usb/gadget/function/uvc_v4l2.c  | 34 +++++++++++++-
 drivers/usb/gadget/function/uvc_video.c |  3 +-
 drivers/usb/gadget/legacy/webcam.c      | 35 +++++++--------
 drivers/usb/gadget/udc/core.c           |  3 ++
 drivers/usb/gadget/udc/pxa27x_udc.c     | 79 +++++++++++++++++++++------------
 drivers/usb/gadget/udc/pxa27x_udc.h     |  7 ++-
 7 files changed, 116 insertions(+), 51 deletions(-)

diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 27ed51b5082f..ff20eacad4c4 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -597,6 +597,9 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
 	opts = fi_to_f_uvc_opts(f->fi);
 	/* Sanity check the streaming endpoint module parameters.
 	 */
+
+	pr_info("[DEBUG] opts->streaming_maxpacket=%i\n",opts->streaming_maxpacket);
+
 	opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U);
 	opts->streaming_maxpacket = clamp(opts->streaming_maxpacket, 1U, 3072U);
 	opts->streaming_maxburst = min(opts->streaming_maxburst, 15U);
@@ -845,7 +848,8 @@ static struct usb_function_instance *uvc_alloc_inst(void)
 		(const struct uvc_descriptor_header * const *)ctl_cls;
 
 	opts->streaming_interval = 1;
-	opts->streaming_maxpacket = 1024;
+
+	opts->streaming_maxpacket = 256;	//for PXA limit (PXA should support 1023)
 
 	uvcg_attach_configfs(opts);
 	return &opts->func_inst;
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index 3e22b45687d3..4a2957b765ae 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -61,6 +61,7 @@ struct uvc_format {
 static struct uvc_format uvc_formats[] = {
 	{ 16, V4L2_PIX_FMT_YUYV  },
 	{ 0,  V4L2_PIX_FMT_MJPEG },
+	{ 0,  V4L2_PIX_FMT_JPEG },
 };
 
 static int
@@ -81,6 +82,34 @@ uvc_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
 	return 0;
 }
 
+//around v3.10 for v4l2 compliance
+static int uvc_v4l2_enum_format(struct file *file, void  *priv,
+                   struct v4l2_fmtdesc *fmt)
+{
+   struct uvc_format *format;
+   enum v4l2_buf_type type = fmt->type;
+
+   if (fmt->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+       pr_info("wcam: bad type %i\n",fmt->type);
+       return -EINVAL;
+   }
+
+   if (fmt->index >= ARRAY_SIZE(uvc_formats)) {
+       pr_info("wcam: index to high %i/%i\n",fmt->index,ARRAY_SIZE(uvc_formats));
+       return -EINVAL;
+   }
+
+   fmt->pixelformat = uvc_formats[fmt->index].fcc;
+   fmt->flags = 0;	//V4L2_FMT_FLAG_COMPRESSED or V4L2_FMT_FLAG_EMULATED
+
+   strlcpy(fmt->description, "TODO\0",
+       sizeof(fmt->description));
+
+   fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+   return 0;
+}
+
 static int
 uvc_v4l2_get_format(struct file *file, void *fh, struct v4l2_format *fmt)
 {
@@ -94,7 +123,9 @@ uvc_v4l2_get_format(struct file *file, void *fh, struct v4l2_format *fmt)
 	fmt->fmt.pix.field = V4L2_FIELD_NONE;
 	fmt->fmt.pix.bytesperline = video->bpp * video->width / 8;
 	fmt->fmt.pix.sizeimage = video->imagesize;
-	fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+//	fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+	fmt->fmt.pix.colorspace =   V4L2_COLORSPACE_JPEG;
+
 	fmt->fmt.pix.priv = 0;
 
 	return 0;
@@ -263,6 +294,7 @@ uvc_v4l2_ioctl_default(struct file *file, void *fh, bool valid_prio,
 
 const struct v4l2_ioctl_ops uvc_v4l2_ioctl_ops = {
 	.vidioc_querycap = uvc_v4l2_querycap,
+	.vidioc_enum_fmt_vid_out = uvc_v4l2_enum_format,
 	.vidioc_g_fmt_vid_out = uvc_v4l2_get_format,
 	.vidioc_s_fmt_vid_out = uvc_v4l2_set_format,
 	.vidioc_reqbufs = uvc_v4l2_reqbufs,
diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
index 0f01c04d7cbd..e746b3bce90f 100644
--- a/drivers/usb/gadget/function/uvc_video.c
+++ b/drivers/usb/gadget/function/uvc_video.c
@@ -384,7 +384,8 @@ int uvcg_video_init(struct uvc_video *video)
 	INIT_LIST_HEAD(&video->req_free);
 	spin_lock_init(&video->req_lock);
 
-	video->fcc = V4L2_PIX_FMT_YUYV;
+//	video->fcc = V4L2_PIX_FMT_YUYV;
+video->fcc = V4L2_PIX_FMT_MJPEG;
 	video->bpp = 16;
 	video->width = 320;
 	video->height = 240;
diff --git a/drivers/usb/gadget/legacy/webcam.c b/drivers/usb/gadget/legacy/webcam.c
index f9661cd627c8..9478412b224d 100644
--- a/drivers/usb/gadget/legacy/webcam.c
+++ b/drivers/usb/gadget/legacy/webcam.c
@@ -42,7 +42,7 @@ MODULE_PARM_DESC(trace, "Trace level bitmask");
  */
 
 #define WEBCAM_VENDOR_ID		0x1d6b	/* Linux Foundation */
-#define WEBCAM_PRODUCT_ID		0x0102	/* Webcam A/V gadget */
+#define WEBCAM_PRODUCT_ID		0x0666	/* Webcam A/V gadget, dummy PID */
 #define WEBCAM_DEVICE_BCD		0x0010	/* 0.10 */
 
 static char webcam_vendor_label[] = "Linux Foundation";
@@ -235,14 +235,14 @@ static const struct uvc_format_mjpeg uvc_format_mjpg = {
 DECLARE_UVC_FRAME_MJPEG(1);
 DECLARE_UVC_FRAME_MJPEG(3);
 
-static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
+static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_240p = {
 	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(3),
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
 	.bDescriptorSubType	= UVC_VS_FRAME_MJPEG,
 	.bFrameIndex		= 1,
 	.bmCapabilities		= 0,
-	.wWidth			= cpu_to_le16(640),
-	.wHeight		= cpu_to_le16(360),
+	.wWidth			= cpu_to_le16(320),
+	.wHeight		= cpu_to_le16(240),
 	.dwMinBitRate		= cpu_to_le32(18432000),
 	.dwMaxBitRate		= cpu_to_le32(55296000),
 	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
@@ -253,14 +253,14 @@ static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
 	.dwFrameInterval[2]	= cpu_to_le32(5000000),
 };
 
-static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
+static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_480p = {
 	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
 	.bDescriptorSubType	= UVC_VS_FRAME_MJPEG,
 	.bFrameIndex		= 2,
 	.bmCapabilities		= 0,
-	.wWidth			= cpu_to_le16(1280),
-	.wHeight		= cpu_to_le16(720),
+	.wWidth			= cpu_to_le16(640),
+	.wHeight		= cpu_to_le16(480),
 	.dwMinBitRate		= cpu_to_le32(29491200),
 	.dwMaxBitRate		= cpu_to_le32(29491200),
 	.dwMaxVideoFrameBufferSize	= cpu_to_le32(1843200),
@@ -296,12 +296,9 @@ static const struct uvc_descriptor_header * const uvc_ss_control_cls[] = {
 
 static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = {
 	(const struct uvc_descriptor_header *) &uvc_input_header,
-	(const struct uvc_descriptor_header *) &uvc_format_yuv,
-	(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
-	(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
 	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
-	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
-	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
+	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_240p,
+	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_480p,
 	(const struct uvc_descriptor_header *) &uvc_color_matching,
 	NULL,
 };
@@ -312,8 +309,8 @@ static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
 	(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
 	(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
 	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
-	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
-	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
+	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_240p,
+	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_480p,
 	(const struct uvc_descriptor_header *) &uvc_color_matching,
 	NULL,
 };
@@ -324,8 +321,8 @@ static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = {
 	(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
 	(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
 	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
-	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
-	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
+	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_240p,
+	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_480p,
 	(const struct uvc_descriptor_header *) &uvc_color_matching,
 	NULL,
 };
@@ -352,7 +349,7 @@ webcam_config_bind(struct usb_configuration *c)
 
 static struct usb_configuration webcam_config_driver = {
 	.label			= webcam_config_label,
-	.bConfigurationValue	= 1,
+	.bConfigurationValue	= 3,	// set during userspace program test
 	.iConfiguration		= 0, /* dynamic */
 	.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
 	.MaxPower		= CONFIG_USB_GADGET_VBUS_DRAW,
@@ -406,8 +403,10 @@ webcam_bind(struct usb_composite_dev *cdev)
 
 	/* Register our configuration. */
 	if ((ret = usb_add_config(cdev, &webcam_config_driver,
-					webcam_config_bind)) < 0)
+					webcam_config_bind)) < 0) {
+		pr_err("ERR: webcam usb_add_config ret=%i\n",ret);
 		goto error;
+	}
 
 	usb_composite_overwrite_options(cdev, &coverwrite);
 	INFO(cdev, "Webcam Video Gadget\n");
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 0402177f93cd..382baf40d32b 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -897,6 +897,8 @@ int usb_gadget_ep_match_desc(struct usb_gadget *gadget,
 	u16		max;
 	int		num_req_streams = 0;
 
+	pr_info("====name: %s, mp=%i\n",ep->name,ep->maxpacket_limit);
+
 	/* endpoint already claimed? */
 	if (ep->claimed)
 		return 0;
@@ -906,6 +908,7 @@ int usb_gadget_ep_match_desc(struct usb_gadget *gadget,
 
 	if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in)
 		return 0;
+
 	if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out)
 		return 0;
 
diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c
index 7fa60f5b7ae4..654605412cfd 100644
--- a/drivers/usb/gadget/udc/pxa27x_udc.c
+++ b/drivers/usb/gadget/udc/pxa27x_udc.c
@@ -2381,38 +2381,61 @@ static struct pxa_udc memory = {
 
 	.udc_usb_ep = {
 		USB_EP_CTRL,
-		USB_EP_OUT_BULK(1),
-		USB_EP_IN_BULK(2),
-		USB_EP_IN_ISO(3),
-		USB_EP_OUT_ISO(4),
-		USB_EP_IN_INT(5),
+		USB_EP_IN_INT(1),
+		USB_EP_IN_INT(2),
+		USB_EP_OUT_INT(3),
+
+		USB_EP_IN_ISO(4),
+		USB_EP_OUT_ISO(5),
+		USB_EP_IN_BULK(6),
+		USB_EP_OUT_BULK(7),
+
+		USB_EP_IN_BULK(8),
+		USB_EP_OUT_BULK(9),
+
+		USB_EP_IN_ISO(10),
+		USB_EP_OUT_BULK(11),
+		USB_EP_IN_BULK(12),
+		USB_EP_IN_INT(13),
+		USB_EP_OUT_INT(14),
 	},
 
 	.pxa_ep = {
 		PXA_EP_CTRL,
-		/* Endpoints for gadget zero */
-		PXA_EP_OUT_BULK(1, 1, 3, 0, 0),
-		PXA_EP_IN_BULK(2,  2, 3, 0, 0),
-		/* Endpoints for ether gadget, file storage gadget */
-		PXA_EP_OUT_BULK(3, 1, 1, 0, 0),
-		PXA_EP_IN_BULK(4,  2, 1, 0, 0),
-		PXA_EP_IN_ISO(5,   3, 1, 0, 0),
-		PXA_EP_OUT_ISO(6,  4, 1, 0, 0),
-		PXA_EP_IN_INT(7,   5, 1, 0, 0),
-		/* Endpoints for RNDIS, serial */
-		PXA_EP_OUT_BULK(8, 1, 2, 0, 0),
-		PXA_EP_IN_BULK(9,  2, 2, 0, 0),
-		PXA_EP_IN_INT(10,  5, 2, 0, 0),
-		/*
-		 * All the following endpoints are only for completion.  They
-		 * won't never work, as multiple interfaces are really broken on
-		 * the pxa.
-		*/
-		PXA_EP_OUT_BULK(11, 1, 2, 1, 0),
-		PXA_EP_IN_BULK(12,  2, 2, 1, 0),
-		/* Endpoint for CDC Ether */
-		PXA_EP_OUT_BULK(13, 1, 1, 1, 1),
-		PXA_EP_IN_BULK(14,  2, 1, 1, 1),
+
+/* NOTICE these endpoints were crafted (around 3.13) before changes in the UDC
+endpoint lookup functions. They may be redundant now. */
+
+		/*g_hid*/
+		PXA_EP_IN_INT(1,    1, 1, 0, 0),
+		PXA_EP_OUT_INT(2,   3, 1, 0, 0),
+		/*g_audio uac2*/
+		PXA_EP_OUT_ISO(3,   5, 1, 1, 1),
+		PXA_EP_IN_ISO(4,    4, 1, 2, 1),
+		/*g_ether, mass storage*/
+		PXA_EP_IN_BULK(5,   6, 1, 0, 0),
+		PXA_EP_OUT_BULK(6,  7, 1, 0, 0),
+		/*g_webcam*/
+		PXA_EP_IN_INT(7,    1, 3, 0, 0),
+		PXA_EP_IN_ISO(8,    4, 3, 1, 1),
+		/*g_cdc maybe?*/
+		PXA_EP_IN_BULK(9,   6, 1, 1, 1),
+		PXA_EP_OUT_BULK(10, 7, 1, 1, 1),
+		PXA_EP_IN_INT(11,   1, 1, 0, 0),
+		PXA_EP_IN_BULK(12,  6, 1, 0, 0),
+		PXA_EP_OUT_BULK(13, 7, 1, 0, 0),
+		PXA_EP_IN_INT(14,   2, 1, 0, 0),
+		/*additional userspace gadget?*/
+		PXA_EP_IN_BULK(15,  6, 1, 2, 0),
+		PXA_EP_OUT_BULK(16, 7, 1, 2, 0),
+		PXA_EP_IN_ISO(17,   4, 1, 1, 1),
+		/*free*/
+		PXA_EP_OUT_BULK(18, 11, 1, 1, 0),
+		PXA_EP_IN_BULK(19,  12, 2, 0, 0),
+		PXA_EP_OUT_BULK(20, 11, 2, 0, 0),
+		PXA_EP_IN_BULK(21,  12, 2, 1, 0),
+		PXA_EP_OUT_BULK(22, 11, 2, 1, 0),
+		PXA_EP_IN_INT(23,   13, 3, 0, 0),
 	}
 };
 
diff --git a/drivers/usb/gadget/udc/pxa27x_udc.h b/drivers/usb/gadget/udc/pxa27x_udc.h
index cea2cb79b30c..586c9bc9a748 100644
--- a/drivers/usb/gadget/udc/pxa27x_udc.h
+++ b/drivers/usb/gadget/udc/pxa27x_udc.h
@@ -261,6 +261,8 @@
 					USB_EP_CAPS_DIR_OUT)
 #define USB_EP_IN_INT(n)	USB_EP_INT(n,  "ep" #n "in-int", 1, \
 					USB_EP_CAPS_DIR_IN)
+#define USB_EP_OUT_INT(n)	USB_EP_INT(n,  "ep" #n "out-int", 0, \
+					USB_EP_CAPS_DIR_OUT)
 #define USB_EP_CTRL	USB_EP_DEF(0,  "ep0", 0, CONTROL, EP0_FIFO_SIZE, \
 				USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)
 
@@ -287,6 +289,7 @@
 #define PXA_EP_IN_ISO(i, adr, c, f, a)		PXA_EP_ISO(i, adr, 1, c, f, a)
 #define PXA_EP_OUT_ISO(i, adr, c, f, a)		PXA_EP_ISO(i, adr, 0, c, f, a)
 #define PXA_EP_IN_INT(i, adr, c, f, a)		PXA_EP_INT(i, adr, 1, c, f, a)
+#define PXA_EP_OUT_INT(i, adr, c, f, a)		PXA_EP_INT(i, adr, 0, c, f, a)
 #define PXA_EP_CTRL	PXA_EP_DEF(0, 0, 0, 0, EP0_FIFO_SIZE, 0, 0, 0)
 
 struct pxa27x_udc;
@@ -419,8 +422,8 @@ struct udc_stats {
 	unsigned long	irqs_reconfig;
 };
 
-#define NR_USB_ENDPOINTS (1 + 5)	/* ep0 + ep1in-bulk + .. + ep3in-iso */
-#define NR_PXA_ENDPOINTS (1 + 14)	/* ep0 + epA + epB + .. + epX */
+#define NR_USB_ENDPOINTS (1 + 14) /* ep0 + ep1in-int + .. + ep14out-int */
+#define NR_PXA_ENDPOINTS (1 + 23) /* ep0 + epA + epB + .. + epX */
 
 /**
  * struct pxa_udc - udc structure
-- 
2.11.0

