All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v2 0/3] fs/erofs: new filesystem
From: Gao Xiang @ 2022-01-05 11:57 UTC (permalink / raw)
  To: Huang Jianan; +Cc: Tom Rini, u-boot, linux-erofs
In-Reply-To: <20210825224042.GF858@bill-the-cat>

Hi Jianan,

On Wed, Aug 25, 2021 at 06:40:42PM -0400, Tom Rini wrote:
> On Mon, Aug 23, 2021 at 08:36:43PM +0800, Huang Jianan wrote:
> 
> > From: Huang Jianan <huangjianan@oppo.com>
> > 
> > Add erofs filesystem support.
> > 
> > The code is adapted from erofs-utils in order to reduce maintenance
> > burden and keep with the latest feature.
> > 
> > Changes since v1:
> >  - fix the inconsistency between From and SoB (Bin Meng);
> >  - add missing license header;
> > 
> > Huang Jianan (3):
> >   fs/erofs: add erofs filesystem support
> >   fs/erofs: add lz4 1.8.3 decompressor
> >   fs/erofs: add lz4 decompression support
> 
> Aside from what I've just now sent, can you please extend the existing
> py/tests/ to cover basic functionality here, ensure they run on sandbox
> and in CI?  Thanks.

Any further progress on this work? At least sync it up with erofs-utils
1.4?

Thanks,
Gao Xiang

> 
> -- 
> Tom



^ permalink raw reply

* Linux 4.19.224
From: Greg Kroah-Hartman @ 2022-01-05 11:58 UTC (permalink / raw)
  To: linux-kernel, akpm, torvalds, stable; +Cc: lwn, jslaby, Greg Kroah-Hartman

I'm announcing the release of the 4.19.224 kernel.

All users of the 4.19 kernel series must upgrade.

The updated 4.19.y git tree can be found at:
	git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git linux-4.19.y
and can be browsed at the normal kernel.org git web browser:
	https://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git;a=summary

thanks,

greg k-h

------------

 Documentation/admin-guide/kernel-parameters.txt   |    2 
 Makefile                                          |    2 
 drivers/android/binder_alloc.c                    |    2 
 drivers/hid/Kconfig                               |    1 
 drivers/i2c/i2c-dev.c                             |    3 
 drivers/input/joystick/spaceball.c                |   11 +
 drivers/input/mouse/appletouch.c                  |    4 
 drivers/input/serio/i8042-x86ia64io.h             |   21 ++
 drivers/input/serio/i8042.c                       |   54 ++++--
 drivers/net/ethernet/freescale/fman/fman_port.c   |   12 -
 drivers/net/ethernet/mellanox/mlx5/core/en_main.c |   11 -
 drivers/net/usb/pegasus.c                         |    4 
 drivers/nfc/st21nfca/i2c.c                        |   29 ++-
 drivers/platform/x86/apple-gmux.c                 |    2 
 drivers/scsi/lpfc/lpfc_debugfs.c                  |    4 
 drivers/scsi/vmw_pvscsi.c                         |    7 
 drivers/tee/tee_shm.c                             |  177 ++++++++--------------
 drivers/usb/gadget/function/f_fs.c                |    9 -
 drivers/usb/host/xhci-pci.c                       |    5 
 drivers/usb/mtu3/mtu3_gadget.c                    |    7 
 include/linux/tee_drv.h                           |    4 
 include/net/sctp/sctp.h                           |    6 
 include/net/sctp/structs.h                        |    3 
 include/uapi/linux/nfc.h                          |    6 
 net/ipv4/af_inet.c                                |   10 -
 net/ipv6/udp.c                                    |    2 
 net/sctp/diag.c                                   |   12 -
 net/sctp/endpointola.c                            |   23 +-
 net/sctp/socket.c                                 |   23 +-
 scripts/recordmcount.pl                           |    2 
 security/selinux/hooks.c                          |    2 
 tools/testing/selftests/net/udpgso.c              |   12 -
 tools/testing/selftests/net/udpgso_bench_tx.c     |    8 
 33 files changed, 267 insertions(+), 213 deletions(-)

Alexey Makhalov (1):
      scsi: vmw_pvscsi: Set residual data length conditionally

Chunfeng Yun (1):
      usb: mtu3: set interval of FS intr and isoc endpoint

Coco Li (2):
      udp: using datalen to cap ipv6 udp max gso segments
      selftests: Calculate udpgso segment count without header adjustment

Dan Carpenter (1):
      scsi: lpfc: Terminate string in lpfc_debugfs_nvmeio_trc_write()

Dmitry V. Levin (1):
      uapi: fix linux/nfc.h userspace compilation errors

Gal Pressman (1):
      net/mlx5e: Fix wrong features assignment in case of error

Greg Kroah-Hartman (1):
      Linux 4.19.224

Hans de Goede (1):
      HID: asus: Add depends on USB_HID to HID_ASUS Kconfig option

Heiko Carstens (1):
      recordmcount.pl: fix typo in s390 mcount regex

Jens Wiklander (1):
      tee: handle lookup of shm with reference count 0

Krzysztof Kozlowski (1):
      nfc: uapi: use kernel size_t to fix user-space builds

Leo L. Schwab (1):
      Input: spaceball - fix parsing of movement data packets

Mathias Nyman (1):
      xhci: Fresco FL1100 controller should not have BROKEN_MSI quirk set.

Matthias-Christian Ott (1):
      net: usb: pegasus: Do not drop long Ethernet frames

Miaoqian Lin (1):
      fsl/fman: Fix missing put_device() call in fman_port_probe

Muchun Song (1):
      net: fix use-after-free in tw_timer_handler

Pavel Skripkin (2):
      i2c: validate user data in compat ioctl
      Input: appletouch - initialize work before device registration

Samuel Čavoj (1):
      Input: i8042 - enable deferred probe quirk for ASUS UM325UA

Takashi Iwai (1):
      Input: i8042 - add deferred probe support

Todd Kjos (1):
      binder: fix async_free_space accounting for empty parcels

Tom Rix (1):
      selinux: initialize proto variable in selinux_ip_postroute_compat()

Vincent Pelletier (1):
      usb: gadget: f_fs: Clear ffs_eventfd in ffs_data_clear.

Wang Qing (1):
      platform/x86: apple-gmux: use resource_size() with res

Wei Yongjun (1):
      NFC: st21nfca: Fix memory leak in device probe and remove

Xin Long (1):
      sctp: use call_rcu to free endpoint

wujianguo (1):
      selftests/net: udpgso_bench_tx: fix dst ip argument


^ permalink raw reply

* Re: Linux 4.14.261
From: Greg Kroah-Hartman @ 2022-01-05 11:58 UTC (permalink / raw)
  To: linux-kernel, akpm, torvalds, stable; +Cc: lwn, jslaby, Greg Kroah-Hartman
In-Reply-To: <164138388915177@kroah.com>

diff --git a/Makefile b/Makefile
index 8a87f5c06a83..38e64d636717 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 VERSION = 4
 PATCHLEVEL = 14
-SUBLEVEL = 260
+SUBLEVEL = 261
 EXTRAVERSION =
 NAME = Petit Gorille
 
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index f89ea0866892..1687368ea71f 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -619,7 +619,7 @@ static void binder_free_buf_locked(struct binder_alloc *alloc,
 	BUG_ON(buffer->data > alloc->buffer + alloc->buffer_size);
 
 	if (buffer->async_transaction) {
-		alloc->free_async_space += size + sizeof(struct binder_buffer);
+		alloc->free_async_space += buffer_size + sizeof(struct binder_buffer);
 
 		binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC,
 			     "%d: binder_free_buf size %zd async free %zd\n",
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 5f5580fbd351..a4fb3fccf1b2 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -148,6 +148,7 @@ config HID_APPLEIR
 
 config HID_ASUS
 	tristate "Asus"
+	depends on USB_HID
 	depends on LEDS_CLASS
 	---help---
 	Support for Asus notebook built-in keyboard and touchpad via i2c, and
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index e9712a1b7cad..43bc432e1d3a 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -35,6 +35,7 @@
 #include <linux/module.h>
 #include <linux/input.h>
 #include <linux/serio.h>
+#include <asm/unaligned.h>
 
 #define DRIVER_DESC	"SpaceTec SpaceBall 2003/3003/4000 FLX driver"
 
@@ -91,9 +92,15 @@ static void spaceball_process_packet(struct spaceball* spaceball)
 
 		case 'D':					/* Ball data */
 			if (spaceball->idx != 15) return;
-			for (i = 0; i < 6; i++)
+			/*
+			 * Skip first three bytes; read six axes worth of data.
+			 * Axis values are signed 16-bit big-endian.
+			 */
+			data += 3;
+			for (i = 0; i < ARRAY_SIZE(spaceball_axes); i++) {
 				input_report_abs(dev, spaceball_axes[i],
-					(__s16)((data[2 * i + 3] << 8) | data[2 * i + 2]));
+					(__s16)get_unaligned_be16(&data[i * 2]));
+			}
 			break;
 
 		case 'K':					/* Button data */
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index 81a695d0b4e0..5b4f15a23293 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -929,6 +929,8 @@ static int atp_probe(struct usb_interface *iface,
 	set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
 	set_bit(BTN_LEFT, input_dev->keybit);
 
+	INIT_WORK(&dev->work, atp_reinit);
+
 	error = input_register_device(dev->input);
 	if (error)
 		goto err_free_buffer;
@@ -936,8 +938,6 @@ static int atp_probe(struct usb_interface *iface,
 	/* save our data pointer in this interface device */
 	usb_set_intfdata(iface, dev);
 
-	INIT_WORK(&dev->work, atp_reinit);
-
 	return 0;
 
  err_free_buffer:
diff --git a/drivers/net/ethernet/freescale/fman/fman_port.c b/drivers/net/ethernet/freescale/fman/fman_port.c
index ac3d791f5282..b7295f21aa58 100644
--- a/drivers/net/ethernet/freescale/fman/fman_port.c
+++ b/drivers/net/ethernet/freescale/fman/fman_port.c
@@ -1779,7 +1779,7 @@ static int fman_port_probe(struct platform_device *of_dev)
 	fman = dev_get_drvdata(&fm_pdev->dev);
 	if (!fman) {
 		err = -EINVAL;
-		goto return_err;
+		goto put_device;
 	}
 
 	err = of_property_read_u32(port_node, "cell-index", &val);
@@ -1787,7 +1787,7 @@ static int fman_port_probe(struct platform_device *of_dev)
 		dev_err(port->dev, "%s: reading cell-index for %pOF failed\n",
 			__func__, port_node);
 		err = -EINVAL;
-		goto return_err;
+		goto put_device;
 	}
 	port_id = (u8)val;
 	port->dts_params.id = port_id;
@@ -1821,7 +1821,7 @@ static int fman_port_probe(struct platform_device *of_dev)
 	}  else {
 		dev_err(port->dev, "%s: Illegal port type\n", __func__);
 		err = -EINVAL;
-		goto return_err;
+		goto put_device;
 	}
 
 	port->dts_params.type = port_type;
@@ -1835,7 +1835,7 @@ static int fman_port_probe(struct platform_device *of_dev)
 			dev_err(port->dev, "%s: incorrect qman-channel-id\n",
 				__func__);
 			err = -EINVAL;
-			goto return_err;
+			goto put_device;
 		}
 		port->dts_params.qman_channel_id = qman_channel_id;
 	}
@@ -1845,7 +1845,7 @@ static int fman_port_probe(struct platform_device *of_dev)
 		dev_err(port->dev, "%s: of_address_to_resource() failed\n",
 			__func__);
 		err = -ENOMEM;
-		goto return_err;
+		goto put_device;
 	}
 
 	port->dts_params.fman = fman;
@@ -1870,6 +1870,8 @@ static int fman_port_probe(struct platform_device *of_dev)
 
 	return 0;
 
+put_device:
+	put_device(&fm_pdev->dev);
 return_err:
 	of_node_put(port_node);
 free_port:
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index d18a283a0ccf..408b996ff4df 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -498,11 +498,11 @@ static void read_bulk_callback(struct urb *urb)
 		goto goon;
 
 	rx_status = buf[count - 2];
-	if (rx_status & 0x1e) {
+	if (rx_status & 0x1c) {
 		netif_dbg(pegasus, rx_err, net,
 			  "RX packet error %x\n", rx_status);
 		net->stats.rx_errors++;
-		if (rx_status & 0x06)	/* long or runt	*/
+		if (rx_status & 0x04)	/* runt	*/
 			net->stats.rx_length_errors++;
 		if (rx_status & 0x08)
 			net->stats.rx_crc_errors++;
diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c
index cd1f7bfa75eb..dc9dd66cf673 100644
--- a/drivers/nfc/st21nfca/i2c.c
+++ b/drivers/nfc/st21nfca/i2c.c
@@ -544,7 +544,8 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client,
 	phy->gpiod_ena = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
 	if (IS_ERR(phy->gpiod_ena)) {
 		nfc_err(dev, "Unable to get ENABLE GPIO\n");
-		return PTR_ERR(phy->gpiod_ena);
+		r = PTR_ERR(phy->gpiod_ena);
+		goto out_free;
 	}
 
 	phy->se_status.is_ese_present =
@@ -555,7 +556,7 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client,
 	r = st21nfca_hci_platform_init(phy);
 	if (r < 0) {
 		nfc_err(&client->dev, "Unable to reboot st21nfca\n");
-		return r;
+		goto out_free;
 	}
 
 	r = devm_request_threaded_irq(&client->dev, client->irq, NULL,
@@ -564,15 +565,23 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client,
 				ST21NFCA_HCI_DRIVER_NAME, phy);
 	if (r < 0) {
 		nfc_err(&client->dev, "Unable to register IRQ handler\n");
-		return r;
+		goto out_free;
 	}
 
-	return st21nfca_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME,
-					ST21NFCA_FRAME_HEADROOM,
-					ST21NFCA_FRAME_TAILROOM,
-					ST21NFCA_HCI_LLC_MAX_PAYLOAD,
-					&phy->hdev,
-					&phy->se_status);
+	r = st21nfca_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME,
+			       ST21NFCA_FRAME_HEADROOM,
+			       ST21NFCA_FRAME_TAILROOM,
+			       ST21NFCA_HCI_LLC_MAX_PAYLOAD,
+			       &phy->hdev,
+			       &phy->se_status);
+	if (r)
+		goto out_free;
+
+	return 0;
+
+out_free:
+	kfree_skb(phy->pending_skb);
+	return r;
 }
 
 static int st21nfca_hci_i2c_remove(struct i2c_client *client)
@@ -585,6 +594,8 @@ static int st21nfca_hci_i2c_remove(struct i2c_client *client)
 
 	if (phy->powered)
 		st21nfca_hci_i2c_disable(phy);
+	if (phy->pending_skb)
+		kfree_skb(phy->pending_skb);
 
 	return 0;
 }
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index 7c4eb86c851e..5463d740f352 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -628,7 +628,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
 	}
 
 	gmux_data->iostart = res->start;
-	gmux_data->iolen = res->end - res->start;
+	gmux_data->iolen = resource_size(res);
 
 	if (gmux_data->iolen < GMUX_MIN_IO_LEN) {
 		pr_err("gmux I/O region too small (%lu < %u)\n",
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index c77ad2b78ce4..39a1c9e18c0e 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -2177,8 +2177,8 @@ lpfc_debugfs_nvmeio_trc_write(struct file *file, const char __user *buf,
 	char mybuf[64];
 	char *pbuf;
 
-	if (nbytes > 64)
-		nbytes = 64;
+	if (nbytes > 63)
+		nbytes = 63;
 
 	memset(mybuf, 0, sizeof(mybuf));
 
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index 2c707b5c7b0b..68b5177bf09d 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -578,9 +578,12 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter,
 			 * Commands like INQUIRY may transfer less data than
 			 * requested by the initiator via bufflen. Set residual
 			 * count to make upper layer aware of the actual amount
-			 * of data returned.
+			 * of data returned. There are cases when controller
+			 * returns zero dataLen with non zero data - do not set
+			 * residual count in that case.
 			 */
-			scsi_set_resid(cmd, scsi_bufflen(cmd) - e->dataLen);
+			if (e->dataLen && (e->dataLen < scsi_bufflen(cmd)))
+				scsi_set_resid(cmd, scsi_bufflen(cmd) - e->dataLen);
 			cmd->result = (DID_OK << 16);
 			break;
 
diff --git a/drivers/tee/tee_private.h b/drivers/tee/tee_private.h
index 21cb6be8bce9..4ef325f782d1 100644
--- a/drivers/tee/tee_private.h
+++ b/drivers/tee/tee_private.h
@@ -31,7 +31,7 @@ struct tee_device;
  * @paddr:	physical address of the shared memory
  * @kaddr:	virtual address of the shared memory
  * @size:	size of shared memory
- * @dmabuf:	dmabuf used to for exporting to user space
+ * @refcount:	reference counter
  * @flags:	defined by TEE_SHM_* in tee_drv.h
  * @id:		unique id of a shared memory object on this device
  */
@@ -42,7 +42,7 @@ struct tee_shm {
 	phys_addr_t paddr;
 	void *kaddr;
 	size_t size;
-	struct dma_buf *dmabuf;
+	refcount_t refcount;
 	u32 flags;
 	int id;
 };
diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c
index ea3ce4e17b85..b8f171b9658b 100644
--- a/drivers/tee/tee_shm.c
+++ b/drivers/tee/tee_shm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, Linaro Limited
+ * Copyright (c) 2015-2017, 2019-2021 Linaro Limited
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -11,26 +11,19 @@
  * GNU General Public License for more details.
  *
  */
+#include <linux/anon_inodes.h>
 #include <linux/device.h>
-#include <linux/dma-buf.h>
-#include <linux/fdtable.h>
 #include <linux/idr.h>
+#include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/tee_drv.h>
 #include "tee_private.h"
 
-static void tee_shm_release(struct tee_shm *shm)
+static void tee_shm_release(struct tee_device *teedev, struct tee_shm *shm)
 {
-	struct tee_device *teedev = shm->teedev;
 	struct tee_shm_pool_mgr *poolm;
 
-	mutex_lock(&teedev->mutex);
-	idr_remove(&teedev->idr, shm->id);
-	if (shm->ctx)
-		list_del(&shm->link);
-	mutex_unlock(&teedev->mutex);
-
 	if (shm->flags & TEE_SHM_DMA_BUF)
 		poolm = &teedev->pool->dma_buf_mgr;
 	else
@@ -42,53 +35,6 @@ static void tee_shm_release(struct tee_shm *shm)
 	tee_device_put(teedev);
 }
 
-static struct sg_table *tee_shm_op_map_dma_buf(struct dma_buf_attachment
-			*attach, enum dma_data_direction dir)
-{
-	return NULL;
-}
-
-static void tee_shm_op_unmap_dma_buf(struct dma_buf_attachment *attach,
-				     struct sg_table *table,
-				     enum dma_data_direction dir)
-{
-}
-
-static void tee_shm_op_release(struct dma_buf *dmabuf)
-{
-	struct tee_shm *shm = dmabuf->priv;
-
-	tee_shm_release(shm);
-}
-
-static void *tee_shm_op_map_atomic(struct dma_buf *dmabuf, unsigned long pgnum)
-{
-	return NULL;
-}
-
-static void *tee_shm_op_map(struct dma_buf *dmabuf, unsigned long pgnum)
-{
-	return NULL;
-}
-
-static int tee_shm_op_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
-{
-	struct tee_shm *shm = dmabuf->priv;
-	size_t size = vma->vm_end - vma->vm_start;
-
-	return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT,
-			       size, vma->vm_page_prot);
-}
-
-static const struct dma_buf_ops tee_shm_dma_buf_ops = {
-	.map_dma_buf = tee_shm_op_map_dma_buf,
-	.unmap_dma_buf = tee_shm_op_unmap_dma_buf,
-	.release = tee_shm_op_release,
-	.map_atomic = tee_shm_op_map_atomic,
-	.map = tee_shm_op_map,
-	.mmap = tee_shm_op_mmap,
-};
-
 /**
  * tee_shm_alloc() - Allocate shared memory
  * @ctx:	Context that allocates the shared memory
@@ -135,6 +81,7 @@ struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
 		goto err_dev_put;
 	}
 
+	refcount_set(&shm->refcount, 1);
 	shm->flags = flags;
 	shm->teedev = teedev;
 	shm->ctx = ctx;
@@ -157,29 +104,11 @@ struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
 		goto err_pool_free;
 	}
 
-	if (flags & TEE_SHM_DMA_BUF) {
-		DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
-
-		exp_info.ops = &tee_shm_dma_buf_ops;
-		exp_info.size = shm->size;
-		exp_info.flags = O_RDWR;
-		exp_info.priv = shm;
-
-		shm->dmabuf = dma_buf_export(&exp_info);
-		if (IS_ERR(shm->dmabuf)) {
-			ret = ERR_CAST(shm->dmabuf);
-			goto err_rem;
-		}
-	}
 	mutex_lock(&teedev->mutex);
 	list_add_tail(&shm->link, &ctx->list_shm);
 	mutex_unlock(&teedev->mutex);
 
 	return shm;
-err_rem:
-	mutex_lock(&teedev->mutex);
-	idr_remove(&teedev->idr, shm->id);
-	mutex_unlock(&teedev->mutex);
 err_pool_free:
 	poolm->ops->free(poolm, shm);
 err_kfree:
@@ -190,6 +119,31 @@ struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
 }
 EXPORT_SYMBOL_GPL(tee_shm_alloc);
 
+static int tee_shm_fop_release(struct inode *inode, struct file *filp)
+{
+	tee_shm_put(filp->private_data);
+	return 0;
+}
+
+static int tee_shm_fop_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct tee_shm *shm = filp->private_data;
+	size_t size = vma->vm_end - vma->vm_start;
+
+	/* check for overflowing the buffer's size */
+	if (vma->vm_pgoff + vma_pages(vma) > shm->size >> PAGE_SHIFT)
+		return -EINVAL;
+
+	return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT,
+			       size, vma->vm_page_prot);
+}
+
+static const struct file_operations tee_shm_fops = {
+	.owner = THIS_MODULE,
+	.release = tee_shm_fop_release,
+	.mmap = tee_shm_fop_mmap,
+};
+
 /**
  * tee_shm_get_fd() - Increase reference count and return file descriptor
  * @shm:	Shared memory handle
@@ -203,10 +157,11 @@ int tee_shm_get_fd(struct tee_shm *shm)
 	if ((shm->flags & req_flags) != req_flags)
 		return -EINVAL;
 
-	get_dma_buf(shm->dmabuf);
-	fd = dma_buf_fd(shm->dmabuf, O_CLOEXEC);
+	/* matched by tee_shm_put() in tee_shm_op_release() */
+	refcount_inc(&shm->refcount);
+	fd = anon_inode_getfd("tee_shm", &tee_shm_fops, shm, O_RDWR);
 	if (fd < 0)
-		dma_buf_put(shm->dmabuf);
+		tee_shm_put(shm);
 	return fd;
 }
 
@@ -216,17 +171,7 @@ int tee_shm_get_fd(struct tee_shm *shm)
  */
 void tee_shm_free(struct tee_shm *shm)
 {
-	/*
-	 * dma_buf_put() decreases the dmabuf reference counter and will
-	 * call tee_shm_release() when the last reference is gone.
-	 *
-	 * In the case of driver private memory we call tee_shm_release
-	 * directly instead as it doesn't have a reference counter.
-	 */
-	if (shm->flags & TEE_SHM_DMA_BUF)
-		dma_buf_put(shm->dmabuf);
-	else
-		tee_shm_release(shm);
+	tee_shm_put(shm);
 }
 EXPORT_SYMBOL_GPL(tee_shm_free);
 
@@ -327,10 +272,15 @@ struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id)
 	teedev = ctx->teedev;
 	mutex_lock(&teedev->mutex);
 	shm = idr_find(&teedev->idr, id);
+	/*
+	 * If the tee_shm was found in the IDR it must have a refcount
+	 * larger than 0 due to the guarantee in tee_shm_put() below. So
+	 * it's safe to use refcount_inc().
+	 */
 	if (!shm || shm->ctx != ctx)
 		shm = ERR_PTR(-EINVAL);
-	else if (shm->flags & TEE_SHM_DMA_BUF)
-		get_dma_buf(shm->dmabuf);
+	else
+		refcount_inc(&shm->refcount);
 	mutex_unlock(&teedev->mutex);
 	return shm;
 }
@@ -353,7 +303,24 @@ EXPORT_SYMBOL_GPL(tee_shm_get_id);
  */
 void tee_shm_put(struct tee_shm *shm)
 {
-	if (shm->flags & TEE_SHM_DMA_BUF)
-		dma_buf_put(shm->dmabuf);
+	struct tee_device *teedev = shm->teedev;
+	bool do_release = false;
+
+	mutex_lock(&teedev->mutex);
+	if (refcount_dec_and_test(&shm->refcount)) {
+		/*
+		 * refcount has reached 0, we must now remove it from the
+		 * IDR before releasing the mutex.  This will guarantee
+		 * that the refcount_inc() in tee_shm_get_from_id() never
+		 * starts from 0.
+		 */
+		if (shm->ctx)
+			list_del(&shm->link);
+		do_release = true;
+	}
+	mutex_unlock(&teedev->mutex);
+
+	if (do_release)
+		tee_shm_release(teedev, shm);
 }
 EXPORT_SYMBOL_GPL(tee_shm_put);
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 5dfe926c251a..6029f9b00b4a 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -1688,11 +1688,15 @@ static void ffs_data_clear(struct ffs_data *ffs)
 
 	BUG_ON(ffs->gadget);
 
-	if (ffs->epfiles)
+	if (ffs->epfiles) {
 		ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
+		ffs->epfiles = NULL;
+	}
 
-	if (ffs->ffs_eventfd)
+	if (ffs->ffs_eventfd) {
 		eventfd_ctx_put(ffs->ffs_eventfd);
+		ffs->ffs_eventfd = NULL;
+	}
 
 	kfree(ffs->raw_descs_data);
 	kfree(ffs->raw_strings);
@@ -1705,7 +1709,6 @@ static void ffs_data_reset(struct ffs_data *ffs)
 
 	ffs_data_clear(ffs);
 
-	ffs->epfiles = NULL;
 	ffs->raw_descs_data = NULL;
 	ffs->raw_descs = NULL;
 	ffs->raw_strings = NULL;
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 0e419cb53de4..bf649af49cbd 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -100,7 +100,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
 	/* Look for vendor-specific quirks */
 	if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
 			(pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK ||
-			 pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1100 ||
 			 pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1400)) {
 		if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK &&
 				pdev->revision == 0x0) {
@@ -135,6 +134,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
 			pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1009)
 		xhci->quirks |= XHCI_BROKEN_STREAMS;
 
+	if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
+			pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1100)
+		xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+
 	if (pdev->vendor == PCI_VENDOR_ID_NEC)
 		xhci->quirks |= XHCI_NEC_HOST;
 
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index c713bd62428f..6c20a08a54ae 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -118,6 +118,7 @@ extern struct percpu_counter sctp_sockets_allocated;
 int sctp_asconf_mgmt(struct sctp_sock *, struct sctp_sockaddr_entry *);
 struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *);
 
+typedef int (*sctp_callback_t)(struct sctp_endpoint *, struct sctp_transport *, void *);
 int sctp_transport_walk_start(struct rhashtable_iter *iter);
 void sctp_transport_walk_stop(struct rhashtable_iter *iter);
 struct sctp_transport *sctp_transport_get_next(struct net *net,
@@ -128,9 +129,8 @@ int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *),
 				  struct net *net,
 				  const union sctp_addr *laddr,
 				  const union sctp_addr *paddr, void *p);
-int sctp_for_each_transport(int (*cb)(struct sctp_transport *, void *),
-			    int (*cb_done)(struct sctp_transport *, void *),
-			    struct net *net, int *pos, void *p);
+int sctp_transport_traverse_process(sctp_callback_t cb, sctp_callback_t cb_done,
+				    struct net *net, int *pos, void *p);
 int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *), void *p);
 int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc,
 		       struct sctp_info *info);
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 5831a304e61b..adbd8ad778f4 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -1272,6 +1272,7 @@ struct sctp_endpoint {
 	      reconf_enable:1;
 
 	__u8  strreset_enable;
+	struct rcu_head rcu;
 };
 
 /* Recover the outter endpoint structure. */
@@ -1287,7 +1288,7 @@ static inline struct sctp_endpoint *sctp_ep(struct sctp_ep_common *base)
 struct sctp_endpoint *sctp_endpoint_new(struct sock *, gfp_t);
 void sctp_endpoint_free(struct sctp_endpoint *);
 void sctp_endpoint_put(struct sctp_endpoint *);
-void sctp_endpoint_hold(struct sctp_endpoint *);
+int sctp_endpoint_hold(struct sctp_endpoint *ep);
 void sctp_endpoint_add_asoc(struct sctp_endpoint *, struct sctp_association *);
 struct sctp_association *sctp_endpoint_lookup_assoc(
 	const struct sctp_endpoint *ep,
diff --git a/include/uapi/linux/nfc.h b/include/uapi/linux/nfc.h
index 399f39ff8048..1b6d54a328ba 100644
--- a/include/uapi/linux/nfc.h
+++ b/include/uapi/linux/nfc.h
@@ -261,7 +261,7 @@ enum nfc_sdp_attr {
 #define NFC_SE_ENABLED  0x1
 
 struct sockaddr_nfc {
-	sa_family_t sa_family;
+	__kernel_sa_family_t sa_family;
 	__u32 dev_idx;
 	__u32 target_idx;
 	__u32 nfc_protocol;
@@ -269,14 +269,14 @@ struct sockaddr_nfc {
 
 #define NFC_LLCP_MAX_SERVICE_NAME 63
 struct sockaddr_nfc_llcp {
-	sa_family_t sa_family;
+	__kernel_sa_family_t sa_family;
 	__u32 dev_idx;
 	__u32 target_idx;
 	__u32 nfc_protocol;
 	__u8 dsap; /* Destination SAP, if known */
 	__u8 ssap; /* Source SAP to be bound to */
 	char service_name[NFC_LLCP_MAX_SERVICE_NAME]; /* Service name URI */;
-	size_t service_name_len;
+	__kernel_size_t service_name_len;
 };
 
 /* NFC socket protocols */
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index f31c09873d0f..d0ef51d49f8a 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1883,6 +1883,10 @@ static int __init inet_init(void)
 
 	ip_init();
 
+	/* Initialise per-cpu ipv4 mibs */
+	if (init_ipv4_mibs())
+		panic("%s: Cannot init ipv4 mibs\n", __func__);
+
 	/* Setup TCP slab cache for open requests. */
 	tcp_init();
 
@@ -1911,12 +1915,6 @@ static int __init inet_init(void)
 
 	if (init_inet_pernet_ops())
 		pr_crit("%s: Cannot init ipv4 inet pernet ops\n", __func__);
-	/*
-	 *	Initialise per-cpu ipv4 mibs
-	 */
-
-	if (init_ipv4_mibs())
-		pr_crit("%s: Cannot init ipv4 mibs\n", __func__);
 
 	ipv4_proc_init();
 
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c
index c71b4191df1e..8d3ee8bb6181 100644
--- a/net/sctp/endpointola.c
+++ b/net/sctp/endpointola.c
@@ -242,6 +242,18 @@ void sctp_endpoint_free(struct sctp_endpoint *ep)
 }
 
 /* Final destructor for endpoint.  */
+static void sctp_endpoint_destroy_rcu(struct rcu_head *head)
+{
+	struct sctp_endpoint *ep = container_of(head, struct sctp_endpoint, rcu);
+	struct sock *sk = ep->base.sk;
+
+	sctp_sk(sk)->ep = NULL;
+	sock_put(sk);
+
+	kfree(ep);
+	SCTP_DBG_OBJCNT_DEC(ep);
+}
+
 static void sctp_endpoint_destroy(struct sctp_endpoint *ep)
 {
 	struct sock *sk;
@@ -275,18 +287,13 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep)
 	if (sctp_sk(sk)->bind_hash)
 		sctp_put_port(sk);
 
-	sctp_sk(sk)->ep = NULL;
-	/* Give up our hold on the sock */
-	sock_put(sk);
-
-	kfree(ep);
-	SCTP_DBG_OBJCNT_DEC(ep);
+	call_rcu(&ep->rcu, sctp_endpoint_destroy_rcu);
 }
 
 /* Hold a reference to an endpoint. */
-void sctp_endpoint_hold(struct sctp_endpoint *ep)
+int sctp_endpoint_hold(struct sctp_endpoint *ep)
 {
-	refcount_inc(&ep->base.refcnt);
+	return refcount_inc_not_zero(&ep->base.refcnt);
 }
 
 /* Release a reference to an endpoint and clean up if there are
diff --git a/net/sctp/sctp_diag.c b/net/sctp/sctp_diag.c
index 6a5a3dfa6c8d..7c7b476bad31 100644
--- a/net/sctp/sctp_diag.c
+++ b/net/sctp/sctp_diag.c
@@ -276,9 +276,8 @@ static int sctp_tsp_dump_one(struct sctp_transport *tsp, void *p)
 	return err;
 }
 
-static int sctp_sock_dump(struct sctp_transport *tsp, void *p)
+static int sctp_sock_dump(struct sctp_endpoint *ep, struct sctp_transport *tsp, void *p)
 {
-	struct sctp_endpoint *ep = tsp->asoc->ep;
 	struct sctp_comm_param *commp = p;
 	struct sock *sk = ep->base.sk;
 	struct sk_buff *skb = commp->skb;
@@ -288,6 +287,8 @@ static int sctp_sock_dump(struct sctp_transport *tsp, void *p)
 	int err = 0;
 
 	lock_sock(sk);
+	if (ep != tsp->asoc->ep)
+		goto release;
 	list_for_each_entry(assoc, &ep->asocs, asocs) {
 		if (cb->args[4] < cb->args[1])
 			goto next;
@@ -330,9 +331,8 @@ static int sctp_sock_dump(struct sctp_transport *tsp, void *p)
 	return err;
 }
 
-static int sctp_sock_filter(struct sctp_transport *tsp, void *p)
+static int sctp_sock_filter(struct sctp_endpoint *ep, struct sctp_transport *tsp, void *p)
 {
-	struct sctp_endpoint *ep = tsp->asoc->ep;
 	struct sctp_comm_param *commp = p;
 	struct sock *sk = ep->base.sk;
 	const struct inet_diag_req_v2 *r = commp->r;
@@ -490,8 +490,8 @@ static void sctp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
 	if (!(idiag_states & ~(TCPF_LISTEN | TCPF_CLOSE)))
 		goto done;
 
-	sctp_for_each_transport(sctp_sock_filter, sctp_sock_dump,
-				net, &pos, &commp);
+	sctp_transport_traverse_process(sctp_sock_filter, sctp_sock_dump,
+					net, &pos, &commp);
 	cb->args[2] = pos;
 
 done:
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 8d64caa72cba..fac24f329c1d 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -4738,11 +4738,12 @@ int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *),
 }
 EXPORT_SYMBOL_GPL(sctp_transport_lookup_process);
 
-int sctp_for_each_transport(int (*cb)(struct sctp_transport *, void *),
-			    int (*cb_done)(struct sctp_transport *, void *),
-			    struct net *net, int *pos, void *p) {
+int sctp_transport_traverse_process(sctp_callback_t cb, sctp_callback_t cb_done,
+				    struct net *net, int *pos, void *p)
+{
 	struct rhashtable_iter hti;
 	struct sctp_transport *tsp;
+	struct sctp_endpoint *ep;
 	int ret;
 
 again:
@@ -4752,26 +4753,32 @@ int sctp_for_each_transport(int (*cb)(struct sctp_transport *, void *),
 
 	tsp = sctp_transport_get_idx(net, &hti, *pos + 1);
 	for (; !IS_ERR_OR_NULL(tsp); tsp = sctp_transport_get_next(net, &hti)) {
-		ret = cb(tsp, p);
-		if (ret)
-			break;
+		ep = tsp->asoc->ep;
+		if (sctp_endpoint_hold(ep)) { /* asoc can be peeled off */
+			ret = cb(ep, tsp, p);
+			if (ret)
+				break;
+			sctp_endpoint_put(ep);
+		}
 		(*pos)++;
 		sctp_transport_put(tsp);
 	}
 	sctp_transport_walk_stop(&hti);
 
 	if (ret) {
-		if (cb_done && !cb_done(tsp, p)) {
+		if (cb_done && !cb_done(ep, tsp, p)) {
 			(*pos)++;
+			sctp_endpoint_put(ep);
 			sctp_transport_put(tsp);
 			goto again;
 		}
+		sctp_endpoint_put(ep);
 		sctp_transport_put(tsp);
 	}
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(sctp_for_each_transport);
+EXPORT_SYMBOL_GPL(sctp_transport_traverse_process);
 
 /* 7.2.1 Association Status (SCTP_STATUS)
 
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl
index ebc78cb3bc7d..5a5916fe5692 100755
--- a/scripts/recordmcount.pl
+++ b/scripts/recordmcount.pl
@@ -252,7 +252,7 @@ if ($arch eq "x86_64") {
 
 } elsif ($arch eq "s390" && $bits == 64) {
     if ($cc =~ /-DCC_USING_HOTPATCH/) {
-	$mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*(bcrl\\s*0,|jgnop\\s*)[0-9a-f]+ <([^\+]*)>\$";
+	$mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*(brcl\\s*0,|jgnop\\s*)[0-9a-f]+ <([^\+]*)>\$";
 	$mcount_adjust = 0;
     } else {
 	$mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$";
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 9bb1d492f704..38a4db1f3aaa 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5321,7 +5321,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
 	struct common_audit_data ad;
 	struct lsm_network_audit net = {0,};
 	char *addrp;
-	u8 proto;
+	u8 proto = 0;
 
 	if (sk == NULL)
 		return NF_ACCEPT;

^ permalink raw reply related

* Linux 4.14.261
From: Greg Kroah-Hartman @ 2022-01-05 11:58 UTC (permalink / raw)
  To: linux-kernel, akpm, torvalds, stable; +Cc: lwn, jslaby, Greg Kroah-Hartman

I'm announcing the release of the 4.14.261 kernel.

All users of the 4.14 kernel series must upgrade.

The updated 4.14.y git tree can be found at:
	git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git linux-4.14.y
and can be browsed at the normal kernel.org git web browser:
	https://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git;a=summary

thanks,

greg k-h

------------

 Makefile                                        |    2 
 drivers/android/binder_alloc.c                  |    2 
 drivers/hid/Kconfig                             |    1 
 drivers/input/joystick/spaceball.c              |   11 +
 drivers/input/mouse/appletouch.c                |    4 
 drivers/net/ethernet/freescale/fman/fman_port.c |   12 +
 drivers/net/usb/pegasus.c                       |    4 
 drivers/nfc/st21nfca/i2c.c                      |   29 +++-
 drivers/platform/x86/apple-gmux.c               |    2 
 drivers/scsi/lpfc/lpfc_debugfs.c                |    4 
 drivers/scsi/vmw_pvscsi.c                       |    7 -
 drivers/tee/tee_private.h                       |    4 
 drivers/tee/tee_shm.c                           |  155 +++++++++---------------
 drivers/usb/gadget/function/f_fs.c              |    9 -
 drivers/usb/host/xhci-pci.c                     |    5 
 include/net/sctp/sctp.h                         |    6 
 include/net/sctp/structs.h                      |    3 
 include/uapi/linux/nfc.h                        |    6 
 net/ipv4/af_inet.c                              |   10 -
 net/sctp/endpointola.c                          |   23 ++-
 net/sctp/sctp_diag.c                            |   12 -
 net/sctp/socket.c                               |   23 ++-
 scripts/recordmcount.pl                         |    2 
 security/selinux/hooks.c                        |    2 
 24 files changed, 174 insertions(+), 164 deletions(-)

Alexey Makhalov (1):
      scsi: vmw_pvscsi: Set residual data length conditionally

Dan Carpenter (1):
      scsi: lpfc: Terminate string in lpfc_debugfs_nvmeio_trc_write()

Dmitry V. Levin (1):
      uapi: fix linux/nfc.h userspace compilation errors

Greg Kroah-Hartman (1):
      Linux 4.14.261

Hans de Goede (1):
      HID: asus: Add depends on USB_HID to HID_ASUS Kconfig option

Heiko Carstens (1):
      recordmcount.pl: fix typo in s390 mcount regex

Jens Wiklander (1):
      tee: handle lookup of shm with reference count 0

Krzysztof Kozlowski (1):
      nfc: uapi: use kernel size_t to fix user-space builds

Leo L. Schwab (1):
      Input: spaceball - fix parsing of movement data packets

Mathias Nyman (1):
      xhci: Fresco FL1100 controller should not have BROKEN_MSI quirk set.

Matthias-Christian Ott (1):
      net: usb: pegasus: Do not drop long Ethernet frames

Miaoqian Lin (1):
      fsl/fman: Fix missing put_device() call in fman_port_probe

Muchun Song (1):
      net: fix use-after-free in tw_timer_handler

Pavel Skripkin (1):
      Input: appletouch - initialize work before device registration

Todd Kjos (1):
      binder: fix async_free_space accounting for empty parcels

Tom Rix (1):
      selinux: initialize proto variable in selinux_ip_postroute_compat()

Vincent Pelletier (1):
      usb: gadget: f_fs: Clear ffs_eventfd in ffs_data_clear.

Wang Qing (1):
      platform/x86: apple-gmux: use resource_size() with res

Wei Yongjun (1):
      NFC: st21nfca: Fix memory leak in device probe and remove

Xin Long (1):
      sctp: use call_rcu to free endpoint


^ permalink raw reply

* [PATCH v6 7/7] usb: gadget: uvc: add format/frame handling code
From: Michael Grzeschik @ 2022-01-05 11:55 UTC (permalink / raw)
  To: linux-usb; +Cc: balbi, laurent.pinchart, paul.elder, kernel
In-Reply-To: <20220105115527.3592860-1-m.grzeschik@pengutronix.de>

The Hostside format selection is currently only done in userspace, as
the events for SET_CUR and GET_CUR are allways moved to the application
layer. Since the v4l2 device parses the configfs data, the format
negotiation can be done in the kernel. This patch adds the functions to
set the current configuration while continuing to forward all unknown
events to the userspace level.

Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>

---
v1 -> v2:
   - fixed the commit message
   - changed pr_debug to pr_err in events_process_data
   - aligned many indentations
   - simplified uvc_events_process_data
   - fixed uvc_fill_streaming_control calls in uvcg_video_init
   - added setup_subscribed to decide if userspace takes over on EOPNOTSUPP
   - added data_subscribed to decide if userspace takes over on EOPNOTSUPP
   - removed duplicate send_response
   - wrting fmt and frm in full
v2 -> v3:
   - added find_format_index to set the right probe
v3 -> v4:
   - add function find_ival_index and use for cur_ival
   - fix swapped frame and format in uvc_events_process_data on uvc_fill_streaming_control
   - set proper resp.length on ep0 complete
   - dropped setting cur_probe on set_format since function was removed
   - added locking around getting correspondent cur_{frame,format,ival}
v4 -> v5:
   - fixed sparse errors reported by kernel test robot
v5 -> v6:
   - fixed the handling in uvc_function_ep0_complete after events_process_data

 drivers/usb/gadget/function/f_uvc.c     | 234 +++++++++++++++++++++++-
 drivers/usb/gadget/function/uvc.h       |  19 ++
 drivers/usb/gadget/function/uvc_v4l2.c  |  66 ++++++-
 drivers/usb/gadget/function/uvc_video.c |  12 +-
 4 files changed, 319 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index e081a4e6572ee2..23028adf0ff3fe 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -16,7 +16,6 @@
 #include <linux/string.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
-#include <linux/usb/g_uvc.h>
 #include <linux/usb/video.h>
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
@@ -200,21 +199,225 @@ static const struct usb_descriptor_header * const uvc_ss_streaming[] = {
  * Control requests
  */
 
+void uvc_fill_streaming_control(struct uvc_device *uvc,
+			   struct uvc_streaming_control *ctrl,
+			   int iframe, int iformat, unsigned int ival)
+{
+	struct uvcg_format *uformat;
+	struct uvcg_frame *uframe;
+
+	/* Restrict the iformat, iframe and ival to valid values. Negative
+	 * values for ifrmat and iframe will result in the maximum valid value
+	 * being selected
+	 */
+	iformat = clamp((unsigned int)iformat, 1U,
+			(unsigned int)uvc->header->num_fmt);
+	uformat = find_format_by_index(uvc, iformat);
+	if (!uformat)
+		return;
+
+	iframe = clamp((unsigned int)iframe, 1U,
+		       (unsigned int)uformat->num_frames);
+	uframe = find_frame_by_index(uvc, uformat, iframe);
+	if (!uframe)
+		return;
+
+	ival = clamp((unsigned int)ival, 1U,
+		     (unsigned int)uframe->frame.b_frame_interval_type);
+	if (!uframe->dw_frame_interval[ival - 1])
+		return;
+
+	memset(ctrl, 0, sizeof(*ctrl));
+
+	ctrl->bmHint = 1;
+	ctrl->bFormatIndex = iformat;
+	ctrl->bFrameIndex = iframe;
+	ctrl->dwFrameInterval = uframe->dw_frame_interval[ival - 1];
+	ctrl->dwMaxVideoFrameSize =
+		uframe->frame.dw_max_video_frame_buffer_size;
+
+	if (uvc->video.ep->desc)
+		ctrl->dwMaxPayloadTransferSize =
+			le16_to_cpu(uvc->video.ep->desc->wMaxPacketSize);
+	ctrl->bmFramingInfo = 3;
+	ctrl->bPreferedVersion = 1;
+	ctrl->bMaxVersion = 1;
+}
+
+static int uvc_events_process_data(struct uvc_device *uvc,
+				   struct usb_request *req)
+{
+	struct uvc_video *video = &uvc->video;
+	struct uvc_streaming_control *target;
+	struct uvc_streaming_control *ctrl;
+	struct uvcg_frame *uframe;
+	struct uvcg_format *uformat;
+
+	switch (video->control) {
+	case UVC_VS_PROBE_CONTROL:
+		pr_debug("setting probe control, length = %d\n", req->actual);
+		target = &video->probe;
+		break;
+
+	case UVC_VS_COMMIT_CONTROL:
+		pr_debug("setting commit control, length = %d\n", req->actual);
+		target = &video->commit;
+		break;
+
+	default:
+		pr_err("setting unknown control, length = %d\n", req->actual);
+		return -EOPNOTSUPP;
+	}
+
+	ctrl = (struct uvc_streaming_control *)req->buf;
+
+	uvc_fill_streaming_control(uvc, target, ctrl->bFrameIndex,
+			   ctrl->bFormatIndex, ctrl->dwFrameInterval);
+
+	if (video->control == UVC_VS_COMMIT_CONTROL) {
+		uformat = find_format_by_index(uvc, target->bFormatIndex);
+		if (!uformat)
+			return -EINVAL;
+
+		uframe = find_frame_by_index(uvc, uformat, ctrl->bFrameIndex);
+		if (!uframe)
+			return -EINVAL;
+
+		spin_lock(&video->frame_lock);
+
+		video->cur_frame = uframe;
+		video->cur_format = uformat;
+		video->cur_ival = find_ival_index(uframe, ctrl->dwFrameInterval);
+
+		spin_unlock(&video->frame_lock);
+	}
+
+	return 0;
+}
+
+static void
+uvc_events_process_streaming(struct uvc_device *uvc, uint8_t req, uint8_t cs,
+			     struct uvc_request_data *resp)
+{
+	struct uvc_streaming_control *ctrl;
+
+	pr_debug("streaming request (req %02x cs %02x)\n", req, cs);
+
+	if (cs != UVC_VS_PROBE_CONTROL && cs != UVC_VS_COMMIT_CONTROL)
+		return;
+
+	ctrl = (struct uvc_streaming_control *)&resp->data;
+	resp->length = sizeof(*ctrl);
+
+	switch (req) {
+	case UVC_SET_CUR:
+		uvc->video.control = cs;
+		resp->length = 34;
+		break;
+
+	case UVC_GET_CUR:
+		if (cs == UVC_VS_PROBE_CONTROL)
+			memcpy(ctrl, &uvc->video.probe, sizeof(*ctrl));
+		else
+			memcpy(ctrl, &uvc->video.commit, sizeof(*ctrl));
+		break;
+
+	case UVC_GET_MIN:
+	case UVC_GET_MAX:
+	case UVC_GET_DEF:
+		if (req == UVC_GET_MAX)
+			uvc_fill_streaming_control(uvc, ctrl, -1, -1, UINT_MAX);
+		else
+			uvc_fill_streaming_control(uvc, ctrl, 1, 1, 0);
+		break;
+
+	case UVC_GET_RES:
+		memset(ctrl, 0, sizeof(*ctrl));
+		break;
+
+	case UVC_GET_LEN:
+		resp->data[0] = 0x00;
+		resp->data[1] = 0x22;
+		resp->length = 2;
+		break;
+
+	case UVC_GET_INFO:
+		resp->data[0] = 0x03;
+		resp->length = 1;
+		break;
+	}
+}
+
+static int
+uvc_events_process_class(struct uvc_device *uvc,
+			 const struct usb_ctrlrequest *ctrl,
+			 struct uvc_request_data *resp)
+{
+	if ((ctrl->bRequestType & USB_RECIP_MASK) != USB_RECIP_INTERFACE)
+		return -EINVAL;
+
+	if (le16_to_cpu(ctrl->wIndex) == uvc->control_intf)
+		return -EOPNOTSUPP;
+	else if (le16_to_cpu(ctrl->wIndex) == uvc->streaming_intf)
+		uvc_events_process_streaming(uvc, ctrl->bRequest,
+					     le16_to_cpu(ctrl->wValue) >> 8,
+					     resp);
+
+	return 0;
+}
+
+static int
+uvc_events_process_setup(struct uvc_device *uvc,
+			 const struct usb_ctrlrequest *ctrl,
+			 struct uvc_request_data *resp)
+{
+	uvc->video.control = 0;
+
+	pr_debug("bRequestType %02x bRequest %02x wValue %04x wIndex %04x wLength %04x\n",
+		ctrl->bRequestType, ctrl->bRequest, ctrl->wValue,
+		ctrl->wIndex, ctrl->wLength);
+
+	switch (ctrl->bRequestType & USB_TYPE_MASK) {
+	case USB_TYPE_STANDARD:
+		return -EOPNOTSUPP;
+
+	case USB_TYPE_CLASS:
+		return uvc_events_process_class(uvc, ctrl, resp);
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
 static void
 uvc_function_ep0_complete(struct usb_ep *ep, struct usb_request *req)
 {
 	struct uvc_device *uvc = req->context;
 	struct v4l2_event v4l2_event;
 	struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
+	int ret;
 
 	if (uvc->event_setup_out) {
 		uvc->event_setup_out = 0;
 
-		memset(&v4l2_event, 0, sizeof(v4l2_event));
-		v4l2_event.type = UVC_EVENT_DATA;
-		uvc_event->data.length = req->actual;
-		memcpy(&uvc_event->data.data, req->buf, req->actual);
-		v4l2_event_queue(&uvc->vdev, &v4l2_event);
+		ret = uvc_events_process_data(uvc, req);
+		/* If we have a real error on process */
+		if (ret == -EINVAL) {
+			struct uvc_request_data resp;
+
+			memset(&resp, 0, sizeof(resp));
+			resp.length = -EL2HLT;
+
+			uvc_send_response(uvc, &resp);
+		} else if (ret == -EOPNOTSUPP && uvc->data_subscribed) {
+			memset(&v4l2_event, 0, sizeof(v4l2_event));
+			v4l2_event.type = UVC_EVENT_DATA;
+			uvc_event->data.length = req->actual;
+			memcpy(&uvc_event->data.data, req->buf, req->actual);
+			v4l2_event_queue(&uvc->vdev, &v4l2_event);
+		}
 	}
 }
 
@@ -224,6 +427,8 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
 	struct uvc_device *uvc = to_uvc(f);
 	struct v4l2_event v4l2_event;
 	struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
+	struct uvc_request_data resp;
+	int ret = 0;
 
 	if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) {
 		uvcg_info(f, "invalid request type\n");
@@ -240,6 +445,23 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
 	uvc->event_setup_out = !(ctrl->bRequestType & USB_DIR_IN);
 	uvc->event_length = le16_to_cpu(ctrl->wLength);
 
+	memset(&resp, 0, sizeof(resp));
+	resp.length = -EL2HLT;
+
+	ret = uvc_events_process_setup(uvc, ctrl, &resp);
+	/* If we have no error on process */
+	if (!ret)
+		return uvc_send_response(uvc, &resp);
+
+	/* If we have a real error on process */
+	if (ret != -EOPNOTSUPP)
+		return ret;
+
+	/* If we have -EOPNOTSUPP */
+	if (!uvc->setup_subscribed)
+		return uvc_send_response(uvc, &resp);
+
+	/* If we have setup subscribed */
 	memset(&v4l2_event, 0, sizeof(v4l2_event));
 	v4l2_event.type = UVC_EVENT_SETUP;
 	memcpy(&uvc_event->req, ctrl, sizeof(uvc_event->req));
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index b7246b4bee1d87..a9984d26ebe043 100644
--- a/drivers/usb/gadget/function/uvc.h
+++ b/drivers/usb/gadget/function/uvc.h
@@ -13,6 +13,8 @@
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
 #include <linux/usb/composite.h>
+#include <linux/usb/g_uvc.h>
+#include <linux/usb/video.h>
 #include <linux/videodev2.h>
 
 #include <media/v4l2-device.h>
@@ -93,6 +95,12 @@ struct uvc_video {
 	unsigned int cur_ival;
 
 	struct mutex mutex;	/* protects frame parameters */
+	spinlock_t frame_lock;
+
+	struct uvc_streaming_control probe;
+	struct uvc_streaming_control commit;
+
+	int control;
 
 	unsigned int uvc_num_requests;
 
@@ -128,6 +136,8 @@ struct uvc_device {
 	struct usb_function func;
 	struct uvc_video video;
 	bool func_connected;
+	bool setup_subscribed;
+	bool data_subscribed;
 
 	struct uvcg_streaming_header *header;
 
@@ -183,5 +193,14 @@ extern struct uvcg_format *find_format_by_index(struct uvc_device *uvc,
 extern struct uvcg_frame *find_frame_by_index(struct uvc_device *uvc,
 					      struct uvcg_format *uformat,
 					      int index);
+extern int find_format_index(struct uvc_device *uvc,
+			       struct uvcg_format *uformat);
+extern int find_ival_index(struct uvcg_frame *uframe, int dwFrameInterval);
+extern void uvc_fill_streaming_control(struct uvc_device *uvc,
+				       struct uvc_streaming_control *ctrl,
+				       int iframe, int iformat,
+				       unsigned int ival);
+extern int uvc_send_response(struct uvc_device *uvc,
+			     struct uvc_request_data *data);
 
 #endif /* _UVC_GADGET_H_ */
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index e4c4884806ce94..fc7a113711c9ba 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -81,6 +81,33 @@ struct uvcg_format *find_format_by_index(struct uvc_device *uvc, int index)
 	return uformat;
 }
 
+int find_format_index(struct uvc_device *uvc, struct uvcg_format *uformat)
+{
+	struct uvcg_format_ptr *format;
+	int i = 1;
+
+	list_for_each_entry(format, &uvc->header->formats, entry) {
+		if (uformat == format->fmt)
+			return i;
+		i++;
+	}
+
+	return 0;
+}
+
+int find_ival_index(struct uvcg_frame *uframe, int dwFrameInterval)
+{
+	int i;
+
+	for (i = 0; i < uframe->frame.b_frame_interval_type; i++) {
+		if (dwFrameInterval == uframe->dw_frame_interval[i])
+			return i + 1;
+	}
+
+	/* fallback */
+	return 1;
+}
+
 struct uvcg_frame *find_frame_by_index(struct uvc_device *uvc,
 				       struct uvcg_format *uformat,
 				       int index)
@@ -169,8 +196,7 @@ static struct uvcg_frame *find_closest_frame_by_size(struct uvc_device *uvc,
  * Requests handling
  */
 
-static int
-uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
+int uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
 {
 	struct usb_composite_dev *cdev = uvc->func.config->cdev;
 	struct usb_request *req = uvc->control_req;
@@ -212,6 +238,8 @@ uvc_v4l2_get_format(struct file *file, void *fh, struct v4l2_format *fmt)
 	struct uvc_video *video = &uvc->video;
 	struct uvc_format_desc *fmtdesc;
 
+	spin_lock(&video->frame_lock);
+
 	fmtdesc = to_uvc_format(video->cur_format);
 
 	fmt->fmt.pix.pixelformat = fmtdesc->fcc;
@@ -225,6 +253,8 @@ uvc_v4l2_get_format(struct file *file, void *fh, struct v4l2_format *fmt)
 	fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
 	fmt->fmt.pix.priv = 0;
 
+	spin_unlock(&video->frame_lock);
+
 	return 0;
 }
 
@@ -236,6 +266,7 @@ uvc_v4l2_try_set_fmt(struct file *file, void *fh, struct v4l2_format *fmt)
 	struct uvc_video *video = &uvc->video;
 	struct uvcg_format *uformat;
 	struct uvcg_frame *uframe;
+	int iformat;
 	u8 *fcc;
 
 	if (fmt->type != video->queue.queue.type)
@@ -251,6 +282,10 @@ uvc_v4l2_try_set_fmt(struct file *file, void *fh, struct v4l2_format *fmt)
 	if (!uformat)
 		return -EINVAL;
 
+	iformat = find_format_index(uvc, uformat);
+	if (!iformat)
+		return -EINVAL;
+
 	uframe = find_closest_frame_by_size(uvc, uformat,
 				fmt->fmt.pix.width, fmt->fmt.pix.height);
 	if (!uframe)
@@ -297,8 +332,12 @@ uvc_v4l2_enum_frameintervals(struct file *file, void *fh,
 		if (fival->index >= 1)
 			return -EINVAL;
 
+		spin_lock(&video->frame_lock);
+
 		fival->discrete.numerator =
 			uframe->dw_frame_interval[video->cur_ival - 1];
+
+		spin_unlock(&video->frame_lock);
 	} else {
 		if (fival->index >= uframe->frame.b_frame_interval_type)
 			return -EINVAL;
@@ -330,8 +369,12 @@ uvc_v4l2_enum_framesizes(struct file *file, void *fh,
 		if (fsize->index >= 1)
 			return -EINVAL;
 
+		spin_lock(&video->frame_lock);
+
 		uformat = video->cur_format;
 		uframe = video->cur_frame;
+
+		spin_unlock(&video->frame_lock);
 	} else {
 		uformat = find_format_by_pix(uvc, fsize->pixel_format);
 		if (!uformat)
@@ -365,7 +408,11 @@ uvc_v4l2_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
 		if (f->index >= 1)
 			return -EINVAL;
 
+		spin_lock(&video->frame_lock);
+
 		uformat = video->cur_format;
+
+		spin_unlock(&video->frame_lock);
 	} else {
 		if (f->index >= uvc->header->num_fmt)
 			return -EINVAL;
@@ -489,14 +536,20 @@ uvc_v4l2_subscribe_event(struct v4l2_fh *fh,
 	if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
 		return -EINVAL;
 
-	if (sub->type == UVC_EVENT_SETUP && uvc->func_connected)
+	if (sub->type == UVC_EVENT_STREAMON && uvc->func_connected)
 		return -EBUSY;
 
 	ret = v4l2_event_subscribe(fh, sub, 2, NULL);
 	if (ret < 0)
 		return ret;
 
-	if (sub->type == UVC_EVENT_SETUP) {
+	if (sub->type == UVC_EVENT_SETUP)
+		uvc->setup_subscribed = true;
+
+	if (sub->type == UVC_EVENT_DATA)
+		uvc->data_subscribed = true;
+
+	if (sub->type == UVC_EVENT_STREAMON) {
 		uvc->func_connected = true;
 		handle->is_uvc_app_handle = true;
 		uvc_function_connect(uvc);
@@ -525,7 +578,10 @@ uvc_v4l2_unsubscribe_event(struct v4l2_fh *fh,
 	if (ret < 0)
 		return ret;
 
-	if (sub->type == UVC_EVENT_SETUP && handle->is_uvc_app_handle) {
+	if (sub->type == UVC_EVENT_SETUP)
+		uvc->setup_subscribed = false;
+
+	if (sub->type == UVC_EVENT_STREAMON && handle->is_uvc_app_handle) {
 		uvc_v4l2_disable(uvc);
 		handle->is_uvc_app_handle = false;
 	}
diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
index 9fb2b9c575ed34..7eb5364997028b 100644
--- a/drivers/usb/gadget/function/uvc_video.c
+++ b/drivers/usb/gadget/function/uvc_video.c
@@ -517,10 +517,11 @@ static int uvc_default_frame_interval(struct uvc_video *video)
  */
 int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc)
 {
-	int iframe;
+	int iframe, iformat;
 
 	INIT_LIST_HEAD(&video->req_free);
 	spin_lock_init(&video->req_lock);
+	spin_lock_init(&video->frame_lock);
 	INIT_WORK(&video->pump, uvcg_video_pump);
 
 	if (list_empty(&uvc->header->formats))
@@ -531,6 +532,10 @@ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc)
 	if (!video->cur_format)
 		return -EINVAL;
 
+	iformat = find_format_index(uvc, video->cur_format);
+	if (!iformat)
+		return -EINVAL;
+
 	iframe = uvc_frame_default(video->cur_format);
 	if (!iframe)
 		return -EINVAL;
@@ -541,6 +546,11 @@ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc)
 
 	video->cur_ival = uvc_default_frame_interval(video);
 
+	uvc_fill_streaming_control(uvc, &video->probe, iframe, iformat,
+				   video->cur_ival);
+	uvc_fill_streaming_control(uvc, &video->commit, iframe, iformat,
+				   video->cur_ival);
+
 	/* Initialize the video buffers queue. */
 	uvcg_queue_init(&video->queue, uvc->v4l2_dev.dev->parent,
 			V4L2_BUF_TYPE_VIDEO_OUTPUT, &video->mutex);
-- 
2.30.2


^ permalink raw reply related

* [PATCH v6 6/7] usb: gadget: uvc: add VIDIOC function
From: Michael Grzeschik @ 2022-01-05 11:55 UTC (permalink / raw)
  To: linux-usb; +Cc: balbi, laurent.pinchart, paul.elder, kernel
In-Reply-To: <20220105115527.3592860-1-m.grzeschik@pengutronix.de>

This patch adds support to the v4l2 VIDIOC for enum_format,
enum_framesizes, enum_frameintervals and try_fmt. The linked/active
configfs userspace setup is used in the v4l2 interface functions.

With the v4l2 vidiocontrols the userspace can use the v4l2 api to
negotiate and alloc the data. It doesn't have to bring its own configfs
parser.

Also it only needs to be extended with subscription for streamon,
streamoff, connect and disconnect for stream handling and become able to
serve the uvc device.

Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>

---
v1 -> v2:
   - fixed indentation of find_frame/format_by_index
   - fixed function name find_frm_by_size to find_frame_by_size
   - fixed indentation of _uvc_v4l2_try_fmt
   - fixed indentation in uvc_v4l2_enum_frameintervals
   - removed unneeded declaration of uvc_v4l2_get_bytesperline in uvc_v4l2.h
   - checked return values on config_group_find_item, handling refcount
   - fixed sizeof using variables instead of types
   - removed unsused def_format variable
   - wrting grp, hdr, fmt and frm in full
   - added proper ival handling
   - removed analyze_configfs function
   - added linked list of frames to uvcg_format
   - added functon find_frame_by_index
v2 -> v3:
   - fixed usage of u_uvc.h
   - removed unused variable i in _try_fmt
   - made uvc_v4l2_get_bytesperline static
v3 -> v4:
   - conditionally return current or all frames/formats/frameintervals on enum
   - dropped setting format and frame with set_format
   - combined try and set format function to one call
v4 -> v5:
   - fixed uninitialized return values reported by kernel test robot
   - added local video variable to uvc_v4l2_enum_frameintervals
v5 -> v6:
   -

 drivers/usb/gadget/function/f_uvc.c     |  28 ++
 drivers/usb/gadget/function/uvc.h       |  19 +-
 drivers/usb/gadget/function/uvc_queue.c |   3 +-
 drivers/usb/gadget/function/uvc_v4l2.c  | 338 +++++++++++++++++++++---
 drivers/usb/gadget/function/uvc_video.c |  61 ++++-
 5 files changed, 398 insertions(+), 51 deletions(-)

diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 37fdf8b3495a48..e081a4e6572ee2 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -322,6 +322,8 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
 		if (uvc->video.ep)
 			usb_ep_disable(uvc->video.ep);
 
+		uvc->streamon = 0;
+
 		memset(&v4l2_event, 0, sizeof(v4l2_event));
 		v4l2_event.type = UVC_EVENT_STREAMOFF;
 		v4l2_event_queue(&uvc->vdev, &v4l2_event);
@@ -345,6 +347,8 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
 			return ret;
 		usb_ep_enable(uvc->video.ep);
 
+		uvc->streamon = 1;
+
 		memset(&v4l2_event, 0, sizeof(v4l2_event));
 		v4l2_event.type = UVC_EVENT_STREAMON;
 		v4l2_event_queue(&uvc->vdev, &v4l2_event);
@@ -880,6 +884,7 @@ static void uvc_free(struct usb_function *f)
 	struct uvc_device *uvc = to_uvc(f);
 	struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts,
 					       func_inst);
+	config_item_put(&uvc->header->item);
 	--opts->refcnt;
 	kfree(uvc);
 }
@@ -907,6 +912,7 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
 	struct uvc_device *uvc;
 	struct f_uvc_opts *opts;
 	struct uvc_descriptor_header **strm_cls;
+	struct config_item *streaming, *header, *h;
 
 	uvc = kzalloc(sizeof(*uvc), GFP_KERNEL);
 	if (uvc == NULL)
@@ -938,6 +944,28 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
 	uvc->desc.fs_streaming = opts->fs_streaming;
 	uvc->desc.hs_streaming = opts->hs_streaming;
 	uvc->desc.ss_streaming = opts->ss_streaming;
+
+	streaming = config_group_find_item(&opts->func_inst.group, "streaming");
+	if (!streaming) {
+		config_item_put(streaming);
+		return ERR_PTR(-ENOMEM);
+	}
+	header = config_group_find_item(to_config_group(streaming), "header");
+	config_item_put(streaming);
+	if (!header) {
+		config_item_put(header);
+		return ERR_PTR(-ENOMEM);
+	}
+	h = config_group_find_item(to_config_group(header), "h");
+	config_item_put(header);
+	if (!h) {
+		config_item_put(h);
+		return ERR_PTR(-ENOMEM);
+	}
+	uvc->header = to_uvcg_streaming_header(h);
+	if (!uvc->header->linked)
+		return ERR_PTR(-EBUSY);
+
 	++opts->refcnt;
 	mutex_unlock(&opts->lock);
 
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index c3607a32b98624..b7246b4bee1d87 100644
--- a/drivers/usb/gadget/function/uvc.h
+++ b/drivers/usb/gadget/function/uvc.h
@@ -88,11 +88,10 @@ struct uvc_video {
 	struct work_struct pump;
 
 	/* Frame parameters */
-	u8 bpp;
-	u32 fcc;
-	unsigned int width;
-	unsigned int height;
-	unsigned int imagesize;
+	struct uvcg_format *cur_format;
+	struct uvcg_frame *cur_frame;
+	unsigned int cur_ival;
+
 	struct mutex mutex;	/* protects frame parameters */
 
 	unsigned int uvc_num_requests;
@@ -130,6 +129,8 @@ struct uvc_device {
 	struct uvc_video video;
 	bool func_connected;
 
+	struct uvcg_streaming_header *header;
+
 	/* Descriptors */
 	struct {
 		const struct uvc_descriptor_header * const *fs_control;
@@ -139,6 +140,8 @@ struct uvc_device {
 		const struct uvc_descriptor_header * const *ss_streaming;
 	} desc;
 
+	bool streamon;
+
 	unsigned int control_intf;
 	struct usb_ep *control_ep;
 	struct usb_request *control_req;
@@ -175,4 +178,10 @@ extern void uvc_endpoint_stream(struct uvc_device *dev);
 extern void uvc_function_connect(struct uvc_device *uvc);
 extern void uvc_function_disconnect(struct uvc_device *uvc);
 
+extern struct uvcg_format *find_format_by_index(struct uvc_device *uvc,
+						int index);
+extern struct uvcg_frame *find_frame_by_index(struct uvc_device *uvc,
+					      struct uvcg_format *uformat,
+					      int index);
+
 #endif /* _UVC_GADGET_H_ */
diff --git a/drivers/usb/gadget/function/uvc_queue.c b/drivers/usb/gadget/function/uvc_queue.c
index d852ac9e47e72c..84f4218191e38f 100644
--- a/drivers/usb/gadget/function/uvc_queue.c
+++ b/drivers/usb/gadget/function/uvc_queue.c
@@ -21,6 +21,7 @@
 #include <media/videobuf2-vmalloc.h>
 
 #include "uvc.h"
+#include "uvc_configfs.h"
 
 /* ------------------------------------------------------------------------
  * Video buffers queue management.
@@ -51,7 +52,7 @@ static int uvc_queue_setup(struct vb2_queue *vq,
 
 	*nplanes = 1;
 
-	sizes[0] = video->imagesize;
+	sizes[0] = video->cur_frame->frame.dw_max_video_frame_buffer_size;
 
 	if (cdev->gadget->speed < USB_SPEED_SUPER)
 		video->uvc_num_requests = 4;
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index a2c78690c5c288..e4c4884806ce94 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -18,12 +18,152 @@
 #include <media/v4l2-dev.h>
 #include <media/v4l2-event.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-uvc.h>
 
 #include "f_uvc.h"
 #include "uvc.h"
 #include "uvc_queue.h"
 #include "uvc_video.h"
 #include "uvc_v4l2.h"
+#include "uvc_configfs.h"
+
+static struct uvc_format_desc *to_uvc_format(struct uvcg_format *uformat)
+{
+	char guid[16] = UVC_GUID_FORMAT_MJPEG;
+	struct uvc_format_desc *format;
+	struct uvcg_uncompressed *unc;
+
+	if (uformat->type == UVCG_UNCOMPRESSED) {
+		unc = to_uvcg_uncompressed(&uformat->group.cg_item);
+		if (!unc)
+			return ERR_PTR(-EINVAL);
+
+		memcpy(guid, unc->desc.guidFormat, sizeof(guid));
+	}
+
+	format = uvc_format_by_guid(guid);
+	if (!format)
+		return ERR_PTR(-EINVAL);
+
+	return format;
+}
+
+static int uvc_v4l2_get_bytesperline(struct uvcg_format *uformat,
+			      struct uvcg_frame *uframe)
+{
+	struct uvcg_uncompressed *u;
+
+	if (uformat->type == UVCG_UNCOMPRESSED) {
+		u = to_uvcg_uncompressed(&uformat->group.cg_item);
+		if (!u)
+			return 0;
+
+		return u->desc.bBitsPerPixel * uframe->frame.w_width / 8;
+	}
+
+	return 0;
+}
+
+struct uvcg_format *find_format_by_index(struct uvc_device *uvc, int index)
+{
+	struct uvcg_format_ptr *format;
+	struct uvcg_format *uformat = NULL;
+	int i = 1;
+
+	list_for_each_entry(format, &uvc->header->formats, entry) {
+		if (index == i) {
+			uformat = format->fmt;
+			break;
+		}
+		i++;
+	}
+
+	return uformat;
+}
+
+struct uvcg_frame *find_frame_by_index(struct uvc_device *uvc,
+				       struct uvcg_format *uformat,
+				       int index)
+{
+	struct uvcg_format_ptr *format;
+	struct uvcg_frame_ptr *frame;
+	struct uvcg_frame *uframe = NULL;
+
+	list_for_each_entry(format, &uvc->header->formats, entry) {
+		if (format->fmt->type != uformat->type)
+			continue;
+		list_for_each_entry(frame, &format->fmt->frames, entry) {
+			if (index == frame->frm->frame.b_frame_index) {
+				uframe = frame->frm;
+				break;
+			}
+		}
+	}
+
+	return uframe;
+}
+
+static struct uvcg_format *find_format_by_pix(struct uvc_device *uvc,
+					      u32 pixelformat)
+{
+	struct uvcg_format_ptr *format;
+	struct uvcg_format *uformat = NULL;
+
+	list_for_each_entry(format, &uvc->header->formats, entry) {
+		struct uvc_format_desc *fmtdesc = to_uvc_format(format->fmt);
+
+		if (fmtdesc->fcc == pixelformat) {
+			uformat = format->fmt;
+			break;
+		}
+	}
+
+	return uformat;
+}
+
+static struct uvcg_frame *find_closest_frame_by_size(struct uvc_device *uvc,
+					   struct uvcg_format *uformat,
+					   u16 rw, u16 rh)
+{
+	struct uvc_video *video = &uvc->video;
+	struct uvcg_format_ptr *format;
+	struct uvcg_frame_ptr *frame;
+	struct uvcg_frame *uframe = NULL;
+	unsigned int d, maxd;
+
+	/* Find the closest image size. The distance between image sizes is
+	 * the size in pixels of the non-overlapping regions between the
+	 * requested size and the frame-specified size.
+	 */
+	maxd = (unsigned int)-1;
+
+	list_for_each_entry(format, &uvc->header->formats, entry) {
+		if (format->fmt->type != uformat->type)
+			continue;
+
+		list_for_each_entry(frame, &format->fmt->frames, entry) {
+			u16 w, h;
+
+			w = frame->frm->frame.w_width;
+			h = frame->frm->frame.w_height;
+
+			d = min(w, rw) * min(h, rh);
+			d = w*h + rw*rh - 2*d;
+			if (d < maxd) {
+				maxd = d;
+				uframe = frame->frm;
+			}
+
+			if (maxd == 0)
+				break;
+		}
+	}
+
+	if (!uframe)
+		uvcg_dbg(&video->uvc->func, "Unsupported size %ux%u\n", rw, rh);
+
+	return uframe;
+}
 
 /* --------------------------------------------------------------------------
  * Requests handling
@@ -50,16 +190,6 @@ uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
  * V4L2 ioctls
  */
 
-struct uvc_format {
-	u8 bpp;
-	u32 fcc;
-};
-
-static struct uvc_format uvc_formats[] = {
-	{ 16, V4L2_PIX_FMT_YUYV  },
-	{ 0,  V4L2_PIX_FMT_MJPEG },
-};
-
 static int
 uvc_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
 {
@@ -80,13 +210,18 @@ uvc_v4l2_get_format(struct file *file, void *fh, struct v4l2_format *fmt)
 	struct video_device *vdev = video_devdata(file);
 	struct uvc_device *uvc = video_get_drvdata(vdev);
 	struct uvc_video *video = &uvc->video;
+	struct uvc_format_desc *fmtdesc;
+
+	fmtdesc = to_uvc_format(video->cur_format);
 
-	fmt->fmt.pix.pixelformat = video->fcc;
-	fmt->fmt.pix.width = video->width;
-	fmt->fmt.pix.height = video->height;
+	fmt->fmt.pix.pixelformat = fmtdesc->fcc;
+	fmt->fmt.pix.width = video->cur_frame->frame.w_width;
+	fmt->fmt.pix.height = video->cur_frame->frame.w_height;
 	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.bytesperline = uvc_v4l2_get_bytesperline(video->cur_format,
+							      video->cur_frame);
+	fmt->fmt.pix.sizeimage =
+			video->cur_frame->frame.dw_max_video_frame_buffer_size;
 	fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
 	fmt->fmt.pix.priv = 0;
 
@@ -94,46 +229,165 @@ uvc_v4l2_get_format(struct file *file, void *fh, struct v4l2_format *fmt)
 }
 
 static int
-uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt)
+uvc_v4l2_try_set_fmt(struct file *file, void *fh, struct v4l2_format *fmt)
 {
 	struct video_device *vdev = video_devdata(file);
 	struct uvc_device *uvc = video_get_drvdata(vdev);
 	struct uvc_video *video = &uvc->video;
-	struct uvc_format *format;
-	unsigned int imagesize;
-	unsigned int bpl;
-	unsigned int i;
-
-	for (i = 0; i < ARRAY_SIZE(uvc_formats); ++i) {
-		format = &uvc_formats[i];
-		if (format->fcc == fmt->fmt.pix.pixelformat)
-			break;
-	}
+	struct uvcg_format *uformat;
+	struct uvcg_frame *uframe;
+	u8 *fcc;
 
-	if (i == ARRAY_SIZE(uvc_formats)) {
-		uvcg_info(&uvc->func, "Unsupported format 0x%08x.\n",
-			  fmt->fmt.pix.pixelformat);
+	if (fmt->type != video->queue.queue.type)
 		return -EINVAL;
-	}
 
-	bpl = format->bpp * fmt->fmt.pix.width / 8;
-	imagesize = bpl ? bpl * fmt->fmt.pix.height : fmt->fmt.pix.sizeimage;
+	fcc = (u8 *)&fmt->fmt.pix.pixelformat;
+	uvcg_dbg(&uvc->func, "Trying format 0x%08x (%c%c%c%c): %ux%u\n",
+		fmt->fmt.pix.pixelformat,
+		fcc[0], fcc[1], fcc[2], fcc[3],
+		fmt->fmt.pix.width, fmt->fmt.pix.height);
 
-	video->fcc = format->fcc;
-	video->bpp = format->bpp;
-	video->width = fmt->fmt.pix.width;
-	video->height = fmt->fmt.pix.height;
-	video->imagesize = imagesize;
+	uformat = find_format_by_pix(uvc, fmt->fmt.pix.pixelformat);
+	if (!uformat)
+		return -EINVAL;
 
+	uframe = find_closest_frame_by_size(uvc, uformat,
+				fmt->fmt.pix.width, fmt->fmt.pix.height);
+	if (!uframe)
+		return -EINVAL;
+
+	fmt->fmt.pix.width = uframe->frame.w_width;
+	fmt->fmt.pix.height = uframe->frame.w_height;
 	fmt->fmt.pix.field = V4L2_FIELD_NONE;
-	fmt->fmt.pix.bytesperline = bpl;
-	fmt->fmt.pix.sizeimage = imagesize;
+	fmt->fmt.pix.bytesperline = uvc_v4l2_get_bytesperline(uformat, uframe);
+	fmt->fmt.pix.sizeimage = uframe->frame.dw_max_video_frame_buffer_size;
+	fmt->fmt.pix.pixelformat = to_uvc_format(uformat)->fcc;
 	fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
 	fmt->fmt.pix.priv = 0;
 
 	return 0;
 }
 
+static int
+uvc_v4l2_enum_frameintervals(struct file *file, void *fh,
+		struct v4l2_frmivalenum *fival)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct uvc_device *uvc = video_get_drvdata(vdev);
+	struct uvc_video *video = &uvc->video;
+	struct uvcg_format *uformat = NULL;
+	struct uvcg_frame *uframe = NULL;
+	struct uvcg_frame_ptr *frame;
+
+	uformat = find_format_by_pix(uvc, fival->pixel_format);
+	if (!uformat)
+		return -EINVAL;
+
+	list_for_each_entry(frame, &uformat->frames, entry) {
+		if (frame->frm->frame.w_width == fival->width &&
+		    frame->frm->frame.w_height == fival->height) {
+			uframe = frame->frm;
+			break;
+		}
+	}
+	if (!uframe)
+		return -EINVAL;
+
+	if (uvc->streamon) {
+		if (fival->index >= 1)
+			return -EINVAL;
+
+		fival->discrete.numerator =
+			uframe->dw_frame_interval[video->cur_ival - 1];
+	} else {
+		if (fival->index >= uframe->frame.b_frame_interval_type)
+			return -EINVAL;
+
+		fival->discrete.numerator =
+			uframe->dw_frame_interval[fival->index];
+	}
+
+	/* TODO: handle V4L2_FRMIVAL_TYPE_STEPWISE */
+	fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+	fival->discrete.denominator = 10000000;
+	v4l2_simplify_fraction(&fival->discrete.numerator,
+		&fival->discrete.denominator, 8, 333);
+
+	return 0;
+}
+
+static int
+uvc_v4l2_enum_framesizes(struct file *file, void *fh,
+		struct v4l2_frmsizeenum *fsize)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct uvc_device *uvc = video_get_drvdata(vdev);
+	struct uvc_video *video = &uvc->video;
+	struct uvcg_format *uformat = NULL;
+	struct uvcg_frame *uframe = NULL;
+
+	if (uvc->streamon) {
+		if (fsize->index >= 1)
+			return -EINVAL;
+
+		uformat = video->cur_format;
+		uframe = video->cur_frame;
+	} else {
+		uformat = find_format_by_pix(uvc, fsize->pixel_format);
+		if (!uformat)
+			return -EINVAL;
+
+		if (fsize->index >= uformat->num_frames)
+			return -EINVAL;
+
+		uframe = find_frame_by_index(uvc, uformat, fsize->index + 1);
+		if (!uframe)
+			return -EINVAL;
+	}
+
+	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+	fsize->discrete.width = uframe->frame.w_width;
+	fsize->discrete.height = uframe->frame.w_height;
+
+	return 0;
+}
+
+static int
+uvc_v4l2_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct uvc_device *uvc = video_get_drvdata(vdev);
+	struct uvc_video *video = &uvc->video;
+	struct uvc_format_desc *fmtdesc;
+	struct uvcg_format *uformat;
+
+	if (uvc->streamon) {
+		if (f->index >= 1)
+			return -EINVAL;
+
+		uformat = video->cur_format;
+	} else {
+		if (f->index >= uvc->header->num_fmt)
+			return -EINVAL;
+
+		uformat = find_format_by_index(uvc, f->index + 1);
+		if (!uformat)
+			return -EINVAL;
+
+	}
+
+	if (uformat->type != UVCG_UNCOMPRESSED)
+		f->flags |= V4L2_FMT_FLAG_COMPRESSED;
+
+	fmtdesc = to_uvc_format(uformat);
+	f->pixelformat = fmtdesc->fcc;
+
+	strscpy(f->description, fmtdesc->name, sizeof(f->description));
+	f->description[strlen(fmtdesc->name) - 1] = 0;
+
+	return 0;
+}
+
 static int
 uvc_v4l2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *b)
 {
@@ -297,8 +551,12 @@ 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_try_fmt_vid_out = uvc_v4l2_try_set_fmt,
 	.vidioc_g_fmt_vid_out = uvc_v4l2_get_format,
-	.vidioc_s_fmt_vid_out = uvc_v4l2_set_format,
+	.vidioc_s_fmt_vid_out = uvc_v4l2_try_set_fmt,
+	.vidioc_enum_frameintervals = uvc_v4l2_enum_frameintervals,
+	.vidioc_enum_framesizes = uvc_v4l2_enum_framesizes,
+	.vidioc_enum_fmt_vid_out = uvc_v4l2_enum_fmt,
 	.vidioc_reqbufs = uvc_v4l2_reqbufs,
 	.vidioc_querybuf = uvc_v4l2_querybuf,
 	.vidioc_qbuf = uvc_v4l2_qbuf,
diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
index 7f59a0c4740209..9fb2b9c575ed34 100644
--- a/drivers/usb/gadget/function/uvc_video.c
+++ b/drivers/usb/gadget/function/uvc_video.c
@@ -19,6 +19,7 @@
 #include "uvc.h"
 #include "uvc_queue.h"
 #include "uvc_video.h"
+#include "uvc_configfs.h"
 
 /* --------------------------------------------------------------------------
  * Video codecs
@@ -474,21 +475,71 @@ int uvcg_video_enable(struct uvc_video *video, int enable)
 	return ret;
 }
 
+static int uvc_frame_default(struct uvcg_format *uformat)
+{
+	struct uvcg_uncompressed *u;
+	struct uvcg_mjpeg *m;
+
+	switch (uformat->type) {
+	case UVCG_UNCOMPRESSED:
+		u = to_uvcg_uncompressed(&uformat->group.cg_item);
+		if (u)
+			return u->desc.bDefaultFrameIndex;
+		break;
+	case UVCG_MJPEG:
+		m = to_uvcg_mjpeg(&uformat->group.cg_item);
+		if (m)
+			return m->desc.bDefaultFrameIndex;
+		break;
+	}
+
+	return 0;
+}
+
+static int uvc_default_frame_interval(struct uvc_video *video)
+{
+	int i;
+
+	for (i = 0; i < video->cur_frame->frame.b_frame_interval_type; i++) {
+		if (video->cur_frame->frame.dw_default_frame_interval ==
+			video->cur_frame->dw_frame_interval[i]) {
+			video->cur_ival = i + 1;
+			return i + 1;
+		}
+	}
+
+	/* fallback */
+	return 1;
+}
+
 /*
  * Initialize the UVC video stream.
  */
 int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc)
 {
+	int iframe;
+
 	INIT_LIST_HEAD(&video->req_free);
 	spin_lock_init(&video->req_lock);
 	INIT_WORK(&video->pump, uvcg_video_pump);
 
+	if (list_empty(&uvc->header->formats))
+		return -EINVAL;
+
 	video->uvc = uvc;
-	video->fcc = V4L2_PIX_FMT_YUYV;
-	video->bpp = 16;
-	video->width = 320;
-	video->height = 240;
-	video->imagesize = 320 * 240 * 2;
+	video->cur_format = find_format_by_index(uvc, 1);
+	if (!video->cur_format)
+		return -EINVAL;
+
+	iframe = uvc_frame_default(video->cur_format);
+	if (!iframe)
+		return -EINVAL;
+
+	video->cur_frame = find_frame_by_index(uvc, video->cur_format, iframe);
+	if (!video->cur_frame)
+		return -EINVAL;
+
+	video->cur_ival = uvc_default_frame_interval(video);
 
 	/* Initialize the video buffers queue. */
 	uvcg_queue_init(&video->queue, uvc->v4l2_dev.dev->parent,
-- 
2.30.2


^ permalink raw reply related

* [PATCH v6 2/7] media: uvcvideo: move uvc_format_desc to common header
From: Michael Grzeschik @ 2022-01-05 11:55 UTC (permalink / raw)
  To: linux-usb; +Cc: balbi, laurent.pinchart, paul.elder, kernel
In-Reply-To: <20220105115527.3592860-1-m.grzeschik@pengutronix.de>

The uvc_format_desc, GUID defines and the uvc_format_by_guid helper is
also useful for the uvc gadget stack. This patch moves them to a common
header.

Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>

---
v1 -> v2: -
v2 -> v3: -
v3 -> v4: -
v4 -> v5: -
v5 -> v6: -

 drivers/media/usb/uvc/uvc_ctrl.c   |   1 +
 drivers/media/usb/uvc/uvc_driver.c | 201 +----------------
 drivers/media/usb/uvc/uvcvideo.h   | 141 ------------
 include/media/v4l2-uvc.h           | 351 +++++++++++++++++++++++++++++
 4 files changed, 353 insertions(+), 341 deletions(-)
 create mode 100644 include/media/v4l2-uvc.h

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 30bfe9069a1fb4..20d1555cc174d0 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -18,6 +18,7 @@
 #include <linux/workqueue.h>
 #include <linux/atomic.h>
 #include <media/v4l2-ctrls.h>
+#include <media/v4l2-uvc.h>
 
 #include "uvcvideo.h"
 
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index cdb92da0f56afd..57e489f9df9e4b 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -20,6 +20,7 @@
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-uvc.h>
 
 #include "uvcvideo.h"
 
@@ -34,193 +35,6 @@ static unsigned int uvc_quirks_param = -1;
 unsigned int uvc_dbg_param;
 unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT;
 
-/* ------------------------------------------------------------------------
- * Video formats
- */
-
-static struct uvc_format_desc uvc_fmts[] = {
-	{
-		.name		= "YUV 4:2:2 (YUYV)",
-		.guid		= UVC_GUID_FORMAT_YUY2,
-		.fcc		= V4L2_PIX_FMT_YUYV,
-	},
-	{
-		.name		= "YUV 4:2:2 (YUYV)",
-		.guid		= UVC_GUID_FORMAT_YUY2_ISIGHT,
-		.fcc		= V4L2_PIX_FMT_YUYV,
-	},
-	{
-		.name		= "YUV 4:2:0 (NV12)",
-		.guid		= UVC_GUID_FORMAT_NV12,
-		.fcc		= V4L2_PIX_FMT_NV12,
-	},
-	{
-		.name		= "MJPEG",
-		.guid		= UVC_GUID_FORMAT_MJPEG,
-		.fcc		= V4L2_PIX_FMT_MJPEG,
-	},
-	{
-		.name		= "YVU 4:2:0 (YV12)",
-		.guid		= UVC_GUID_FORMAT_YV12,
-		.fcc		= V4L2_PIX_FMT_YVU420,
-	},
-	{
-		.name		= "YUV 4:2:0 (I420)",
-		.guid		= UVC_GUID_FORMAT_I420,
-		.fcc		= V4L2_PIX_FMT_YUV420,
-	},
-	{
-		.name		= "YUV 4:2:0 (M420)",
-		.guid		= UVC_GUID_FORMAT_M420,
-		.fcc		= V4L2_PIX_FMT_M420,
-	},
-	{
-		.name		= "YUV 4:2:2 (UYVY)",
-		.guid		= UVC_GUID_FORMAT_UYVY,
-		.fcc		= V4L2_PIX_FMT_UYVY,
-	},
-	{
-		.name		= "Greyscale 8-bit (Y800)",
-		.guid		= UVC_GUID_FORMAT_Y800,
-		.fcc		= V4L2_PIX_FMT_GREY,
-	},
-	{
-		.name		= "Greyscale 8-bit (Y8  )",
-		.guid		= UVC_GUID_FORMAT_Y8,
-		.fcc		= V4L2_PIX_FMT_GREY,
-	},
-	{
-		.name		= "Greyscale 8-bit (D3DFMT_L8)",
-		.guid		= UVC_GUID_FORMAT_D3DFMT_L8,
-		.fcc		= V4L2_PIX_FMT_GREY,
-	},
-	{
-		.name		= "IR 8-bit (L8_IR)",
-		.guid		= UVC_GUID_FORMAT_KSMEDIA_L8_IR,
-		.fcc		= V4L2_PIX_FMT_GREY,
-	},
-	{
-		.name		= "Greyscale 10-bit (Y10 )",
-		.guid		= UVC_GUID_FORMAT_Y10,
-		.fcc		= V4L2_PIX_FMT_Y10,
-	},
-	{
-		.name		= "Greyscale 12-bit (Y12 )",
-		.guid		= UVC_GUID_FORMAT_Y12,
-		.fcc		= V4L2_PIX_FMT_Y12,
-	},
-	{
-		.name		= "Greyscale 16-bit (Y16 )",
-		.guid		= UVC_GUID_FORMAT_Y16,
-		.fcc		= V4L2_PIX_FMT_Y16,
-	},
-	{
-		.name		= "BGGR Bayer (BY8 )",
-		.guid		= UVC_GUID_FORMAT_BY8,
-		.fcc		= V4L2_PIX_FMT_SBGGR8,
-	},
-	{
-		.name		= "BGGR Bayer (BA81)",
-		.guid		= UVC_GUID_FORMAT_BA81,
-		.fcc		= V4L2_PIX_FMT_SBGGR8,
-	},
-	{
-		.name		= "GBRG Bayer (GBRG)",
-		.guid		= UVC_GUID_FORMAT_GBRG,
-		.fcc		= V4L2_PIX_FMT_SGBRG8,
-	},
-	{
-		.name		= "GRBG Bayer (GRBG)",
-		.guid		= UVC_GUID_FORMAT_GRBG,
-		.fcc		= V4L2_PIX_FMT_SGRBG8,
-	},
-	{
-		.name		= "RGGB Bayer (RGGB)",
-		.guid		= UVC_GUID_FORMAT_RGGB,
-		.fcc		= V4L2_PIX_FMT_SRGGB8,
-	},
-	{
-		.name		= "RGB565",
-		.guid		= UVC_GUID_FORMAT_RGBP,
-		.fcc		= V4L2_PIX_FMT_RGB565,
-	},
-	{
-		.name		= "BGR 8:8:8 (BGR3)",
-		.guid		= UVC_GUID_FORMAT_BGR3,
-		.fcc		= V4L2_PIX_FMT_BGR24,
-	},
-	{
-		.name		= "H.264",
-		.guid		= UVC_GUID_FORMAT_H264,
-		.fcc		= V4L2_PIX_FMT_H264,
-	},
-	{
-		.name		= "Greyscale 8 L/R (Y8I)",
-		.guid		= UVC_GUID_FORMAT_Y8I,
-		.fcc		= V4L2_PIX_FMT_Y8I,
-	},
-	{
-		.name		= "Greyscale 12 L/R (Y12I)",
-		.guid		= UVC_GUID_FORMAT_Y12I,
-		.fcc		= V4L2_PIX_FMT_Y12I,
-	},
-	{
-		.name		= "Depth data 16-bit (Z16)",
-		.guid		= UVC_GUID_FORMAT_Z16,
-		.fcc		= V4L2_PIX_FMT_Z16,
-	},
-	{
-		.name		= "Bayer 10-bit (SRGGB10P)",
-		.guid		= UVC_GUID_FORMAT_RW10,
-		.fcc		= V4L2_PIX_FMT_SRGGB10P,
-	},
-	{
-		.name		= "Bayer 16-bit (SBGGR16)",
-		.guid		= UVC_GUID_FORMAT_BG16,
-		.fcc		= V4L2_PIX_FMT_SBGGR16,
-	},
-	{
-		.name		= "Bayer 16-bit (SGBRG16)",
-		.guid		= UVC_GUID_FORMAT_GB16,
-		.fcc		= V4L2_PIX_FMT_SGBRG16,
-	},
-	{
-		.name		= "Bayer 16-bit (SRGGB16)",
-		.guid		= UVC_GUID_FORMAT_RG16,
-		.fcc		= V4L2_PIX_FMT_SRGGB16,
-	},
-	{
-		.name		= "Bayer 16-bit (SGRBG16)",
-		.guid		= UVC_GUID_FORMAT_GR16,
-		.fcc		= V4L2_PIX_FMT_SGRBG16,
-	},
-	{
-		.name		= "Depth data 16-bit (Z16)",
-		.guid		= UVC_GUID_FORMAT_INVZ,
-		.fcc		= V4L2_PIX_FMT_Z16,
-	},
-	{
-		.name		= "Greyscale 10-bit (Y10 )",
-		.guid		= UVC_GUID_FORMAT_INVI,
-		.fcc		= V4L2_PIX_FMT_Y10,
-	},
-	{
-		.name		= "IR:Depth 26-bit (INZI)",
-		.guid		= UVC_GUID_FORMAT_INZI,
-		.fcc		= V4L2_PIX_FMT_INZI,
-	},
-	{
-		.name		= "4-bit Depth Confidence (Packed)",
-		.guid		= UVC_GUID_FORMAT_CNF4,
-		.fcc		= V4L2_PIX_FMT_CNF4,
-	},
-	{
-		.name		= "HEVC",
-		.guid		= UVC_GUID_FORMAT_HEVC,
-		.fcc		= V4L2_PIX_FMT_HEVC,
-	},
-};
-
 /* ------------------------------------------------------------------------
  * Utility functions
  */
@@ -240,19 +54,6 @@ struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
 	return NULL;
 }
 
-static struct uvc_format_desc *uvc_format_by_guid(const u8 guid[16])
-{
-	unsigned int len = ARRAY_SIZE(uvc_fmts);
-	unsigned int i;
-
-	for (i = 0; i < len; ++i) {
-		if (memcmp(guid, uvc_fmts[i].guid, 16) == 0)
-			return &uvc_fmts[i];
-	}
-
-	return NULL;
-}
-
 static enum v4l2_colorspace uvc_colorspace(const u8 primaries)
 {
 	static const enum v4l2_colorspace colorprimaries[] = {
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index a61cd0a459e88d..7ed229516dbbfb 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -41,141 +41,6 @@
 #define UVC_EXT_GPIO_UNIT		0x7ffe
 #define UVC_EXT_GPIO_UNIT_ID		0x100
 
-/* ------------------------------------------------------------------------
- * GUIDs
- */
-#define UVC_GUID_UVC_CAMERA \
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
-#define UVC_GUID_UVC_OUTPUT \
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}
-#define UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT \
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
-#define UVC_GUID_UVC_PROCESSING \
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01}
-#define UVC_GUID_UVC_SELECTOR \
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}
-#define UVC_GUID_EXT_GPIO_CONTROLLER \
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03}
-
-#define UVC_GUID_FORMAT_MJPEG \
-	{ 'M',  'J',  'P',  'G', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_YUY2 \
-	{ 'Y',  'U',  'Y',  '2', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_YUY2_ISIGHT \
-	{ 'Y',  'U',  'Y',  '2', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0x00, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_NV12 \
-	{ 'N',  'V',  '1',  '2', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_YV12 \
-	{ 'Y',  'V',  '1',  '2', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_I420 \
-	{ 'I',  '4',  '2',  '0', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_UYVY \
-	{ 'U',  'Y',  'V',  'Y', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y800 \
-	{ 'Y',  '8',  '0',  '0', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y8 \
-	{ 'Y',  '8',  ' ',  ' ', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y10 \
-	{ 'Y',  '1',  '0',  ' ', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y12 \
-	{ 'Y',  '1',  '2',  ' ', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y16 \
-	{ 'Y',  '1',  '6',  ' ', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_BY8 \
-	{ 'B',  'Y',  '8',  ' ', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_BA81 \
-	{ 'B',  'A',  '8',  '1', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_GBRG \
-	{ 'G',  'B',  'R',  'G', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_GRBG \
-	{ 'G',  'R',  'B',  'G', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_RGGB \
-	{ 'R',  'G',  'G',  'B', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_BG16 \
-	{ 'B',  'G',  '1',  '6', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_GB16 \
-	{ 'G',  'B',  '1',  '6', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_RG16 \
-	{ 'R',  'G',  '1',  '6', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_GR16 \
-	{ 'G',  'R',  '1',  '6', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_RGBP \
-	{ 'R',  'G',  'B',  'P', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_BGR3 \
-	{ 0x7d, 0xeb, 0x36, 0xe4, 0x4f, 0x52, 0xce, 0x11, \
-	 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}
-#define UVC_GUID_FORMAT_M420 \
-	{ 'M',  '4',  '2',  '0', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-
-#define UVC_GUID_FORMAT_H264 \
-	{ 'H',  '2',  '6',  '4', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y8I \
-	{ 'Y',  '8',  'I',  ' ', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y12I \
-	{ 'Y',  '1',  '2',  'I', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Z16 \
-	{ 'Z',  '1',  '6',  ' ', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_RW10 \
-	{ 'R',  'W',  '1',  '0', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_INVZ \
-	{ 'I',  'N',  'V',  'Z', 0x90, 0x2d, 0x58, 0x4a, \
-	 0x92, 0x0b, 0x77, 0x3f, 0x1f, 0x2c, 0x55, 0x6b}
-#define UVC_GUID_FORMAT_INZI \
-	{ 'I',  'N',  'Z',  'I', 0x66, 0x1a, 0x42, 0xa2, \
-	 0x90, 0x65, 0xd0, 0x18, 0x14, 0xa8, 0xef, 0x8a}
-#define UVC_GUID_FORMAT_INVI \
-	{ 'I',  'N',  'V',  'I', 0xdb, 0x57, 0x49, 0x5e, \
-	 0x8e, 0x3f, 0xf4, 0x79, 0x53, 0x2b, 0x94, 0x6f}
-#define UVC_GUID_FORMAT_CNF4 \
-	{ 'C',  ' ',  ' ',  ' ', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-
-#define UVC_GUID_FORMAT_D3DFMT_L8 \
-	{0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_KSMEDIA_L8_IR \
-	{0x32, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-
-#define UVC_GUID_FORMAT_HEVC \
-	{ 'H',  'E',  'V',  'C', 0x00, 0x00, 0x10, 0x00, \
-	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-
-
 /* ------------------------------------------------------------------------
  * Driver specific constants.
  */
@@ -280,12 +145,6 @@ struct uvc_control {
 	struct uvc_fh *handle;	/* File handle that last changed the control. */
 };
 
-struct uvc_format_desc {
-	char *name;
-	u8 guid[16];
-	u32 fcc;
-};
-
 /* The term 'entity' refers to both UVC units and UVC terminals.
  *
  * The type field is either the terminal type (wTerminalType in the terminal
diff --git a/include/media/v4l2-uvc.h b/include/media/v4l2-uvc.h
new file mode 100644
index 00000000000000..f1b21e1ec7a1a9
--- /dev/null
+++ b/include/media/v4l2-uvc.h
@@ -0,0 +1,351 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *  v4l2 uvc internal API header
+ *
+ *  Some commonly needed functions for uvc drivers
+ */
+
+#ifndef __LINUX_V4L2_UVC_H
+#define __LINUX_V4L2_UVC_H
+
+/* ------------------------------------------------------------------------
+ * GUIDs
+ */
+#define UVC_GUID_UVC_CAMERA \
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
+#define UVC_GUID_UVC_OUTPUT \
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}
+#define UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT \
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
+#define UVC_GUID_UVC_PROCESSING \
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01}
+#define UVC_GUID_UVC_SELECTOR \
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}
+#define UVC_GUID_EXT_GPIO_CONTROLLER \
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03}
+
+#define UVC_GUID_FORMAT_MJPEG \
+	{ 'M',  'J',  'P',  'G', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YUY2 \
+	{ 'Y',  'U',  'Y',  '2', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YUY2_ISIGHT \
+	{ 'Y',  'U',  'Y',  '2', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0x00, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_NV12 \
+	{ 'N',  'V',  '1',  '2', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YV12 \
+	{ 'Y',  'V',  '1',  '2', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_I420 \
+	{ 'I',  '4',  '2',  '0', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_UYVY \
+	{ 'U',  'Y',  'V',  'Y', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y800 \
+	{ 'Y',  '8',  '0',  '0', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y8 \
+	{ 'Y',  '8',  ' ',  ' ', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y10 \
+	{ 'Y',  '1',  '0',  ' ', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y12 \
+	{ 'Y',  '1',  '2',  ' ', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y16 \
+	{ 'Y',  '1',  '6',  ' ', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_BY8 \
+	{ 'B',  'Y',  '8',  ' ', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_BA81 \
+	{ 'B',  'A',  '8',  '1', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_GBRG \
+	{ 'G',  'B',  'R',  'G', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_GRBG \
+	{ 'G',  'R',  'B',  'G', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_RGGB \
+	{ 'R',  'G',  'G',  'B', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_BG16 \
+	{ 'B',  'G',  '1',  '6', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_GB16 \
+	{ 'G',  'B',  '1',  '6', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_RG16 \
+	{ 'R',  'G',  '1',  '6', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_GR16 \
+	{ 'G',  'R',  '1',  '6', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_RGBP \
+	{ 'R',  'G',  'B',  'P', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_BGR3 \
+	{ 0x7d, 0xeb, 0x36, 0xe4, 0x4f, 0x52, 0xce, 0x11, \
+	 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}
+#define UVC_GUID_FORMAT_M420 \
+	{ 'M',  '4',  '2',  '0', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+
+#define UVC_GUID_FORMAT_H264 \
+	{ 'H',  '2',  '6',  '4', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y8I \
+	{ 'Y',  '8',  'I',  ' ', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y12I \
+	{ 'Y',  '1',  '2',  'I', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Z16 \
+	{ 'Z',  '1',  '6',  ' ', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_RW10 \
+	{ 'R',  'W',  '1',  '0', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_INVZ \
+	{ 'I',  'N',  'V',  'Z', 0x90, 0x2d, 0x58, 0x4a, \
+	 0x92, 0x0b, 0x77, 0x3f, 0x1f, 0x2c, 0x55, 0x6b}
+#define UVC_GUID_FORMAT_INZI \
+	{ 'I',  'N',  'Z',  'I', 0x66, 0x1a, 0x42, 0xa2, \
+	 0x90, 0x65, 0xd0, 0x18, 0x14, 0xa8, 0xef, 0x8a}
+#define UVC_GUID_FORMAT_INVI \
+	{ 'I',  'N',  'V',  'I', 0xdb, 0x57, 0x49, 0x5e, \
+	 0x8e, 0x3f, 0xf4, 0x79, 0x53, 0x2b, 0x94, 0x6f}
+#define UVC_GUID_FORMAT_CNF4 \
+	{ 'C',  ' ',  ' ',  ' ', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+
+#define UVC_GUID_FORMAT_D3DFMT_L8 \
+	{0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_KSMEDIA_L8_IR \
+	{0x32, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+
+#define UVC_GUID_FORMAT_HEVC \
+	{ 'H',  'E',  'V',  'C', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+
+/* ------------------------------------------------------------------------
+ * Video formats
+ */
+
+struct uvc_format_desc {
+	char *name;
+	u8 guid[16];
+	u32 fcc;
+};
+
+static struct uvc_format_desc uvc_fmts[] = {
+	{
+		.name		= "YUV 4:2:2 (YUYV)",
+		.guid		= UVC_GUID_FORMAT_YUY2,
+		.fcc		= V4L2_PIX_FMT_YUYV,
+	},
+	{
+		.name		= "YUV 4:2:2 (YUYV)",
+		.guid		= UVC_GUID_FORMAT_YUY2_ISIGHT,
+		.fcc		= V4L2_PIX_FMT_YUYV,
+	},
+	{
+		.name		= "YUV 4:2:0 (NV12)",
+		.guid		= UVC_GUID_FORMAT_NV12,
+		.fcc		= V4L2_PIX_FMT_NV12,
+	},
+	{
+		.name		= "MJPEG",
+		.guid		= UVC_GUID_FORMAT_MJPEG,
+		.fcc		= V4L2_PIX_FMT_MJPEG,
+	},
+	{
+		.name		= "YVU 4:2:0 (YV12)",
+		.guid		= UVC_GUID_FORMAT_YV12,
+		.fcc		= V4L2_PIX_FMT_YVU420,
+	},
+	{
+		.name		= "YUV 4:2:0 (I420)",
+		.guid		= UVC_GUID_FORMAT_I420,
+		.fcc		= V4L2_PIX_FMT_YUV420,
+	},
+	{
+		.name		= "YUV 4:2:0 (M420)",
+		.guid		= UVC_GUID_FORMAT_M420,
+		.fcc		= V4L2_PIX_FMT_M420,
+	},
+	{
+		.name		= "YUV 4:2:2 (UYVY)",
+		.guid		= UVC_GUID_FORMAT_UYVY,
+		.fcc		= V4L2_PIX_FMT_UYVY,
+	},
+	{
+		.name		= "Greyscale 8-bit (Y800)",
+		.guid		= UVC_GUID_FORMAT_Y800,
+		.fcc		= V4L2_PIX_FMT_GREY,
+	},
+	{
+		.name		= "Greyscale 8-bit (Y8  )",
+		.guid		= UVC_GUID_FORMAT_Y8,
+		.fcc		= V4L2_PIX_FMT_GREY,
+	},
+	{
+		.name		= "Greyscale 8-bit (D3DFMT_L8)",
+		.guid		= UVC_GUID_FORMAT_D3DFMT_L8,
+		.fcc		= V4L2_PIX_FMT_GREY,
+	},
+	{
+		.name		= "IR 8-bit (L8_IR)",
+		.guid		= UVC_GUID_FORMAT_KSMEDIA_L8_IR,
+		.fcc		= V4L2_PIX_FMT_GREY,
+	},
+	{
+		.name		= "Greyscale 10-bit (Y10 )",
+		.guid		= UVC_GUID_FORMAT_Y10,
+		.fcc		= V4L2_PIX_FMT_Y10,
+	},
+	{
+		.name		= "Greyscale 12-bit (Y12 )",
+		.guid		= UVC_GUID_FORMAT_Y12,
+		.fcc		= V4L2_PIX_FMT_Y12,
+	},
+	{
+		.name		= "Greyscale 16-bit (Y16 )",
+		.guid		= UVC_GUID_FORMAT_Y16,
+		.fcc		= V4L2_PIX_FMT_Y16,
+	},
+	{
+		.name		= "BGGR Bayer (BY8 )",
+		.guid		= UVC_GUID_FORMAT_BY8,
+		.fcc		= V4L2_PIX_FMT_SBGGR8,
+	},
+	{
+		.name		= "BGGR Bayer (BA81)",
+		.guid		= UVC_GUID_FORMAT_BA81,
+		.fcc		= V4L2_PIX_FMT_SBGGR8,
+	},
+	{
+		.name		= "GBRG Bayer (GBRG)",
+		.guid		= UVC_GUID_FORMAT_GBRG,
+		.fcc		= V4L2_PIX_FMT_SGBRG8,
+	},
+	{
+		.name		= "GRBG Bayer (GRBG)",
+		.guid		= UVC_GUID_FORMAT_GRBG,
+		.fcc		= V4L2_PIX_FMT_SGRBG8,
+	},
+	{
+		.name		= "RGGB Bayer (RGGB)",
+		.guid		= UVC_GUID_FORMAT_RGGB,
+		.fcc		= V4L2_PIX_FMT_SRGGB8,
+	},
+	{
+		.name		= "RGB565",
+		.guid		= UVC_GUID_FORMAT_RGBP,
+		.fcc		= V4L2_PIX_FMT_RGB565,
+	},
+	{
+		.name		= "BGR 8:8:8 (BGR3)",
+		.guid		= UVC_GUID_FORMAT_BGR3,
+		.fcc		= V4L2_PIX_FMT_BGR24,
+	},
+	{
+		.name		= "H.264",
+		.guid		= UVC_GUID_FORMAT_H264,
+		.fcc		= V4L2_PIX_FMT_H264,
+	},
+	{
+		.name		= "Greyscale 8 L/R (Y8I)",
+		.guid		= UVC_GUID_FORMAT_Y8I,
+		.fcc		= V4L2_PIX_FMT_Y8I,
+	},
+	{
+		.name		= "Greyscale 12 L/R (Y12I)",
+		.guid		= UVC_GUID_FORMAT_Y12I,
+		.fcc		= V4L2_PIX_FMT_Y12I,
+	},
+	{
+		.name		= "Depth data 16-bit (Z16)",
+		.guid		= UVC_GUID_FORMAT_Z16,
+		.fcc		= V4L2_PIX_FMT_Z16,
+	},
+	{
+		.name		= "Bayer 10-bit (SRGGB10P)",
+		.guid		= UVC_GUID_FORMAT_RW10,
+		.fcc		= V4L2_PIX_FMT_SRGGB10P,
+	},
+	{
+		.name		= "Bayer 16-bit (SBGGR16)",
+		.guid		= UVC_GUID_FORMAT_BG16,
+		.fcc		= V4L2_PIX_FMT_SBGGR16,
+	},
+	{
+		.name		= "Bayer 16-bit (SGBRG16)",
+		.guid		= UVC_GUID_FORMAT_GB16,
+		.fcc		= V4L2_PIX_FMT_SGBRG16,
+	},
+	{
+		.name		= "Bayer 16-bit (SRGGB16)",
+		.guid		= UVC_GUID_FORMAT_RG16,
+		.fcc		= V4L2_PIX_FMT_SRGGB16,
+	},
+	{
+		.name		= "Bayer 16-bit (SGRBG16)",
+		.guid		= UVC_GUID_FORMAT_GR16,
+		.fcc		= V4L2_PIX_FMT_SGRBG16,
+	},
+	{
+		.name		= "Depth data 16-bit (Z16)",
+		.guid		= UVC_GUID_FORMAT_INVZ,
+		.fcc		= V4L2_PIX_FMT_Z16,
+	},
+	{
+		.name		= "Greyscale 10-bit (Y10 )",
+		.guid		= UVC_GUID_FORMAT_INVI,
+		.fcc		= V4L2_PIX_FMT_Y10,
+	},
+	{
+		.name		= "IR:Depth 26-bit (INZI)",
+		.guid		= UVC_GUID_FORMAT_INZI,
+		.fcc		= V4L2_PIX_FMT_INZI,
+	},
+	{
+		.name		= "4-bit Depth Confidence (Packed)",
+		.guid		= UVC_GUID_FORMAT_CNF4,
+		.fcc		= V4L2_PIX_FMT_CNF4,
+	},
+	{
+		.name		= "HEVC",
+		.guid		= UVC_GUID_FORMAT_HEVC,
+		.fcc		= V4L2_PIX_FMT_HEVC,
+	},
+};
+
+static inline struct uvc_format_desc *uvc_format_by_guid(const u8 guid[16])
+{
+	unsigned int len = ARRAY_SIZE(uvc_fmts);
+	unsigned int i;
+
+	for (i = 0; i < len; ++i) {
+		if (memcmp(guid, uvc_fmts[i].guid, 16) == 0)
+			return &uvc_fmts[i];
+	}
+
+	return NULL;
+}
+
+#endif /* __LINUX_V4L2_UVC_H */
-- 
2.30.2


^ permalink raw reply related

* [PATCH v6 5/7] usb: gadget: uvc: track frames in format entries
From: Michael Grzeschik @ 2022-01-05 11:55 UTC (permalink / raw)
  To: linux-usb; +Cc: balbi, laurent.pinchart, paul.elder, kernel
In-Reply-To: <20220105115527.3592860-1-m.grzeschik@pengutronix.de>

Just like the header is tracking the formats in a linked list, in this
patch we track the frames in a linked list of the formats. It
simplifies the parsing of the configfs structure.

Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>

---
v1 -> v2: -
v2 -> v3: -
v3 -> v4: -
v4 -> v5: -
v5 -> v6: -

 drivers/usb/gadget/function/uvc_configfs.c | 25 +++++++++++++++++++++-
 drivers/usb/gadget/function/uvc_configfs.h |  6 ++++++
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index 05dc5764020006..41c1876921bb65 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -1262,6 +1262,7 @@ static struct config_item *uvcg_frame_make(struct config_group *group,
 	struct uvcg_format *fmt;
 	struct f_uvc_opts *opts;
 	struct config_item *opts_item;
+	struct uvcg_frame_ptr *frame_ptr;
 
 	h = kzalloc(sizeof(*h), GFP_KERNEL);
 	if (!h)
@@ -1292,6 +1293,16 @@ static struct config_item *uvcg_frame_make(struct config_group *group,
 		kfree(h);
 		return ERR_PTR(-EINVAL);
 	}
+
+	frame_ptr = kzalloc(sizeof(*frame_ptr), GFP_KERNEL);
+	if (!frame_ptr) {
+		mutex_unlock(&opts->lock);
+		kfree(h);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	frame_ptr->frm = h;
+	list_add_tail(&frame_ptr->entry, &fmt->frames);
 	++fmt->num_frames;
 	mutex_unlock(&opts->lock);
 
@@ -1305,13 +1316,23 @@ static void uvcg_frame_drop(struct config_group *group, struct config_item *item
 	struct uvcg_format *fmt;
 	struct f_uvc_opts *opts;
 	struct config_item *opts_item;
+	struct uvcg_frame *target_frm = NULL;
+	struct uvcg_frame_ptr *frame_ptr, *tmp;
 
 	opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
 	opts = to_f_uvc_opts(opts_item);
 
 	mutex_lock(&opts->lock);
+	target_frm = container_of(item, struct uvcg_frame, item);
 	fmt = to_uvcg_format(&group->cg_item);
-	--fmt->num_frames;
+
+	list_for_each_entry_safe(frame_ptr, tmp, &fmt->frames, entry)
+		if (frame_ptr->frm == target_frm) {
+			list_del(&frame_ptr->entry);
+			kfree(frame_ptr);
+			--fmt->num_frames;
+			break;
+		}
 	mutex_unlock(&opts->lock);
 
 	config_item_put(item);
@@ -1556,6 +1577,7 @@ static struct config_group *uvcg_uncompressed_make(struct config_group *group,
 	h->desc.bmInterfaceFlags	= 0;
 	h->desc.bCopyProtect		= 0;
 
+	INIT_LIST_HEAD(&h->fmt.frames);
 	h->fmt.type = UVCG_UNCOMPRESSED;
 	config_group_init_type_name(&h->fmt.group, name,
 				    &uvcg_uncompressed_type);
@@ -1736,6 +1758,7 @@ static struct config_group *uvcg_mjpeg_make(struct config_group *group,
 	h->desc.bmInterfaceFlags	= 0;
 	h->desc.bCopyProtect		= 0;
 
+	INIT_LIST_HEAD(&h->fmt.frames);
 	h->fmt.type = UVCG_MJPEG;
 	config_group_init_type_name(&h->fmt.group, name,
 				    &uvcg_mjpeg_type);
diff --git a/drivers/usb/gadget/function/uvc_configfs.h b/drivers/usb/gadget/function/uvc_configfs.h
index 1ec8529ff1e4fe..ad2ec8c4c78c35 100644
--- a/drivers/usb/gadget/function/uvc_configfs.h
+++ b/drivers/usb/gadget/function/uvc_configfs.h
@@ -46,6 +46,7 @@ struct uvcg_format {
 	struct config_group	group;
 	enum uvcg_format_type	type;
 	unsigned		linked;
+	struct list_head	frames;
 	unsigned		num_frames;
 	__u8			bmaControls[UVCG_STREAMING_CONTROL_SIZE];
 };
@@ -73,6 +74,11 @@ static inline struct uvcg_streaming_header *to_uvcg_streaming_header(struct conf
 	return container_of(item, struct uvcg_streaming_header, item);
 }
 
+struct uvcg_frame_ptr {
+	struct uvcg_frame	*frm;
+	struct list_head	entry;
+};
+
 struct uvcg_frame {
 	struct config_item	item;
 	enum uvcg_format_type	fmt_type;
-- 
2.30.2


^ permalink raw reply related

* [PATCH v6 4/7] usb: gadget: uvc: move structs to common header
From: Michael Grzeschik @ 2022-01-05 11:55 UTC (permalink / raw)
  To: linux-usb; +Cc: balbi, laurent.pinchart, paul.elder, kernel
In-Reply-To: <20220105115527.3592860-1-m.grzeschik@pengutronix.de>

The functions and structs of the configfs interface should also be used
by the uvc gadget driver. This patch prepares the stack by moving the
common structs and functions to the common header file.

Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>

---
v1 -> v2:
   - moved uvcg_attach_configfs declaration to end of header file
   - moved header uvc_configfs to beginning of uvc_configfs.c
   - simplified call of to_uvcg_uncompressed
   - simplified call of to_uvcg_mjpeg
   - moved uvc_configfs.h to the beginning to show that the header is self-contained
v2 -> v3:
   - fixed include of uvcg_format_names back to uvc_configfs.c
v3 -> v4: -
v4 -> v5: -
v5 -> v6: -

 drivers/usb/gadget/function/f_uvc.c        |   1 -
 drivers/usb/gadget/function/uvc_configfs.c | 111 +-------------------
 drivers/usb/gadget/function/uvc_configfs.h | 114 ++++++++++++++++++++-
 3 files changed, 115 insertions(+), 111 deletions(-)

diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 71bb5e477dbad7..37fdf8b3495a48 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -24,7 +24,6 @@
 #include <media/v4l2-dev.h>
 #include <media/v4l2-event.h>
 
-#include "u_uvc.h"
 #include "uvc.h"
 #include "uvc_configfs.h"
 #include "uvc_v4l2.h"
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index b6bb5706299951..05dc5764020006 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -10,17 +10,14 @@
  * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
  */
 
-#include <linux/sort.h>
-
-#include "u_uvc.h"
 #include "uvc_configfs.h"
 
+#include <linux/sort.h>
+
 /* -----------------------------------------------------------------------------
  * Global Utility Structures and Macros
  */
 
-#define UVCG_STREAMING_CONTROL_SIZE	1
-
 #define UVC_ATTR(prefix, cname, aname) \
 static struct configfs_attribute prefix##attr_##cname = { \
 	.ca_name	= __stringify(aname),				\
@@ -49,12 +46,6 @@ static int uvcg_config_compare_u32(const void *l, const void *r)
 	return li < ri ? -1 : li == ri ? 0 : 1;
 }
 
-static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item)
-{
-	return container_of(to_config_group(item), struct f_uvc_opts,
-			    func_inst.group);
-}
-
 struct uvcg_config_group_type {
 	struct config_item_type type;
 	const char *name;
@@ -125,19 +116,6 @@ static void uvcg_config_remove_children(struct config_group *group)
  * control/header
  */
 
-DECLARE_UVC_HEADER_DESCRIPTOR(1);
-
-struct uvcg_control_header {
-	struct config_item		item;
-	struct UVC_HEADER_DESCRIPTOR(1)	desc;
-	unsigned			linked;
-};
-
-static struct uvcg_control_header *to_uvcg_control_header(struct config_item *item)
-{
-	return container_of(item, struct uvcg_control_header, item);
-}
-
 #define UVCG_CTRL_HDR_ATTR(cname, aname, bits, limit)			\
 static ssize_t uvcg_control_header_##cname##_show(			\
 	struct config_item *item, char *page)				\
@@ -769,24 +747,6 @@ static const char * const uvcg_format_names[] = {
 	"mjpeg",
 };
 
-enum uvcg_format_type {
-	UVCG_UNCOMPRESSED = 0,
-	UVCG_MJPEG,
-};
-
-struct uvcg_format {
-	struct config_group	group;
-	enum uvcg_format_type	type;
-	unsigned		linked;
-	unsigned		num_frames;
-	__u8			bmaControls[UVCG_STREAMING_CONTROL_SIZE];
-};
-
-static struct uvcg_format *to_uvcg_format(struct config_item *item)
-{
-	return container_of(to_config_group(item), struct uvcg_format, group);
-}
-
 static ssize_t uvcg_format_bma_controls_show(struct uvcg_format *f, char *page)
 {
 	struct f_uvc_opts *opts;
@@ -845,29 +805,11 @@ static ssize_t uvcg_format_bma_controls_store(struct uvcg_format *ch,
 	return ret;
 }
 
-struct uvcg_format_ptr {
-	struct uvcg_format	*fmt;
-	struct list_head	entry;
-};
-
 /* -----------------------------------------------------------------------------
  * streaming/header/<NAME>
  * streaming/header
  */
 
-struct uvcg_streaming_header {
-	struct config_item				item;
-	struct uvc_input_header_descriptor		desc;
-	unsigned					linked;
-	struct list_head				formats;
-	unsigned					num_fmt;
-};
-
-static struct uvcg_streaming_header *to_uvcg_streaming_header(struct config_item *item)
-{
-	return container_of(item, struct uvcg_streaming_header, item);
-}
-
 static void uvcg_format_set_indices(struct config_group *fmt);
 
 static int uvcg_streaming_header_allow_link(struct config_item *src,
@@ -1059,31 +1001,6 @@ static const struct uvcg_config_group_type uvcg_streaming_header_grp_type = {
  * streaming/<mode>/<format>/<NAME>
  */
 
-struct uvcg_frame {
-	struct config_item	item;
-	enum uvcg_format_type	fmt_type;
-	struct {
-		u8	b_length;
-		u8	b_descriptor_type;
-		u8	b_descriptor_subtype;
-		u8	b_frame_index;
-		u8	bm_capabilities;
-		u16	w_width;
-		u16	w_height;
-		u32	dw_min_bit_rate;
-		u32	dw_max_bit_rate;
-		u32	dw_max_video_frame_buffer_size;
-		u32	dw_default_frame_interval;
-		u8	b_frame_interval_type;
-	} __attribute__((packed)) frame;
-	u32 *dw_frame_interval;
-};
-
-static struct uvcg_frame *to_uvcg_frame(struct config_item *item)
-{
-	return container_of(item, struct uvcg_frame, item);
-}
-
 #define UVCG_FRAME_ATTR(cname, aname, bits) \
 static ssize_t uvcg_frame_##cname##_show(struct config_item *item, char *page)\
 {									\
@@ -1420,18 +1337,6 @@ static void uvcg_format_set_indices(struct config_group *fmt)
  * streaming/uncompressed/<NAME>
  */
 
-struct uvcg_uncompressed {
-	struct uvcg_format		fmt;
-	struct uvc_format_uncompressed	desc;
-};
-
-static struct uvcg_uncompressed *to_uvcg_uncompressed(struct config_item *item)
-{
-	return container_of(
-		container_of(to_config_group(item), struct uvcg_format, group),
-		struct uvcg_uncompressed, fmt);
-}
-
 static struct configfs_group_operations uvcg_uncompressed_group_ops = {
 	.make_item		= uvcg_frame_make,
 	.drop_item		= uvcg_frame_drop,
@@ -1675,18 +1580,6 @@ static const struct uvcg_config_group_type uvcg_uncompressed_grp_type = {
  * streaming/mjpeg/<NAME>
  */
 
-struct uvcg_mjpeg {
-	struct uvcg_format		fmt;
-	struct uvc_format_mjpeg		desc;
-};
-
-static struct uvcg_mjpeg *to_uvcg_mjpeg(struct config_item *item)
-{
-	return container_of(
-		container_of(to_config_group(item), struct uvcg_format, group),
-		struct uvcg_mjpeg, fmt);
-}
-
 static struct configfs_group_operations uvcg_mjpeg_group_ops = {
 	.make_item		= uvcg_frame_make,
 	.drop_item		= uvcg_frame_drop,
diff --git a/drivers/usb/gadget/function/uvc_configfs.h b/drivers/usb/gadget/function/uvc_configfs.h
index 7e1d7ca29bf210..1ec8529ff1e4fe 100644
--- a/drivers/usb/gadget/function/uvc_configfs.h
+++ b/drivers/usb/gadget/function/uvc_configfs.h
@@ -12,7 +12,119 @@
 #ifndef UVC_CONFIGFS_H
 #define UVC_CONFIGFS_H
 
-struct f_uvc_opts;
+#include <linux/configfs.h>
+
+#include "u_uvc.h"
+
+static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item)
+{
+	return container_of(to_config_group(item), struct f_uvc_opts,
+			    func_inst.group);
+}
+
+#define UVCG_STREAMING_CONTROL_SIZE	1
+
+DECLARE_UVC_HEADER_DESCRIPTOR(1);
+
+struct uvcg_control_header {
+	struct config_item		item;
+	struct UVC_HEADER_DESCRIPTOR(1)	desc;
+	unsigned			linked;
+};
+
+static inline struct uvcg_control_header *to_uvcg_control_header(struct config_item *item)
+{
+	return container_of(item, struct uvcg_control_header, item);
+}
+
+enum uvcg_format_type {
+	UVCG_UNCOMPRESSED = 0,
+	UVCG_MJPEG,
+};
+
+struct uvcg_format {
+	struct config_group	group;
+	enum uvcg_format_type	type;
+	unsigned		linked;
+	unsigned		num_frames;
+	__u8			bmaControls[UVCG_STREAMING_CONTROL_SIZE];
+};
+
+struct uvcg_format_ptr {
+	struct uvcg_format	*fmt;
+	struct list_head	entry;
+};
+
+static inline struct uvcg_format *to_uvcg_format(struct config_item *item)
+{
+	return container_of(to_config_group(item), struct uvcg_format, group);
+}
+
+struct uvcg_streaming_header {
+	struct config_item				item;
+	struct uvc_input_header_descriptor		desc;
+	unsigned					linked;
+	struct list_head				formats;
+	unsigned					num_fmt;
+};
+
+static inline struct uvcg_streaming_header *to_uvcg_streaming_header(struct config_item *item)
+{
+	return container_of(item, struct uvcg_streaming_header, item);
+}
+
+struct uvcg_frame {
+	struct config_item	item;
+	enum uvcg_format_type	fmt_type;
+	struct {
+		u8	b_length;
+		u8	b_descriptor_type;
+		u8	b_descriptor_subtype;
+		u8	b_frame_index;
+		u8	bm_capabilities;
+		u16	w_width;
+		u16	w_height;
+		u32	dw_min_bit_rate;
+		u32	dw_max_bit_rate;
+		u32	dw_max_video_frame_buffer_size;
+		u32	dw_default_frame_interval;
+		u8	b_frame_interval_type;
+	} __attribute__((packed)) frame;
+	u32 *dw_frame_interval;
+};
+
+static inline struct uvcg_frame *to_uvcg_frame(struct config_item *item)
+{
+	return container_of(item, struct uvcg_frame, item);
+}
+
+/* -----------------------------------------------------------------------------
+ * streaming/uncompressed/<NAME>
+ */
+
+struct uvcg_uncompressed {
+	struct uvcg_format		fmt;
+	struct uvc_format_uncompressed	desc;
+};
+
+static inline struct uvcg_uncompressed *to_uvcg_uncompressed(struct config_item *item)
+{
+	return container_of(to_uvcg_format(item), struct uvcg_uncompressed, fmt);
+}
+
+/* -----------------------------------------------------------------------------
+ * streaming/mjpeg/<NAME>
+ */
+
+struct uvcg_mjpeg {
+	struct uvcg_format		fmt;
+	struct uvc_format_mjpeg		desc;
+};
+
+static inline struct uvcg_mjpeg *to_uvcg_mjpeg(struct config_item *item)
+{
+	return container_of(to_uvcg_format(item), struct uvcg_mjpeg, fmt);
+}
 
 int uvcg_attach_configfs(struct f_uvc_opts *opts);
 
-- 
2.30.2


^ permalink raw reply related

* [PATCH v6 3/7] usb: gadget: uvc: prevent index variables to start from 0
From: Michael Grzeschik @ 2022-01-05 11:55 UTC (permalink / raw)
  To: linux-usb; +Cc: balbi, laurent.pinchart, paul.elder, kernel
In-Reply-To: <20220105115527.3592860-1-m.grzeschik@pengutronix.de>

Some configfs variables like bDefaultFrameIndex are always starting by
1. This patch adds a check to prevent setting those variables to 0.

Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>

---
v1 -> v2: -
v2 -> v3: -
v3 -> v4: -
v4 -> v5: -
v5 -> v6: -

 drivers/usb/gadget/function/uvc_configfs.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index 77d64031aa9c2a..b6bb5706299951 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -1565,6 +1565,12 @@ uvcg_uncompressed_##cname##_store(struct config_item *item,		\
 	if (ret)							\
 		goto end;						\
 									\
+	/* index values in uvc are never 0 */				\
+	if (!num) {							\
+		ret = -EINVAL;						\
+		goto end;						\
+	}								\
+									\
 	u->desc.aname = num;						\
 	ret = len;							\
 end:									\
@@ -1758,6 +1764,12 @@ uvcg_mjpeg_##cname##_store(struct config_item *item,			\
 	if (ret)							\
 		goto end;						\
 									\
+	/* index values in uvc are never 0 */				\
+	if (!num) {							\
+		ret = -EINVAL;						\
+		goto end;						\
+	}								\
+									\
 	u->desc.aname = num;						\
 	ret = len;							\
 end:									\
-- 
2.30.2


^ permalink raw reply related

* [PATCH v6 1/7] media: v4l: move helper functions for fractions from uvc to v4l2-common
From: Michael Grzeschik @ 2022-01-05 11:55 UTC (permalink / raw)
  To: linux-usb; +Cc: balbi, laurent.pinchart, paul.elder, kernel
In-Reply-To: <20220105115527.3592860-1-m.grzeschik@pengutronix.de>

The functions uvc_simplify_fraction and uvc_fraction_to_interval are
generic helpers which are also useful for other v4l2 drivers. This patch
moves them to v4l2-common.

Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>

---
v1 -> v2: -
v2 -> v3: -
v3 -> v4: -
v4 -> v5: -
v5 -> v6: -

 drivers/media/usb/uvc/uvc_driver.c    | 80 --------------------------
 drivers/media/usb/uvc/uvc_v4l2.c      | 14 ++---
 drivers/media/usb/uvc/uvcvideo.h      |  3 -
 drivers/media/v4l2-core/v4l2-common.c | 82 +++++++++++++++++++++++++++
 include/media/v4l2-common.h           |  4 ++
 5 files changed, 93 insertions(+), 90 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 7c007426e0827e..cdb92da0f56afd 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -324,86 +324,6 @@ static enum v4l2_ycbcr_encoding uvc_ycbcr_enc(const u8 matrix_coefficients)
 	return V4L2_YCBCR_ENC_DEFAULT;  /* Reserved */
 }
 
-/* Simplify a fraction using a simple continued fraction decomposition. The
- * idea here is to convert fractions such as 333333/10000000 to 1/30 using
- * 32 bit arithmetic only. The algorithm is not perfect and relies upon two
- * arbitrary parameters to remove non-significative terms from the simple
- * continued fraction decomposition. Using 8 and 333 for n_terms and threshold
- * respectively seems to give nice results.
- */
-void uvc_simplify_fraction(u32 *numerator, u32 *denominator,
-		unsigned int n_terms, unsigned int threshold)
-{
-	u32 *an;
-	u32 x, y, r;
-	unsigned int i, n;
-
-	an = kmalloc_array(n_terms, sizeof(*an), GFP_KERNEL);
-	if (an == NULL)
-		return;
-
-	/* Convert the fraction to a simple continued fraction. See
-	 * https://mathforum.org/dr.math/faq/faq.fractions.html
-	 * Stop if the current term is bigger than or equal to the given
-	 * threshold.
-	 */
-	x = *numerator;
-	y = *denominator;
-
-	for (n = 0; n < n_terms && y != 0; ++n) {
-		an[n] = x / y;
-		if (an[n] >= threshold) {
-			if (n < 2)
-				n++;
-			break;
-		}
-
-		r = x - an[n] * y;
-		x = y;
-		y = r;
-	}
-
-	/* Expand the simple continued fraction back to an integer fraction. */
-	x = 0;
-	y = 1;
-
-	for (i = n; i > 0; --i) {
-		r = y;
-		y = an[i-1] * y + x;
-		x = r;
-	}
-
-	*numerator = y;
-	*denominator = x;
-	kfree(an);
-}
-
-/* Convert a fraction to a frame interval in 100ns multiples. The idea here is
- * to compute numerator / denominator * 10000000 using 32 bit fixed point
- * arithmetic only.
- */
-u32 uvc_fraction_to_interval(u32 numerator, u32 denominator)
-{
-	u32 multiplier;
-
-	/* Saturate the result if the operation would overflow. */
-	if (denominator == 0 ||
-	    numerator/denominator >= ((u32)-1)/10000000)
-		return (u32)-1;
-
-	/* Divide both the denominator and the multiplier by two until
-	 * numerator * multiplier doesn't overflow. If anyone knows a better
-	 * algorithm please let me know.
-	 */
-	multiplier = 10000000;
-	while (numerator > ((u32)-1)/multiplier) {
-		multiplier /= 2;
-		denominator /= 2;
-	}
-
-	return denominator ? numerator * multiplier / denominator : 0;
-}
-
 /* ------------------------------------------------------------------------
  * Terminal and unit management
  */
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index f4e4aff8ddf771..9aa7ee9950c7b4 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -380,7 +380,7 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
 	mutex_unlock(&stream->mutex);
 
 	denominator = 10000000;
-	uvc_simplify_fraction(&numerator, &denominator, 8, 333);
+	v4l2_simplify_fraction(&numerator, &denominator, 8, 333);
 
 	memset(parm, 0, sizeof(*parm));
 	parm->type = stream->type;
@@ -421,7 +421,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
 	else
 		timeperframe = parm->parm.output.timeperframe;
 
-	interval = uvc_fraction_to_interval(timeperframe.numerator,
+	interval = v4l2_fraction_to_interval(timeperframe.numerator,
 		timeperframe.denominator);
 	uvc_dbg(stream->dev, FORMAT, "Setting frame interval to %u/%u (%u)\n",
 		timeperframe.numerator, timeperframe.denominator, interval);
@@ -475,7 +475,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
 	/* Return the actual frame period. */
 	timeperframe.numerator = probe.dwFrameInterval;
 	timeperframe.denominator = 10000000;
-	uvc_simplify_fraction(&timeperframe.numerator,
+	v4l2_simplify_fraction(&timeperframe.numerator,
 		&timeperframe.denominator, 8, 333);
 
 	if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
@@ -1267,7 +1267,7 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh,
 		fival->discrete.numerator =
 			frame->dwFrameInterval[index];
 		fival->discrete.denominator = 10000000;
-		uvc_simplify_fraction(&fival->discrete.numerator,
+		v4l2_simplify_fraction(&fival->discrete.numerator,
 			&fival->discrete.denominator, 8, 333);
 	} else {
 		fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
@@ -1277,11 +1277,11 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh,
 		fival->stepwise.max.denominator = 10000000;
 		fival->stepwise.step.numerator = frame->dwFrameInterval[2];
 		fival->stepwise.step.denominator = 10000000;
-		uvc_simplify_fraction(&fival->stepwise.min.numerator,
+		v4l2_simplify_fraction(&fival->stepwise.min.numerator,
 			&fival->stepwise.min.denominator, 8, 333);
-		uvc_simplify_fraction(&fival->stepwise.max.numerator,
+		v4l2_simplify_fraction(&fival->stepwise.max.numerator,
 			&fival->stepwise.max.denominator, 8, 333);
-		uvc_simplify_fraction(&fival->stepwise.step.numerator,
+		v4l2_simplify_fraction(&fival->stepwise.step.numerator,
 			&fival->stepwise.step.denominator, 8, 333);
 	}
 
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 2e5366143b8144..a61cd0a459e88d 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -906,9 +906,6 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
 		      struct uvc_xu_control_query *xqry);
 
 /* Utility functions */
-void uvc_simplify_fraction(u32 *numerator, u32 *denominator,
-			   unsigned int n_terms, unsigned int threshold);
-u32 uvc_fraction_to_interval(u32 numerator, u32 denominator);
 struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
 					    u8 epaddr);
 
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index df34b2a283bc29..1d0b56249ca0e1 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -482,3 +482,85 @@ s64 v4l2_get_link_freq(struct v4l2_ctrl_handler *handler, unsigned int mul,
 	return freq > 0 ? freq : -EINVAL;
 }
 EXPORT_SYMBOL_GPL(v4l2_get_link_freq);
+
+/* Simplify a fraction using a simple continued fraction decomposition. The
+ * idea here is to convert fractions such as 333333/10000000 to 1/30 using
+ * 32 bit arithmetic only. The algorithm is not perfect and relies upon two
+ * arbitrary parameters to remove non-significative terms from the simple
+ * continued fraction decomposition. Using 8 and 333 for n_terms and threshold
+ * respectively seems to give nice results.
+ */
+void v4l2_simplify_fraction(u32 *numerator, u32 *denominator,
+		unsigned int n_terms, unsigned int threshold)
+{
+	u32 *an;
+	u32 x, y, r;
+	unsigned int i, n;
+
+	an = kmalloc_array(n_terms, sizeof(*an), GFP_KERNEL);
+	if (an == NULL)
+		return;
+
+	/* Convert the fraction to a simple continued fraction. See
+	 * https://mathforum.org/dr.math/faq/faq.fractions.html
+	 * Stop if the current term is bigger than or equal to the given
+	 * threshold.
+	 */
+	x = *numerator;
+	y = *denominator;
+
+	for (n = 0; n < n_terms && y != 0; ++n) {
+		an[n] = x / y;
+		if (an[n] >= threshold) {
+			if (n < 2)
+				n++;
+			break;
+		}
+
+		r = x - an[n] * y;
+		x = y;
+		y = r;
+	}
+
+	/* Expand the simple continued fraction back to an integer fraction. */
+	x = 0;
+	y = 1;
+
+	for (i = n; i > 0; --i) {
+		r = y;
+		y = an[i-1] * y + x;
+		x = r;
+	}
+
+	*numerator = y;
+	*denominator = x;
+	kfree(an);
+}
+EXPORT_SYMBOL_GPL(v4l2_simplify_fraction);
+
+/* Convert a fraction to a frame interval in 100ns multiples. The idea here is
+ * to compute numerator / denominator * 10000000 using 32 bit fixed point
+ * arithmetic only.
+ */
+u32 v4l2_fraction_to_interval(u32 numerator, u32 denominator)
+{
+	u32 multiplier;
+
+	/* Saturate the result if the operation would overflow. */
+	if (denominator == 0 ||
+	    numerator/denominator >= ((u32)-1)/10000000)
+		return (u32)-1;
+
+	/* Divide both the denominator and the multiplier by two until
+	 * numerator * multiplier doesn't overflow. If anyone knows a better
+	 * algorithm please let me know.
+	 */
+	multiplier = 10000000;
+	while (numerator > ((u32)-1)/multiplier) {
+		multiplier /= 2;
+		denominator /= 2;
+	}
+
+	return denominator ? numerator * multiplier / denominator : 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_fraction_to_interval);
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index 3eb202259e8ccd..df4ad81251195e 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -540,6 +540,10 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, u32 pixelformat,
 s64 v4l2_get_link_freq(struct v4l2_ctrl_handler *handler, unsigned int mul,
 		       unsigned int div);
 
+void v4l2_simplify_fraction(u32 *numerator, u32 *denominator,
+		unsigned int n_terms, unsigned int threshold);
+u32 v4l2_fraction_to_interval(u32 numerator, u32 denominator);
+
 static inline u64 v4l2_buffer_get_timestamp(const struct v4l2_buffer *buf)
 {
 	/*
-- 
2.30.2


^ permalink raw reply related

* [PATCH v6 0/7] usb: gadget: uvc: use configfs entries for negotiation and v4l2 VIDIOCS
From: Michael Grzeschik @ 2022-01-05 11:55 UTC (permalink / raw)
  To: linux-usb; +Cc: balbi, laurent.pinchart, paul.elder, kernel

This series improves the uvc video gadget by parsing the configfs
entries. With the configfs data, the driver now is able to negotiate the
format with the usb host in the kernel and also exports the supported
frames/formats/intervals via the v4l2 VIDIOC interface.

The uvc userspace stack is also under development. One example is an generic
v4l2uvcsink gstreamer elemnt, which is currently under duiscussion. [1]

[1] https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1304

With the libusbgx library [1] used by the gadget-tool [2] it is now also
possible to fully describe the configfs layout of the uvc gadget with scheme
files.

[2] https://github.com/linux-usb-gadgets/libusbgx/pull/61/commits/53231c76f9d512f59fdc23b65cd5c46b7fb09eb4

[3] https://github.com/linux-usb-gadgets/gt/tree/master/examples/systemd

The bigger picture of these patches is to provide a more versatile interface to
the uvc gadget. The goal is to simply start a uvc-gadget with the following
commands:

$ gt load uvc.scheme
$ gst-launch v4l2src ! v4l2uvcsink

--

v1: https://lore.kernel.org/linux-usb/20210530222239.8793-1-m.grzeschik@pengutronix.de/
v2: https://lore.kernel.org/linux-usb/20211117004432.3763306-1-m.grzeschik@pengutronix.de/
v3: https://lore.kernel.org/linux-usb/20211117122435.2409362-1-m.grzeschik@pengutronix.de/
v4: https://lore.kernel.org/linux-usb/20211205225803.268492-1-m.grzeschik@pengutronix.de/
v5: https://lore.kernel.org/linux-usb/20211209084322.2662616-1-m.grzeschik@pengutronix.de/

Regards,
Michael

Michael Grzeschik (7):
  media: v4l: move helper functions for fractions from uvc to
    v4l2-common
  media: uvcvideo: move uvc_format_desc to common header
  usb: gadget: uvc: prevent index variables to start from 0
  usb: gadget: uvc: move structs to common header
  usb: gadget: uvc: track frames in format entries
  usb: gadget: uvc: add VIDIOC function
  usb: gadget: uvc: add format/frame handling code

 drivers/media/usb/uvc/uvc_ctrl.c           |   1 +
 drivers/media/usb/uvc/uvc_driver.c         | 281 +-------------
 drivers/media/usb/uvc/uvc_v4l2.c           |  14 +-
 drivers/media/usb/uvc/uvcvideo.h           | 144 --------
 drivers/media/v4l2-core/v4l2-common.c      |  82 +++++
 drivers/usb/gadget/function/f_uvc.c        | 263 +++++++++++++-
 drivers/usb/gadget/function/uvc.h          |  38 +-
 drivers/usb/gadget/function/uvc_configfs.c | 148 ++------
 drivers/usb/gadget/function/uvc_configfs.h | 120 +++++-
 drivers/usb/gadget/function/uvc_queue.c    |   3 +-
 drivers/usb/gadget/function/uvc_v4l2.c     | 404 ++++++++++++++++++---
 drivers/usb/gadget/function/uvc_video.c    |  71 +++-
 include/media/v4l2-common.h                |   4 +
 include/media/v4l2-uvc.h                   | 351 ++++++++++++++++++
 14 files changed, 1319 insertions(+), 605 deletions(-)
 create mode 100644 include/media/v4l2-uvc.h

-- 
2.30.2


^ permalink raw reply

* [Intel-gfx] ✓ Fi.CI.BAT: success for drm/i915: stop including i915_irq.h from i915_drv.h
From: Patchwork @ 2022-01-05 11:55 UTC (permalink / raw)
  To: Jani Nikula; +Cc: intel-gfx
In-Reply-To: <20220105102131.988791-1-jani.nikula@intel.com>

[-- Attachment #1: Type: text/plain, Size: 7763 bytes --]

== Series Details ==

Series: drm/i915: stop including i915_irq.h from i915_drv.h
URL   : https://patchwork.freedesktop.org/series/98500/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_11047 -> Patchwork_21926
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/index.html

Participating hosts (48 -> 37)
------------------------------

  Additional (2): fi-kbl-soraka fi-icl-u2 
  Missing    (13): fi-ilk-m540 bat-dg1-6 bat-dg1-5 fi-hsw-4200u fi-bsw-cyan bat-adlp-6 bat-adlp-4 fi-ctg-p8600 fi-pnv-d510 bat-rpls-1 fi-bdw-samus bat-jsl-2 bat-jsl-1 

Known issues
------------

  Here are the changes found in Patchwork_21926 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@amdgpu/amd_cs_nop@fork-gfx0:
    - fi-icl-u2:          NOTRUN -> [SKIP][1] ([fdo#109315]) +17 similar issues
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/fi-icl-u2/igt@amdgpu/amd_cs_nop@fork-gfx0.html

  * igt@gem_exec_fence@basic-busy@bcs0:
    - fi-kbl-soraka:      NOTRUN -> [SKIP][2] ([fdo#109271]) +24 similar issues
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/fi-kbl-soraka/igt@gem_exec_fence@basic-busy@bcs0.html

  * igt@gem_huc_copy@huc-copy:
    - fi-kbl-soraka:      NOTRUN -> [SKIP][3] ([fdo#109271] / [i915#2190])
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/fi-kbl-soraka/igt@gem_huc_copy@huc-copy.html
    - fi-icl-u2:          NOTRUN -> [SKIP][4] ([i915#2190])
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/fi-icl-u2/igt@gem_huc_copy@huc-copy.html

  * igt@gem_lmem_swapping@basic:
    - fi-kbl-soraka:      NOTRUN -> [SKIP][5] ([fdo#109271] / [i915#4613]) +3 similar issues
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/fi-kbl-soraka/igt@gem_lmem_swapping@basic.html

  * igt@gem_lmem_swapping@parallel-random-engines:
    - fi-icl-u2:          NOTRUN -> [SKIP][6] ([i915#4613]) +3 similar issues
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/fi-icl-u2/igt@gem_lmem_swapping@parallel-random-engines.html

  * igt@i915_selftest@live@gt_pm:
    - fi-kbl-soraka:      NOTRUN -> [DMESG-FAIL][7] ([i915#1886] / [i915#2291])
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/fi-kbl-soraka/igt@i915_selftest@live@gt_pm.html

  * igt@kms_chamelium@common-hpd-after-suspend:
    - fi-kbl-soraka:      NOTRUN -> [SKIP][8] ([fdo#109271] / [fdo#111827]) +8 similar issues
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/fi-kbl-soraka/igt@kms_chamelium@common-hpd-after-suspend.html

  * igt@kms_chamelium@hdmi-hpd-fast:
    - fi-icl-u2:          NOTRUN -> [SKIP][9] ([fdo#111827]) +8 similar issues
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/fi-icl-u2/igt@kms_chamelium@hdmi-hpd-fast.html

  * igt@kms_cursor_legacy@basic-busy-flip-before-cursor-legacy:
    - fi-icl-u2:          NOTRUN -> [SKIP][10] ([fdo#109278]) +2 similar issues
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/fi-icl-u2/igt@kms_cursor_legacy@basic-busy-flip-before-cursor-legacy.html

  * igt@kms_force_connector_basic@force-connector-state:
    - fi-cfl-8109u:       [PASS][11] -> [DMESG-WARN][12] ([i915#165]) +1 similar issue
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11047/fi-cfl-8109u/igt@kms_force_connector_basic@force-connector-state.html
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/fi-cfl-8109u/igt@kms_force_connector_basic@force-connector-state.html

  * igt@kms_force_connector_basic@force-load-detect:
    - fi-icl-u2:          NOTRUN -> [SKIP][13] ([fdo#109285])
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/fi-icl-u2/igt@kms_force_connector_basic@force-load-detect.html

  * igt@kms_pipe_crc_basic@compare-crc-sanitycheck-pipe-b:
    - fi-cfl-8109u:       [PASS][14] -> [DMESG-WARN][15] ([i915#165] / [i915#295]) +13 similar issues
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11047/fi-cfl-8109u/igt@kms_pipe_crc_basic@compare-crc-sanitycheck-pipe-b.html
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/fi-cfl-8109u/igt@kms_pipe_crc_basic@compare-crc-sanitycheck-pipe-b.html

  * igt@kms_pipe_crc_basic@compare-crc-sanitycheck-pipe-d:
    - fi-kbl-soraka:      NOTRUN -> [SKIP][16] ([fdo#109271] / [i915#533])
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/fi-kbl-soraka/igt@kms_pipe_crc_basic@compare-crc-sanitycheck-pipe-d.html

  * igt@kms_psr@primary_page_flip:
    - fi-skl-6600u:       [PASS][17] -> [INCOMPLETE][18] ([i915#4547] / [i915#4838])
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11047/fi-skl-6600u/igt@kms_psr@primary_page_flip.html
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/fi-skl-6600u/igt@kms_psr@primary_page_flip.html

  * igt@prime_vgem@basic-userptr:
    - fi-icl-u2:          NOTRUN -> [SKIP][19] ([i915#3301])
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/fi-icl-u2/igt@prime_vgem@basic-userptr.html

  
#### Possible fixes ####

  * igt@kms_frontbuffer_tracking@basic:
    - fi-cml-u2:          [DMESG-WARN][20] ([i915#4269]) -> [PASS][21]
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11047/fi-cml-u2/igt@kms_frontbuffer_tracking@basic.html
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/fi-cml-u2/igt@kms_frontbuffer_tracking@basic.html

  
#### Warnings ####

  * igt@runner@aborted:
    - fi-skl-6600u:       [FAIL][22] ([i915#1436] / [i915#2722] / [i915#4312]) -> [FAIL][23] ([i915#2722] / [i915#4312])
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11047/fi-skl-6600u/igt@runner@aborted.html
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/fi-skl-6600u/igt@runner@aborted.html

  
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109278]: https://bugs.freedesktop.org/show_bug.cgi?id=109278
  [fdo#109285]: https://bugs.freedesktop.org/show_bug.cgi?id=109285
  [fdo#109315]: https://bugs.freedesktop.org/show_bug.cgi?id=109315
  [fdo#111827]: https://bugs.freedesktop.org/show_bug.cgi?id=111827
  [i915#1436]: https://gitlab.freedesktop.org/drm/intel/issues/1436
  [i915#165]: https://gitlab.freedesktop.org/drm/intel/issues/165
  [i915#1886]: https://gitlab.freedesktop.org/drm/intel/issues/1886
  [i915#2190]: https://gitlab.freedesktop.org/drm/intel/issues/2190
  [i915#2291]: https://gitlab.freedesktop.org/drm/intel/issues/2291
  [i915#2722]: https://gitlab.freedesktop.org/drm/intel/issues/2722
  [i915#295]: https://gitlab.freedesktop.org/drm/intel/issues/295
  [i915#3301]: https://gitlab.freedesktop.org/drm/intel/issues/3301
  [i915#4269]: https://gitlab.freedesktop.org/drm/intel/issues/4269
  [i915#4312]: https://gitlab.freedesktop.org/drm/intel/issues/4312
  [i915#4547]: https://gitlab.freedesktop.org/drm/intel/issues/4547
  [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
  [i915#4838]: https://gitlab.freedesktop.org/drm/intel/issues/4838
  [i915#533]: https://gitlab.freedesktop.org/drm/intel/issues/533


Build changes
-------------

  * Linux: CI_DRM_11047 -> Patchwork_21926

  CI-20190529: 20190529
  CI_DRM_11047: f50e5d7abd1873b3488081da88dc8412584280b9 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_6323: 9dbaa0d5be7a859cda9b7d54c20ba96a596f43bd @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
  Patchwork_21926: 06694ac45a0bb18eb79a6eb4e765d7767f7236fb @ git://anongit.freedesktop.org/gfx-ci/linux


== Linux commits ==

06694ac45a0b drm/i915: stop including i915_irq.h from i915_drv.h

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_21926/index.html

[-- Attachment #2: Type: text/html, Size: 9450 bytes --]

^ permalink raw reply

* Linux kernel 5.4.170 released
From: Linux Kernel Distribution System @ 2022-01-05 11:55 UTC (permalink / raw)
  To: linux-kernel-announce

Linux kernel version 5.4.170 is now available:

Full source:    https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.4.170.tar.xz
Patch:          https://cdn.kernel.org/pub/linux/kernel/v5.x/patch-5.4.170.xz
PGP Signature:  https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.4.170.tar.sign

You can view the summary of the changes at the following URL:
https://git.kernel.org/stable/ds/v5.4.170/v5.4.169


^ permalink raw reply

* [PATCH] media: st-delta: Fix PM disable depth imbalance in delta_probe
From: Miaoqian Lin @ 2022-01-05 11:55 UTC (permalink / raw)
  Cc: linmq006, Hugues Fruchet, Mauro Carvalho Chehab, Peter Griffin,
	linux-media, linux-kernel

The pm_runtime_enable will increase power disable depth.
If the probe fails, we should use pm_runtime_disable() to balance
pm_runtime_enable().

Fixes: f386509 ("[media] st-delta: STiH4xx multi-format video decoder v4l2 driver")
Signed-off-by: Miaoqian Lin <linmq006@gmail.com>
---
 drivers/media/platform/sti/delta/delta-v4l2.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/media/platform/sti/delta/delta-v4l2.c b/drivers/media/platform/sti/delta/delta-v4l2.c
index c887a31ebb54..dbcfd0484da4 100644
--- a/drivers/media/platform/sti/delta/delta-v4l2.c
+++ b/drivers/media/platform/sti/delta/delta-v4l2.c
@@ -1898,6 +1898,8 @@ static int delta_probe(struct platform_device *pdev)
 	destroy_workqueue(delta->work_queue);
 err_v4l2:
 	v4l2_device_unregister(&delta->v4l2_dev);
+disable_pm_runtime:
+	pm_runtime_disable(dev);
 err:
 	return ret;
 }
-- 
2.17.1


^ permalink raw reply related

* [Intel-wired-lan] [tnguy-net-queue:dev-queue] BUILD SUCCESS 7bc351fda4e2c4d42b682c90641afc15cc6f3167
From: kernel test robot @ 2022-01-05 11:55 UTC (permalink / raw)
  To: intel-wired-lan

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue.git dev-queue
branch HEAD: 7bc351fda4e2c4d42b682c90641afc15cc6f3167  ice: fix setting l4 port flag when adding filter

elapsed time: 741m

configs tested: 54
configs skipped: 3

The following configs have been built successfully.
More configs may be tested in the coming days.

gcc tested configs:
arm                                 defconfig
arm64                            allyesconfig
arm64                               defconfig
arm                              allyesconfig
arm                              allmodconfig
ia64                             allmodconfig
ia64                                defconfig
ia64                             allyesconfig
m68k                             allmodconfig
m68k                                defconfig
m68k                             allyesconfig
nds32                               defconfig
nios2                            allyesconfig
csky                                defconfig
alpha                               defconfig
alpha                            allyesconfig
xtensa                           allyesconfig
h8300                            allyesconfig
arc                                 defconfig
sh                               allmodconfig
parisc                              defconfig
s390                             allmodconfig
s390                                defconfig
parisc                           allyesconfig
s390                             allyesconfig
i386                             allyesconfig
sparc                               defconfig
i386                                defconfig
i386                   debian-10.3-kselftests
i386                              debian-10.3
sparc                            allyesconfig
nios2                               defconfig
arc                              allyesconfig
nds32                             allnoconfig
mips                             allyesconfig
mips                             allmodconfig
powerpc                          allyesconfig
powerpc                          allmodconfig
powerpc                           allnoconfig
riscv                    nommu_k210_defconfig
riscv                            allyesconfig
riscv                    nommu_virt_defconfig
riscv                             allnoconfig
riscv                               defconfig
riscv                          rv32_defconfig
riscv                            allmodconfig
um                             i386_defconfig
um                           x86_64_defconfig
x86_64                           allyesconfig
x86_64                              defconfig
x86_64                               rhel-8.3
x86_64                          rhel-8.3-func
x86_64                                  kexec
x86_64                    rhel-8.3-kselftests

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org

^ permalink raw reply

* Re: [PATCH v2 3/5] KVM: SVM: fix race between interrupt delivery and AVIC inhibition
From: Paolo Bonzini @ 2022-01-05 11:54 UTC (permalink / raw)
  To: Maxim Levitsky, Sean Christopherson
  Cc: kvm, Jim Mattson, Thomas Gleixner, Joerg Roedel,
	maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT), Vitaly Kuznetsov,
	Borislav Petkov, linux-kernel, Dave Hansen, H. Peter Anvin,
	Wanpeng Li, Ingo Molnar
In-Reply-To: <628ac6d9b16c6b3a2573f717df0d2417df7caddb.camel@redhat.com>

On 1/5/22 12:03, Maxim Levitsky wrote:
>> Hmm, my preference would be to keep the "return -1" even though apicv_active must
>> be rechecked.  That would help highlight that returning "failure" after this point
>> is not an option as it would result in kvm_lapic_set_irr() being called twice.
> I don't mind either - this will fix the tracepoint I recently added to report the
> number of interrupts that were delivered by AVIC/APICv - with this patch,
> all of them count as such.

Perhaps we can move the tracepoints in the delivery functions.  This 
also makes them more precise in the rare case where apicv_active changes 
in the middle of the function.

Paolo


^ permalink raw reply

* Re: [PATCH v5 7/7] usb: gadget: uvc: add format/frame handling code
From: Michael Grzeschik @ 2022-01-05 11:54 UTC (permalink / raw)
  To: linux-usb; +Cc: balbi, paul.elder, laurent.pinchart, kernel
In-Reply-To: <20211212232719.GA3912@pengutronix.de>

[-- Attachment #1: Type: text/plain, Size: 4085 bytes --]

Since this series did not get any feedback and the mentioned code needs
to be fixed I will just start the new year with a fresh v6 series.

On Mon, Dec 13, 2021 at 12:27:19AM +0100, Michael Grzeschik wrote:
>Ping
>
>On Thu, Dec 09, 2021 at 09:43:22AM +0100, Michael Grzeschik wrote:
>>The Hostside format selection is currently only done in userspace, as
>>the events for SET_CUR and GET_CUR are allways moved to the application
>>layer. Since the v4l2 device parses the configfs data, the format
>>negotiation can be done in the kernel. This patch adds the functions to
>>set the current configuration while continuing to forward all unknown
>>events to the userspace level.
>>
>>Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
>>
>>---
>>v1 -> v2:
>>  - fixed the commit message
>>  - changed pr_debug to pr_err in events_process_data
>>  - aligned many indentations
>>  - simplified uvc_events_process_data
>>  - fixed uvc_fill_streaming_control calls in uvcg_video_init
>>  - added setup_subcribed to decide if userspace takes over on EOPNOTSUPP
>>  - added data_subscribed to decide if userspace takes over on EOPNOTSUPP
>>  - removed duplicate send_response
>>  - wrting fmt and frm in full
>>v2 -> v3:
>>  - added find_format_index to set the right probe
>>v3 -> v4:
>>  - add function find_ival_index and use for cur_ival
>>  - fix swapped frame and format in uvc_events_process_data on uvc_fill_streaming_control
>>  - set proper resp.length on ep0 complete
>>  - dropped setting cur_probe on set_format since function was removed
>>  - added locking around getting correspondent cur_{frame,format,ival}
>>v4 -> v5:
>>  - fixed sparse errors reported by kernel test robot
>>
>>drivers/usb/gadget/function/f_uvc.c     | 234 +++++++++++++++++++++++-
>>drivers/usb/gadget/function/uvc.h       |  19 ++
>>drivers/usb/gadget/function/uvc_v4l2.c  |  66 ++++++-
>>drivers/usb/gadget/function/uvc_video.c |  12 +-
>>4 files changed, 324 insertions(+), 7 deletions(-)
>>
>
>[snip]
>
>>static void
>>uvc_function_ep0_complete(struct usb_ep *ep, struct usb_request *req)
>>{
>>	struct uvc_device *uvc = req->context;
>>	struct v4l2_event v4l2_event;
>>	struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
>>+	struct uvc_request_data resp;
>>+	int ret;
>>
>>	if (uvc->event_setup_out) {
>>		uvc->event_setup_out = 0;
>>
>>+		memset(&resp, 0, sizeof(resp));
>>+		resp.length = -EL2HLT;
>>+
>>+		ret = uvc_events_process_data(uvc, req);
>>+		/* If we have no error on process */
>>+		if (!ret) {
>>+			resp.length = req->length;
>>+			uvc_send_response(uvc, &resp);
>>+			return;
>
>I just found out, that depending on the host implementation, sending a
>response persisting probe or commit is no valid. I will just keep it
>aligned with the uvc-gadget implementation and fix it not to send any
>response in that both cases.
>
>>+		}
>>+
>>+		/* If we have a real error on process */
>>+		if (ret != -EOPNOTSUPP)
>>+			return;
>>+
>>+		/* If we have -EOPNOTSUPP */
>>+		if (!uvc->data_subscribed)
>>+			return;
>>+
>>+		/* If we have data subscribed */
>>		memset(&v4l2_event, 0, sizeof(v4l2_event));
>>		v4l2_event.type = UVC_EVENT_DATA;
>>		uvc_event->data.length = req->actual;
>
>Beside that, I hope somebody would help reviewing this, before I will
>send v6.
>
>Laurant? Do you have any thoughts on that whole stack?
>
>Thanks,
>Michael
>
>-- 
>Pengutronix e.K.                           |                             |
>Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
>31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
>Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* Re: [PATCH 1/2] drm/bridge: anx7625: add HDCP support
From: Xin Ji @ 2022-01-05 11:53 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: drinkcat, pihsun, jonas, airlied, robert.foss, dri-devel,
	narmstrong, linux-kernel, jernej.skrabec, bliang, tzungbi,
	Laurent.pinchart, hsinyi, sam, qwen, dan.carpenter, maxime
In-Reply-To: <fa637b7a-c85b-6287-87ac-cf518b59d027@intel.com>

Hi Andrzej Hajda, thanks for the comment, I'll change it in next serial
patches.

Thanks,
Xin

On Wed, Jan 05, 2022 at 10:31:15AM +0100, Andrzej Hajda wrote:
> Hi Xin,
> 
> On 09.11.2021 03:42, Xin Ji wrote:
> > This patch provides HDCP setting interface for userspace to dynamic
> > enable/disable HDCP function.
> > 
> > Signed-off-by: Xin Ji <xji@analogixsemi.com>
> > ---
> >   drivers/gpu/drm/bridge/analogix/anx7625.c | 368 +++++++++++++++++++++-
> >   drivers/gpu/drm/bridge/analogix/anx7625.h |  69 +++-
> >   2 files changed, 425 insertions(+), 12 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c
> > index 001fb39d9919..6d93026c2999 100644
> > --- a/drivers/gpu/drm/bridge/analogix/anx7625.c
> > +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
> > @@ -26,6 +26,7 @@
> >   #include <drm/drm_crtc_helper.h>
> >   #include <drm/drm_dp_helper.h>
> >   #include <drm/drm_edid.h>
> > +#include <drm/drm_hdcp.h>
> >   #include <drm/drm_mipi_dsi.h>
> >   #include <drm/drm_of.h>
> >   #include <drm/drm_panel.h>
> > @@ -213,6 +214,60 @@ static int wait_aux_op_finish(struct anx7625_data *ctx)
> >   	return 0;
> >   }
> > +static int anx7625_aux_dpcd_read(struct anx7625_data *ctx,
> > +				 u8 addrh, u8 addrm, u8 addrl,
> 
> 
> Wouldn't be more convenient to use single u32 address (in fact 24 bits of
> it)?
OK, I'll use u32.
> 
> 
> > +				 u8 len, u8 *buf)
> > +{
> > +	struct device *dev = &ctx->client->dev;
> > +	int ret;
> > +	u8 cmd;
> > +
> > +	if (len > MAX_DPCD_BUFFER_SIZE) {
> > +		DRM_DEV_ERROR(dev, "exceed aux buffer len.\n");
> 
> 
> Here and below (note from inline docs)m regarding DRM_DEV_ERROR and friends:
> 
>  NOTE: this is deprecated in favor of drm_err() or dev_err()
OK. I'll use drm_err()
> 
> 
> > +		return -EINVAL;
> > +	}
> > +
> > +	cmd = ((len - 1) << 4) | 0x09;
> Here and below you can replace magic numbers by macros.
OK
> > +
> > +	/* Set command and length */
> > +	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				AP_AUX_COMMAND, cmd);
> > +
> > +	/* Set aux access address */
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 AP_AUX_ADDR_7_0, addrl);
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 AP_AUX_ADDR_15_8, addrm);
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 AP_AUX_ADDR_19_16, addrh);
> > +
> > +	/* Enable aux access */
> > +	ret |= anx7625_write_or(ctx, ctx->i2c.rx_p0_client,
> > +				AP_AUX_CTRL_STATUS, AP_AUX_CTRL_OP_EN);
> > +
> > +	if (ret < 0) {
> > +		DRM_DEV_ERROR(dev, "cannot access aux related register.\n");
> > +		return -EIO;
> > +	}
> > +
> > +	usleep_range(2000, 2100);
> > +
> > +	ret = wait_aux_op_finish(ctx);
> > +	if (ret) {
> > +		DRM_DEV_ERROR(dev, "aux IO error: wait aux op finish.\n");
> > +		return ret;
> > +	}
> > +
> > +	ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client,
> > +				     AP_AUX_BUFF_START, len, buf);
> > +	if (ret < 0) {
> > +		DRM_DEV_ERROR(dev, "read dpcd register failed\n");
> > +		return -EIO;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> >   static int anx7625_video_mute_control(struct anx7625_data *ctx,
> >   				      u8 status)
> >   {
> > @@ -669,6 +724,160 @@ static int anx7625_dpi_config(struct anx7625_data *ctx)
> >   	return ret;
> >   }
> > +static int anx7625_read_flash_status(struct anx7625_data *ctx)
> > +{
> > +	return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, R_RAM_CTRL);
> > +}
> > +
> > +static int anx7625_hdcp_key_probe(struct anx7625_data *ctx)
> > +{
> > +	int ret, val;
> > +	struct device *dev = &ctx->client->dev;
> > +	u8 ident[32];
> > +
> > +	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				FLASH_ADDR_HIGH, 0x91);
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 FLASH_ADDR_LOW, 0xA0);
> > +	if (ret < 0) {
> > +		DRM_DEV_ERROR(dev, "IO error : set key flash address.\n");
> > +		return ret;
> > +	}
> > +
> > +	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				FLASH_LEN_HIGH, (FLASH_BUF_LEN - 1) >> 8);
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 FLASH_LEN_LOW, (FLASH_BUF_LEN - 1) & 0xFF);
> > +	if (ret < 0) {
> > +		DRM_DEV_ERROR(dev, "IO error : set key flash len.\n");
> > +		return ret;
> > +	}
> > +
> > +	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				R_FLASH_RW_CTRL, FLASH_READ);
> > +	ret |= readx_poll_timeout(anx7625_read_flash_status,
> > +				  ctx, val,
> > +				  ((val & FLASH_DONE) || (val < 0)),
> > +				  2000,
> > +				  2000 * 150);
> > +	if (ret) {
> > +		DRM_DEV_ERROR(dev, "flash read access fail!\n");
> > +		return -EIO;
> > +	}
> > +
> > +	ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client,
> > +				     FLASH_BUF_BASE_ADDR,
> > +				     FLASH_BUF_LEN, ident);
> > +	if (ret < 0) {
> > +		DRM_DEV_ERROR(dev, "read flash data fail!\n");
> > +		return -EIO;
> > +	}
> > +
> > +	if (ident[29] == 0xFF && ident[30] == 0xFF && ident[31] == 0xFF)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> > +static int anx7625_hdcp_key_load(struct anx7625_data *ctx)
> > +{
> > +	int ret;
> > +	struct device *dev = &ctx->client->dev;
> > +
> > +	/* Select HDCP 1.4 KEY */
> > +	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				R_BOOT_RETRY, 0x12);
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 FLASH_ADDR_HIGH, HDCP14KEY_START_ADDR >> 8);
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 FLASH_ADDR_LOW, HDCP14KEY_START_ADDR & 0xFF);
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 R_RAM_LEN_H, HDCP14KEY_SIZE >> 12);
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 R_RAM_LEN_L, HDCP14KEY_SIZE >> 4);
> > +
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 R_RAM_ADDR_H, 0);
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 R_RAM_ADDR_L, 0);
> > +	/* Enable HDCP 1.4 KEY load */
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 R_RAM_CTRL, DECRYPT_EN | LOAD_START);
> > +	DRM_DEV_DEBUG_DRIVER(dev, "load HDCP 1.4 key done\n");
> > +	return ret;
> > +}
> > +
> > +static int anx7625_hdcp_config(struct anx7625_data *ctx, bool on)
> > +{
> > +	u8 bcap;
> > +	int ret;
> > +	struct device *dev = &ctx->client->dev;
> > +
> > +	if (!on) {
> > +		DRM_DEV_DEBUG_DRIVER(dev, "disable HDCP 1.4\n");
> > +
> > +		/* Disable HDCP */
> > +		ret = anx7625_write_and(ctx, ctx->i2c.rx_p1_client, 0xee, 0x9f);
> > +		/* Try auth flag */
> > +		ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xec, 0x10);
> > +		/* Interrupt for DRM */
> > +		ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xff, 0x01);
> > +		if (ret < 0)
> > +			DRM_DEV_ERROR(dev, "fail to disable HDCP\n");
> > +
> > +		return anx7625_write_and(ctx, ctx->i2c.tx_p0_client,
> > +					 TX_HDCP_CTRL0, ~HARD_AUTH_EN & 0xFF);
> > +	}
> 
> 
> Code path for on==true, and on==false have nothing common.
> 
> This is definitely shows that anx7625_hdcp_config should be split to
> anx7625_hdcp_enable and anx7625_hdcp_disable (or on/off, whatever).
> 
OK, I'll split to two function.
> 
> > +
> > +	ret = anx7625_hdcp_key_probe(ctx);
> > +	if (ret) {
> > +		DRM_DEV_DEBUG_DRIVER(dev, "no key found, not to do hdcp\n");
> > +		return ret;
> > +	}
> > +
> > +	anx7625_aux_dpcd_read(ctx, 0x06, 0x80, 0x28, 1, &bcap);
> > +	if (!(bcap & 0x01)) {
> > +		DRM_WARN("downstream not support HDCP 1.4, cap(%x).\n", bcap);
> > +		return 0;
> > +	}
> > +
> > +	DRM_DEV_DEBUG_DRIVER(dev, "enable HDCP 1.4\n");
> > +
> > +	/* First clear HDCP state */
> > +	ret = anx7625_reg_write(ctx, ctx->i2c.tx_p0_client,
> > +				TX_HDCP_CTRL0,
> > +				KSVLIST_VLD | BKSV_SRM_PASS | RE_AUTHEN);
> > +	usleep_range(1000, 1100);
> > +	/* Second clear HDCP state */
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p0_client,
> > +				 TX_HDCP_CTRL0,
> > +				 KSVLIST_VLD | BKSV_SRM_PASS | RE_AUTHEN);
> > +
> > +	/* Set time for waiting KSVR */
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p0_client,
> > +				 SP_TX_WAIT_KSVR_TIME, 0xc8);
> > +	/* Set time for waiting R0 */
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p0_client,
> > +				 SP_TX_WAIT_R0_TIME, 0xb0);
> > +	ret |= anx7625_hdcp_key_load(ctx);
> > +	if (ret) {
> > +		DRM_WARN("prepare HDCP key failed.\n");
> > +		return ret;
> > +	}
> > +
> > +	ret = anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xee, 0x20);
> > +
> > +	/* Try auth flag */
> > +	ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xec, 0x10);
> > +	/* Interrupt for DRM */
> > +	ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xff, 0x01);
> > +	if (ret < 0)
> > +		DRM_DEV_ERROR(dev, "fail to enable HDCP\n");
> > +
> > +	return anx7625_write_or(ctx, ctx->i2c.tx_p0_client,
> > +				TX_HDCP_CTRL0, HARD_AUTH_EN);
> > +}
> > +
> >   static void anx7625_dp_start(struct anx7625_data *ctx)
> >   {
> >   	int ret;
> > @@ -679,6 +888,9 @@ static void anx7625_dp_start(struct anx7625_data *ctx)
> >   		return;
> >   	}
> > +	/* Disable HDCP */
> > +	anx7625_write_and(ctx, ctx->i2c.rx_p1_client, 0xee, 0x9f);
> > +
> >   	if (ctx->pdata.is_dpi)
> >   		ret = anx7625_dpi_config(ctx);
> >   	else
> > @@ -686,6 +898,10 @@ static void anx7625_dp_start(struct anx7625_data *ctx)
> >   	if (ret < 0)
> >   		DRM_DEV_ERROR(dev, "MIPI phy setup error.\n");
> > +
> > +	ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
> > +
> > +	ctx->dp_en = 1;
> >   }
> >   static void anx7625_dp_stop(struct anx7625_data *ctx)
> > @@ -705,6 +921,10 @@ static void anx7625_dp_stop(struct anx7625_data *ctx)
> >   	ret |= anx7625_video_mute_control(ctx, 1);
> >   	if (ret < 0)
> >   		DRM_DEV_ERROR(dev, "IO error : mute video fail\n");
> > +
> > +	ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
> > +
> > +	ctx->dp_en = 0;
> >   }
> >   static int sp_tx_rst_aux(struct anx7625_data *ctx)
> > @@ -859,7 +1079,7 @@ static int sp_tx_edid_read(struct anx7625_data *ctx,
> >   				AP_AUX_ADDR_7_0, 0x50);
> >   	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> >   				 AP_AUX_ADDR_15_8, 0);
> > -	ret |= anx7625_write_and(ctx, ctx->i2c.rx_p0_client,
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> >   				 AP_AUX_ADDR_19_16, 0xf0);
> 
> 
> This is bugfix? How it is related to the rest of patchset.
OK, The old code is OK, I'll revert this change.
> 
> 
> Regards
> 
> Andrzej
> 
> 
> >   	if (ret < 0) {
> >   		DRM_DEV_ERROR(dev, "access aux channel IO error.\n");
> > @@ -1688,6 +1908,83 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx)
> >   	return 0;
> >   }
> > +void hdcp_check_work_func(struct work_struct *work)
> > +{
> > +	u8 status;
> > +	struct delayed_work *dwork;
> > +	struct anx7625_data *ctx;
> > +	struct device *dev;
> > +	struct drm_device *drm_dev;
> > +
> > +	dwork = to_delayed_work(work);
> > +	ctx = container_of(dwork, struct anx7625_data, hdcp_work);
> > +	dev = &ctx->client->dev;
> > +
> > +	if (!ctx->connector) {
> > +		DRM_ERROR("HDCP connector is null!");
> > +		return;
> > +	}
> > +
> > +	drm_dev = ctx->connector->dev;
> > +	drm_modeset_lock(&drm_dev->mode_config.connection_mutex, NULL);
> > +	mutex_lock(&ctx->hdcp_wq_lock);
> > +
> > +	status = anx7625_reg_read(ctx, ctx->i2c.tx_p0_client, 0);
> > +	DRM_DEV_DEBUG_DRIVER(dev, "sink HDCP status check: %.02x\n", status);
> > +	if (status & BIT(1)) {
> > +		ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_ENABLED;
> > +		drm_hdcp_update_content_protection(ctx->connector,
> > +						   ctx->hdcp_cp);
> > +		DRM_DEV_DEBUG_DRIVER(dev, "update CP to ENABLE\n");
> > +	}
> > +
> > +	mutex_unlock(&ctx->hdcp_wq_lock);
> > +	drm_modeset_unlock(&drm_dev->mode_config.connection_mutex);
> > +}
> > +
> > +static int anx7625_connector_atomic_check(struct anx7625_data *ctx,
> > +					  struct drm_connector_state *state)
> > +{
> > +	struct device *dev = &ctx->client->dev;
> > +	int cp;
> > +
> > +	DRM_DEV_DEBUG_DRIVER(dev, "hdcp state check\n");
> > +	cp = state->content_protection;
> > +
> > +	if (cp == ctx->hdcp_cp)
> > +		return 0;
> > +
> > +	if (cp == DRM_MODE_CONTENT_PROTECTION_DESIRED) {
> > +		if (ctx->dp_en) {
> > +			DRM_DEV_DEBUG_DRIVER(dev, "enable HDCP\n");
> > +			anx7625_hdcp_config(ctx, true);
> > +
> > +			queue_delayed_work(ctx->hdcp_workqueue,
> > +					   &ctx->hdcp_work,
> > +					   msecs_to_jiffies(2000));
> > +		}
> > +	}
> > +
> > +	if (cp == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
> > +		if (ctx->hdcp_cp != DRM_MODE_CONTENT_PROTECTION_ENABLED) {
> > +			DRM_ERROR("current CP is not ENABLED\n");
> > +			return -EINVAL;
> > +		}
> > +		anx7625_hdcp_config(ctx, false);
> > +		ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
> > +		drm_hdcp_update_content_protection(ctx->connector,
> > +						   ctx->hdcp_cp);
> > +		DRM_DEV_DEBUG_DRIVER(dev, "update CP to UNDESIRE\n");
> > +	}
> > +
> > +	if (cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
> > +		DRM_ERROR("Userspace illegal set to PROTECTION ENABLE\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> >   static int anx7625_bridge_attach(struct drm_bridge *bridge,
> >   				 enum drm_bridge_attach_flags flags)
> >   {
> > @@ -1902,25 +2199,58 @@ static bool anx7625_bridge_mode_fixup(struct drm_bridge *bridge,
> >   	return true;
> >   }
> > -static void anx7625_bridge_enable(struct drm_bridge *bridge)
> > +static int anx7625_bridge_atomic_check(struct drm_bridge *bridge,
> > +				       struct drm_bridge_state *bridge_state,
> > +				       struct drm_crtc_state *crtc_state,
> > +				       struct drm_connector_state *conn_state)
> >   {
> >   	struct anx7625_data *ctx = bridge_to_anx7625(bridge);
> >   	struct device *dev = &ctx->client->dev;
> > -	DRM_DEV_DEBUG_DRIVER(dev, "drm enable\n");
> > +	DRM_DEV_DEBUG_DRIVER(dev, "drm bridge atomic check\n");
> > +	anx7625_bridge_mode_fixup(bridge, &crtc_state->mode,
> > +				  &crtc_state->adjusted_mode);
> > +
> > +	return anx7625_connector_atomic_check(ctx, conn_state);
> > +}
> > +
> > +static void anx7625_bridge_atomic_enable(struct drm_bridge *bridge,
> > +					 struct drm_bridge_state *state)
> > +{
> > +	struct anx7625_data *ctx = bridge_to_anx7625(bridge);
> > +	struct device *dev = &ctx->client->dev;
> > +	struct drm_connector *connector;
> > +
> > +	DRM_DEV_DEBUG_DRIVER(dev, "drm atomic enable\n");
> > +
> > +	if (!bridge->encoder) {
> > +		DRM_DEV_ERROR(dev, "Parent encoder object not found");
> > +		return;
> > +	}
> > +
> > +	connector = drm_atomic_get_new_connector_for_encoder(state->base.state,
> > +							     bridge->encoder);
> > +	if (!connector)
> > +		return;
> > +
> > +	ctx->connector = connector;
> > +
> > +	DRM_DEV_DEBUG_DRIVER(dev, "attached content protection.\n");
> >   	pm_runtime_get_sync(dev);
> >   	anx7625_dp_start(ctx);
> >   }
> > -static void anx7625_bridge_disable(struct drm_bridge *bridge)
> > +static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge,
> > +					  struct drm_bridge_state *old)
> >   {
> >   	struct anx7625_data *ctx = bridge_to_anx7625(bridge);
> >   	struct device *dev = &ctx->client->dev;
> >   	DRM_DEV_DEBUG_DRIVER(dev, "drm disable\n");
> > +	ctx->connector = NULL;
> >   	anx7625_dp_stop(ctx);
> >   	pm_runtime_put_sync(dev);
> > @@ -1950,11 +2280,14 @@ static struct edid *anx7625_bridge_get_edid(struct drm_bridge *bridge,
> >   static const struct drm_bridge_funcs anx7625_bridge_funcs = {
> >   	.attach = anx7625_bridge_attach,
> > -	.disable = anx7625_bridge_disable,
> >   	.mode_valid = anx7625_bridge_mode_valid,
> >   	.mode_set = anx7625_bridge_mode_set,
> > -	.mode_fixup = anx7625_bridge_mode_fixup,
> > -	.enable = anx7625_bridge_enable,
> > +	.atomic_check = anx7625_bridge_atomic_check,
> > +	.atomic_enable = anx7625_bridge_atomic_enable,
> > +	.atomic_disable = anx7625_bridge_atomic_disable,
> > +	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> > +	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
> > +	.atomic_reset = drm_atomic_helper_bridge_reset,
> >   	.detect = anx7625_bridge_detect,
> >   	.get_edid = anx7625_bridge_get_edid,
> >   };
> > @@ -2134,6 +2467,15 @@ static int anx7625_i2c_probe(struct i2c_client *client,
> >   	anx7625_init_gpio(platform);
> >   	mutex_init(&platform->lock);
> > +	mutex_init(&platform->hdcp_wq_lock);
> > +
> > +	INIT_DELAYED_WORK(&platform->hdcp_work, hdcp_check_work_func);
> > +	platform->hdcp_workqueue = create_workqueue("hdcp workqueue");
> > +	if (!platform->hdcp_workqueue) {
> > +		DRM_DEV_ERROR(dev, "fail to create work queue\n");
> > +		ret = -ENOMEM;
> > +		goto free_platform;
> > +	}
> >   	platform->pdata.intp_irq = client->irq;
> >   	if (platform->pdata.intp_irq) {
> > @@ -2143,7 +2485,7 @@ static int anx7625_i2c_probe(struct i2c_client *client,
> >   		if (!platform->workqueue) {
> >   			DRM_DEV_ERROR(dev, "fail to create work queue\n");
> >   			ret = -ENOMEM;
> > -			goto free_platform;
> > +			goto free_hdcp_wq;
> >   		}
> >   		ret = devm_request_threaded_irq(dev, platform->pdata.intp_irq,
> > @@ -2213,6 +2555,10 @@ static int anx7625_i2c_probe(struct i2c_client *client,
> >   	if (platform->workqueue)
> >   		destroy_workqueue(platform->workqueue);
> > +free_hdcp_wq:
> > +	if (platform->hdcp_workqueue)
> > +		destroy_workqueue(platform->hdcp_workqueue);
> > +
> >   free_platform:
> >   	kfree(platform);
> > @@ -2228,6 +2574,12 @@ static int anx7625_i2c_remove(struct i2c_client *client)
> >   	if (platform->pdata.intp_irq)
> >   		destroy_workqueue(platform->workqueue);
> > +	if (platform->hdcp_workqueue) {
> > +		cancel_delayed_work(&platform->hdcp_work);
> > +		flush_workqueue(platform->workqueue);
> > +		destroy_workqueue(platform->workqueue);
> > +	}
> > +
> >   	if (!platform->pdata.low_power_mode)
> >   		pm_runtime_put_sync_suspend(&client->dev);
> > diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h
> > index 3d79b6fb13c8..89b1b347a463 100644
> > --- a/drivers/gpu/drm/bridge/analogix/anx7625.h
> > +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h
> > @@ -59,10 +59,23 @@
> >   /***************************************************************/
> >   /* Register definition of device address 0x70 */
> > -#define  I2C_ADDR_70_DPTX              0x70
> > -
> > -#define SP_TX_LINK_BW_SET_REG 0xA0
> > -#define SP_TX_LANE_COUNT_SET_REG 0xA1
> > +#define TX_HDCP_CTRL0			0x01
> > +#define STORE_AN			BIT(7)
> > +#define RX_REPEATER			BIT(6)
> > +#define RE_AUTHEN			BIT(5)
> > +#define SW_AUTH_OK			BIT(4)
> > +#define HARD_AUTH_EN			BIT(3)
> > +#define ENC_EN				BIT(2)
> > +#define BKSV_SRM_PASS			BIT(1)
> > +#define KSVLIST_VLD			BIT(0)
> > +
> > +#define SP_TX_WAIT_R0_TIME		0x40
> > +#define SP_TX_WAIT_KSVR_TIME		0x42
> > +#define SP_TX_SYS_CTRL1_REG		0x80
> > +#define HDCP2TX_FW_EN			BIT(4)
> > +
> > +#define SP_TX_LINK_BW_SET_REG		0xA0
> > +#define SP_TX_LANE_COUNT_SET_REG	0xA1
> >   #define M_VID_0 0xC0
> >   #define M_VID_1 0xC1
> > @@ -71,6 +84,12 @@
> >   #define N_VID_1 0xC4
> >   #define N_VID_2 0xC5
> > +#define KEY_START_ADDR			0x9000
> > +#define KEY_RESERVED			416
> > +
> > +#define HDCP14KEY_START_ADDR		(KEY_START_ADDR + KEY_RESERVED)
> > +#define HDCP14KEY_SIZE			624
> > +
> >   /***************************************************************/
> >   /* Register definition of device address 0x72 */
> >   #define AUX_RST	0x04
> > @@ -155,9 +174,43 @@
> >   #define  I2C_ADDR_7E_FLASH_CONTROLLER  0x7E
> > +#define R_BOOT_RETRY		0x00
> > +#define R_RAM_ADDR_H		0x01
> > +#define R_RAM_ADDR_L		0x02
> > +#define R_RAM_LEN_H		0x03
> > +#define R_RAM_LEN_L		0x04
> >   #define FLASH_LOAD_STA          0x05
> >   #define FLASH_LOAD_STA_CHK	BIT(7)
> > +#define R_RAM_CTRL              0x05
> > +/* bit positions */
> > +#define FLASH_DONE              BIT(7)
> > +#define BOOT_LOAD_DONE          BIT(6)
> > +#define CRC_OK                  BIT(5)
> > +#define LOAD_DONE               BIT(4)
> > +#define O_RW_DONE               BIT(3)
> > +#define FUSE_BUSY               BIT(2)
> > +#define DECRYPT_EN              BIT(1)
> > +#define LOAD_START              BIT(0)
> > +
> > +#define FLASH_ADDR_HIGH         0x0F
> > +#define FLASH_ADDR_LOW          0x10
> > +#define FLASH_LEN_HIGH          0x31
> > +#define FLASH_LEN_LOW           0x32
> > +#define R_FLASH_RW_CTRL         0x33
> > +/* bit positions */
> > +#define READ_DELAY_SELECT       BIT(7)
> > +#define GENERAL_INSTRUCTION_EN  BIT(6)
> > +#define FLASH_ERASE_EN          BIT(5)
> > +#define RDID_READ_EN            BIT(4)
> > +#define REMS_READ_EN            BIT(3)
> > +#define WRITE_STATUS_EN         BIT(2)
> > +#define FLASH_READ              BIT(1)
> > +#define FLASH_WRITE             BIT(0)
> > +
> > +#define FLASH_BUF_BASE_ADDR     0x60
> > +#define FLASH_BUF_LEN           0x20
> > +
> >   #define  XTAL_FRQ_SEL    0x3F
> >   /* bit field positions */
> >   #define  XTAL_FRQ_SEL_POS    5
> > @@ -392,21 +445,29 @@ struct anx7625_data {
> >   	struct platform_device *audio_pdev;
> >   	int hpd_status;
> >   	int hpd_high_cnt;
> > +	int dp_en;
> > +	int hdcp_cp;
> >   	/* Lock for work queue */
> >   	struct mutex lock;
> >   	struct i2c_client *client;
> >   	struct anx7625_i2c_client i2c;
> >   	struct i2c_client *last_client;
> > +	struct timer_list hdcp_timer;
> >   	struct s_edid_data slimport_edid_p;
> >   	struct device *codec_dev;
> >   	hdmi_codec_plugged_cb plugged_cb;
> >   	struct work_struct work;
> >   	struct workqueue_struct *workqueue;
> > +	struct delayed_work hdcp_work;
> > +	struct workqueue_struct *hdcp_workqueue;
> > +	/* Lock for hdcp work queue */
> > +	struct mutex hdcp_wq_lock;
> >   	char edid_block;
> >   	struct display_timing dt;
> >   	u8 display_timing_valid;
> >   	struct drm_bridge bridge;
> >   	u8 bridge_attached;
> > +	struct drm_connector *connector;
> >   	struct mipi_dsi_device *dsi;
> >   };

^ permalink raw reply

* Re: [PATCH 1/2] drm/bridge: anx7625: add HDCP support
From: Xin Ji @ 2022-01-05 11:53 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: narmstrong, dan.carpenter, robert.foss, Laurent.pinchart, jonas,
	jernej.skrabec, airlied, daniel, sam, pihsun, tzungbi, maxime,
	drinkcat, hsinyi, dri-devel, linux-kernel, bliang, qwen
In-Reply-To: <fa637b7a-c85b-6287-87ac-cf518b59d027@intel.com>

Hi Andrzej Hajda, thanks for the comment, I'll change it in next serial
patches.

Thanks,
Xin

On Wed, Jan 05, 2022 at 10:31:15AM +0100, Andrzej Hajda wrote:
> Hi Xin,
> 
> On 09.11.2021 03:42, Xin Ji wrote:
> > This patch provides HDCP setting interface for userspace to dynamic
> > enable/disable HDCP function.
> > 
> > Signed-off-by: Xin Ji <xji@analogixsemi.com>
> > ---
> >   drivers/gpu/drm/bridge/analogix/anx7625.c | 368 +++++++++++++++++++++-
> >   drivers/gpu/drm/bridge/analogix/anx7625.h |  69 +++-
> >   2 files changed, 425 insertions(+), 12 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c
> > index 001fb39d9919..6d93026c2999 100644
> > --- a/drivers/gpu/drm/bridge/analogix/anx7625.c
> > +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
> > @@ -26,6 +26,7 @@
> >   #include <drm/drm_crtc_helper.h>
> >   #include <drm/drm_dp_helper.h>
> >   #include <drm/drm_edid.h>
> > +#include <drm/drm_hdcp.h>
> >   #include <drm/drm_mipi_dsi.h>
> >   #include <drm/drm_of.h>
> >   #include <drm/drm_panel.h>
> > @@ -213,6 +214,60 @@ static int wait_aux_op_finish(struct anx7625_data *ctx)
> >   	return 0;
> >   }
> > +static int anx7625_aux_dpcd_read(struct anx7625_data *ctx,
> > +				 u8 addrh, u8 addrm, u8 addrl,
> 
> 
> Wouldn't be more convenient to use single u32 address (in fact 24 bits of
> it)?
OK, I'll use u32.
> 
> 
> > +				 u8 len, u8 *buf)
> > +{
> > +	struct device *dev = &ctx->client->dev;
> > +	int ret;
> > +	u8 cmd;
> > +
> > +	if (len > MAX_DPCD_BUFFER_SIZE) {
> > +		DRM_DEV_ERROR(dev, "exceed aux buffer len.\n");
> 
> 
> Here and below (note from inline docs)m regarding DRM_DEV_ERROR and friends:
> 
>  NOTE: this is deprecated in favor of drm_err() or dev_err()
OK. I'll use drm_err()
> 
> 
> > +		return -EINVAL;
> > +	}
> > +
> > +	cmd = ((len - 1) << 4) | 0x09;
> Here and below you can replace magic numbers by macros.
OK
> > +
> > +	/* Set command and length */
> > +	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				AP_AUX_COMMAND, cmd);
> > +
> > +	/* Set aux access address */
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 AP_AUX_ADDR_7_0, addrl);
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 AP_AUX_ADDR_15_8, addrm);
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 AP_AUX_ADDR_19_16, addrh);
> > +
> > +	/* Enable aux access */
> > +	ret |= anx7625_write_or(ctx, ctx->i2c.rx_p0_client,
> > +				AP_AUX_CTRL_STATUS, AP_AUX_CTRL_OP_EN);
> > +
> > +	if (ret < 0) {
> > +		DRM_DEV_ERROR(dev, "cannot access aux related register.\n");
> > +		return -EIO;
> > +	}
> > +
> > +	usleep_range(2000, 2100);
> > +
> > +	ret = wait_aux_op_finish(ctx);
> > +	if (ret) {
> > +		DRM_DEV_ERROR(dev, "aux IO error: wait aux op finish.\n");
> > +		return ret;
> > +	}
> > +
> > +	ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client,
> > +				     AP_AUX_BUFF_START, len, buf);
> > +	if (ret < 0) {
> > +		DRM_DEV_ERROR(dev, "read dpcd register failed\n");
> > +		return -EIO;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> >   static int anx7625_video_mute_control(struct anx7625_data *ctx,
> >   				      u8 status)
> >   {
> > @@ -669,6 +724,160 @@ static int anx7625_dpi_config(struct anx7625_data *ctx)
> >   	return ret;
> >   }
> > +static int anx7625_read_flash_status(struct anx7625_data *ctx)
> > +{
> > +	return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, R_RAM_CTRL);
> > +}
> > +
> > +static int anx7625_hdcp_key_probe(struct anx7625_data *ctx)
> > +{
> > +	int ret, val;
> > +	struct device *dev = &ctx->client->dev;
> > +	u8 ident[32];
> > +
> > +	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				FLASH_ADDR_HIGH, 0x91);
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 FLASH_ADDR_LOW, 0xA0);
> > +	if (ret < 0) {
> > +		DRM_DEV_ERROR(dev, "IO error : set key flash address.\n");
> > +		return ret;
> > +	}
> > +
> > +	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				FLASH_LEN_HIGH, (FLASH_BUF_LEN - 1) >> 8);
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 FLASH_LEN_LOW, (FLASH_BUF_LEN - 1) & 0xFF);
> > +	if (ret < 0) {
> > +		DRM_DEV_ERROR(dev, "IO error : set key flash len.\n");
> > +		return ret;
> > +	}
> > +
> > +	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				R_FLASH_RW_CTRL, FLASH_READ);
> > +	ret |= readx_poll_timeout(anx7625_read_flash_status,
> > +				  ctx, val,
> > +				  ((val & FLASH_DONE) || (val < 0)),
> > +				  2000,
> > +				  2000 * 150);
> > +	if (ret) {
> > +		DRM_DEV_ERROR(dev, "flash read access fail!\n");
> > +		return -EIO;
> > +	}
> > +
> > +	ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client,
> > +				     FLASH_BUF_BASE_ADDR,
> > +				     FLASH_BUF_LEN, ident);
> > +	if (ret < 0) {
> > +		DRM_DEV_ERROR(dev, "read flash data fail!\n");
> > +		return -EIO;
> > +	}
> > +
> > +	if (ident[29] == 0xFF && ident[30] == 0xFF && ident[31] == 0xFF)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> > +static int anx7625_hdcp_key_load(struct anx7625_data *ctx)
> > +{
> > +	int ret;
> > +	struct device *dev = &ctx->client->dev;
> > +
> > +	/* Select HDCP 1.4 KEY */
> > +	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				R_BOOT_RETRY, 0x12);
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 FLASH_ADDR_HIGH, HDCP14KEY_START_ADDR >> 8);
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 FLASH_ADDR_LOW, HDCP14KEY_START_ADDR & 0xFF);
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 R_RAM_LEN_H, HDCP14KEY_SIZE >> 12);
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 R_RAM_LEN_L, HDCP14KEY_SIZE >> 4);
> > +
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 R_RAM_ADDR_H, 0);
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 R_RAM_ADDR_L, 0);
> > +	/* Enable HDCP 1.4 KEY load */
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +				 R_RAM_CTRL, DECRYPT_EN | LOAD_START);
> > +	DRM_DEV_DEBUG_DRIVER(dev, "load HDCP 1.4 key done\n");
> > +	return ret;
> > +}
> > +
> > +static int anx7625_hdcp_config(struct anx7625_data *ctx, bool on)
> > +{
> > +	u8 bcap;
> > +	int ret;
> > +	struct device *dev = &ctx->client->dev;
> > +
> > +	if (!on) {
> > +		DRM_DEV_DEBUG_DRIVER(dev, "disable HDCP 1.4\n");
> > +
> > +		/* Disable HDCP */
> > +		ret = anx7625_write_and(ctx, ctx->i2c.rx_p1_client, 0xee, 0x9f);
> > +		/* Try auth flag */
> > +		ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xec, 0x10);
> > +		/* Interrupt for DRM */
> > +		ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xff, 0x01);
> > +		if (ret < 0)
> > +			DRM_DEV_ERROR(dev, "fail to disable HDCP\n");
> > +
> > +		return anx7625_write_and(ctx, ctx->i2c.tx_p0_client,
> > +					 TX_HDCP_CTRL0, ~HARD_AUTH_EN & 0xFF);
> > +	}
> 
> 
> Code path for on==true, and on==false have nothing common.
> 
> This is definitely shows that anx7625_hdcp_config should be split to
> anx7625_hdcp_enable and anx7625_hdcp_disable (or on/off, whatever).
> 
OK, I'll split to two function.
> 
> > +
> > +	ret = anx7625_hdcp_key_probe(ctx);
> > +	if (ret) {
> > +		DRM_DEV_DEBUG_DRIVER(dev, "no key found, not to do hdcp\n");
> > +		return ret;
> > +	}
> > +
> > +	anx7625_aux_dpcd_read(ctx, 0x06, 0x80, 0x28, 1, &bcap);
> > +	if (!(bcap & 0x01)) {
> > +		DRM_WARN("downstream not support HDCP 1.4, cap(%x).\n", bcap);
> > +		return 0;
> > +	}
> > +
> > +	DRM_DEV_DEBUG_DRIVER(dev, "enable HDCP 1.4\n");
> > +
> > +	/* First clear HDCP state */
> > +	ret = anx7625_reg_write(ctx, ctx->i2c.tx_p0_client,
> > +				TX_HDCP_CTRL0,
> > +				KSVLIST_VLD | BKSV_SRM_PASS | RE_AUTHEN);
> > +	usleep_range(1000, 1100);
> > +	/* Second clear HDCP state */
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p0_client,
> > +				 TX_HDCP_CTRL0,
> > +				 KSVLIST_VLD | BKSV_SRM_PASS | RE_AUTHEN);
> > +
> > +	/* Set time for waiting KSVR */
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p0_client,
> > +				 SP_TX_WAIT_KSVR_TIME, 0xc8);
> > +	/* Set time for waiting R0 */
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p0_client,
> > +				 SP_TX_WAIT_R0_TIME, 0xb0);
> > +	ret |= anx7625_hdcp_key_load(ctx);
> > +	if (ret) {
> > +		DRM_WARN("prepare HDCP key failed.\n");
> > +		return ret;
> > +	}
> > +
> > +	ret = anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xee, 0x20);
> > +
> > +	/* Try auth flag */
> > +	ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xec, 0x10);
> > +	/* Interrupt for DRM */
> > +	ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xff, 0x01);
> > +	if (ret < 0)
> > +		DRM_DEV_ERROR(dev, "fail to enable HDCP\n");
> > +
> > +	return anx7625_write_or(ctx, ctx->i2c.tx_p0_client,
> > +				TX_HDCP_CTRL0, HARD_AUTH_EN);
> > +}
> > +
> >   static void anx7625_dp_start(struct anx7625_data *ctx)
> >   {
> >   	int ret;
> > @@ -679,6 +888,9 @@ static void anx7625_dp_start(struct anx7625_data *ctx)
> >   		return;
> >   	}
> > +	/* Disable HDCP */
> > +	anx7625_write_and(ctx, ctx->i2c.rx_p1_client, 0xee, 0x9f);
> > +
> >   	if (ctx->pdata.is_dpi)
> >   		ret = anx7625_dpi_config(ctx);
> >   	else
> > @@ -686,6 +898,10 @@ static void anx7625_dp_start(struct anx7625_data *ctx)
> >   	if (ret < 0)
> >   		DRM_DEV_ERROR(dev, "MIPI phy setup error.\n");
> > +
> > +	ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
> > +
> > +	ctx->dp_en = 1;
> >   }
> >   static void anx7625_dp_stop(struct anx7625_data *ctx)
> > @@ -705,6 +921,10 @@ static void anx7625_dp_stop(struct anx7625_data *ctx)
> >   	ret |= anx7625_video_mute_control(ctx, 1);
> >   	if (ret < 0)
> >   		DRM_DEV_ERROR(dev, "IO error : mute video fail\n");
> > +
> > +	ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
> > +
> > +	ctx->dp_en = 0;
> >   }
> >   static int sp_tx_rst_aux(struct anx7625_data *ctx)
> > @@ -859,7 +1079,7 @@ static int sp_tx_edid_read(struct anx7625_data *ctx,
> >   				AP_AUX_ADDR_7_0, 0x50);
> >   	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> >   				 AP_AUX_ADDR_15_8, 0);
> > -	ret |= anx7625_write_and(ctx, ctx->i2c.rx_p0_client,
> > +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> >   				 AP_AUX_ADDR_19_16, 0xf0);
> 
> 
> This is bugfix? How it is related to the rest of patchset.
OK, The old code is OK, I'll revert this change.
> 
> 
> Regards
> 
> Andrzej
> 
> 
> >   	if (ret < 0) {
> >   		DRM_DEV_ERROR(dev, "access aux channel IO error.\n");
> > @@ -1688,6 +1908,83 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx)
> >   	return 0;
> >   }
> > +void hdcp_check_work_func(struct work_struct *work)
> > +{
> > +	u8 status;
> > +	struct delayed_work *dwork;
> > +	struct anx7625_data *ctx;
> > +	struct device *dev;
> > +	struct drm_device *drm_dev;
> > +
> > +	dwork = to_delayed_work(work);
> > +	ctx = container_of(dwork, struct anx7625_data, hdcp_work);
> > +	dev = &ctx->client->dev;
> > +
> > +	if (!ctx->connector) {
> > +		DRM_ERROR("HDCP connector is null!");
> > +		return;
> > +	}
> > +
> > +	drm_dev = ctx->connector->dev;
> > +	drm_modeset_lock(&drm_dev->mode_config.connection_mutex, NULL);
> > +	mutex_lock(&ctx->hdcp_wq_lock);
> > +
> > +	status = anx7625_reg_read(ctx, ctx->i2c.tx_p0_client, 0);
> > +	DRM_DEV_DEBUG_DRIVER(dev, "sink HDCP status check: %.02x\n", status);
> > +	if (status & BIT(1)) {
> > +		ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_ENABLED;
> > +		drm_hdcp_update_content_protection(ctx->connector,
> > +						   ctx->hdcp_cp);
> > +		DRM_DEV_DEBUG_DRIVER(dev, "update CP to ENABLE\n");
> > +	}
> > +
> > +	mutex_unlock(&ctx->hdcp_wq_lock);
> > +	drm_modeset_unlock(&drm_dev->mode_config.connection_mutex);
> > +}
> > +
> > +static int anx7625_connector_atomic_check(struct anx7625_data *ctx,
> > +					  struct drm_connector_state *state)
> > +{
> > +	struct device *dev = &ctx->client->dev;
> > +	int cp;
> > +
> > +	DRM_DEV_DEBUG_DRIVER(dev, "hdcp state check\n");
> > +	cp = state->content_protection;
> > +
> > +	if (cp == ctx->hdcp_cp)
> > +		return 0;
> > +
> > +	if (cp == DRM_MODE_CONTENT_PROTECTION_DESIRED) {
> > +		if (ctx->dp_en) {
> > +			DRM_DEV_DEBUG_DRIVER(dev, "enable HDCP\n");
> > +			anx7625_hdcp_config(ctx, true);
> > +
> > +			queue_delayed_work(ctx->hdcp_workqueue,
> > +					   &ctx->hdcp_work,
> > +					   msecs_to_jiffies(2000));
> > +		}
> > +	}
> > +
> > +	if (cp == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
> > +		if (ctx->hdcp_cp != DRM_MODE_CONTENT_PROTECTION_ENABLED) {
> > +			DRM_ERROR("current CP is not ENABLED\n");
> > +			return -EINVAL;
> > +		}
> > +		anx7625_hdcp_config(ctx, false);
> > +		ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
> > +		drm_hdcp_update_content_protection(ctx->connector,
> > +						   ctx->hdcp_cp);
> > +		DRM_DEV_DEBUG_DRIVER(dev, "update CP to UNDESIRE\n");
> > +	}
> > +
> > +	if (cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
> > +		DRM_ERROR("Userspace illegal set to PROTECTION ENABLE\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> >   static int anx7625_bridge_attach(struct drm_bridge *bridge,
> >   				 enum drm_bridge_attach_flags flags)
> >   {
> > @@ -1902,25 +2199,58 @@ static bool anx7625_bridge_mode_fixup(struct drm_bridge *bridge,
> >   	return true;
> >   }
> > -static void anx7625_bridge_enable(struct drm_bridge *bridge)
> > +static int anx7625_bridge_atomic_check(struct drm_bridge *bridge,
> > +				       struct drm_bridge_state *bridge_state,
> > +				       struct drm_crtc_state *crtc_state,
> > +				       struct drm_connector_state *conn_state)
> >   {
> >   	struct anx7625_data *ctx = bridge_to_anx7625(bridge);
> >   	struct device *dev = &ctx->client->dev;
> > -	DRM_DEV_DEBUG_DRIVER(dev, "drm enable\n");
> > +	DRM_DEV_DEBUG_DRIVER(dev, "drm bridge atomic check\n");
> > +	anx7625_bridge_mode_fixup(bridge, &crtc_state->mode,
> > +				  &crtc_state->adjusted_mode);
> > +
> > +	return anx7625_connector_atomic_check(ctx, conn_state);
> > +}
> > +
> > +static void anx7625_bridge_atomic_enable(struct drm_bridge *bridge,
> > +					 struct drm_bridge_state *state)
> > +{
> > +	struct anx7625_data *ctx = bridge_to_anx7625(bridge);
> > +	struct device *dev = &ctx->client->dev;
> > +	struct drm_connector *connector;
> > +
> > +	DRM_DEV_DEBUG_DRIVER(dev, "drm atomic enable\n");
> > +
> > +	if (!bridge->encoder) {
> > +		DRM_DEV_ERROR(dev, "Parent encoder object not found");
> > +		return;
> > +	}
> > +
> > +	connector = drm_atomic_get_new_connector_for_encoder(state->base.state,
> > +							     bridge->encoder);
> > +	if (!connector)
> > +		return;
> > +
> > +	ctx->connector = connector;
> > +
> > +	DRM_DEV_DEBUG_DRIVER(dev, "attached content protection.\n");
> >   	pm_runtime_get_sync(dev);
> >   	anx7625_dp_start(ctx);
> >   }
> > -static void anx7625_bridge_disable(struct drm_bridge *bridge)
> > +static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge,
> > +					  struct drm_bridge_state *old)
> >   {
> >   	struct anx7625_data *ctx = bridge_to_anx7625(bridge);
> >   	struct device *dev = &ctx->client->dev;
> >   	DRM_DEV_DEBUG_DRIVER(dev, "drm disable\n");
> > +	ctx->connector = NULL;
> >   	anx7625_dp_stop(ctx);
> >   	pm_runtime_put_sync(dev);
> > @@ -1950,11 +2280,14 @@ static struct edid *anx7625_bridge_get_edid(struct drm_bridge *bridge,
> >   static const struct drm_bridge_funcs anx7625_bridge_funcs = {
> >   	.attach = anx7625_bridge_attach,
> > -	.disable = anx7625_bridge_disable,
> >   	.mode_valid = anx7625_bridge_mode_valid,
> >   	.mode_set = anx7625_bridge_mode_set,
> > -	.mode_fixup = anx7625_bridge_mode_fixup,
> > -	.enable = anx7625_bridge_enable,
> > +	.atomic_check = anx7625_bridge_atomic_check,
> > +	.atomic_enable = anx7625_bridge_atomic_enable,
> > +	.atomic_disable = anx7625_bridge_atomic_disable,
> > +	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> > +	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
> > +	.atomic_reset = drm_atomic_helper_bridge_reset,
> >   	.detect = anx7625_bridge_detect,
> >   	.get_edid = anx7625_bridge_get_edid,
> >   };
> > @@ -2134,6 +2467,15 @@ static int anx7625_i2c_probe(struct i2c_client *client,
> >   	anx7625_init_gpio(platform);
> >   	mutex_init(&platform->lock);
> > +	mutex_init(&platform->hdcp_wq_lock);
> > +
> > +	INIT_DELAYED_WORK(&platform->hdcp_work, hdcp_check_work_func);
> > +	platform->hdcp_workqueue = create_workqueue("hdcp workqueue");
> > +	if (!platform->hdcp_workqueue) {
> > +		DRM_DEV_ERROR(dev, "fail to create work queue\n");
> > +		ret = -ENOMEM;
> > +		goto free_platform;
> > +	}
> >   	platform->pdata.intp_irq = client->irq;
> >   	if (platform->pdata.intp_irq) {
> > @@ -2143,7 +2485,7 @@ static int anx7625_i2c_probe(struct i2c_client *client,
> >   		if (!platform->workqueue) {
> >   			DRM_DEV_ERROR(dev, "fail to create work queue\n");
> >   			ret = -ENOMEM;
> > -			goto free_platform;
> > +			goto free_hdcp_wq;
> >   		}
> >   		ret = devm_request_threaded_irq(dev, platform->pdata.intp_irq,
> > @@ -2213,6 +2555,10 @@ static int anx7625_i2c_probe(struct i2c_client *client,
> >   	if (platform->workqueue)
> >   		destroy_workqueue(platform->workqueue);
> > +free_hdcp_wq:
> > +	if (platform->hdcp_workqueue)
> > +		destroy_workqueue(platform->hdcp_workqueue);
> > +
> >   free_platform:
> >   	kfree(platform);
> > @@ -2228,6 +2574,12 @@ static int anx7625_i2c_remove(struct i2c_client *client)
> >   	if (platform->pdata.intp_irq)
> >   		destroy_workqueue(platform->workqueue);
> > +	if (platform->hdcp_workqueue) {
> > +		cancel_delayed_work(&platform->hdcp_work);
> > +		flush_workqueue(platform->workqueue);
> > +		destroy_workqueue(platform->workqueue);
> > +	}
> > +
> >   	if (!platform->pdata.low_power_mode)
> >   		pm_runtime_put_sync_suspend(&client->dev);
> > diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h
> > index 3d79b6fb13c8..89b1b347a463 100644
> > --- a/drivers/gpu/drm/bridge/analogix/anx7625.h
> > +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h
> > @@ -59,10 +59,23 @@
> >   /***************************************************************/
> >   /* Register definition of device address 0x70 */
> > -#define  I2C_ADDR_70_DPTX              0x70
> > -
> > -#define SP_TX_LINK_BW_SET_REG 0xA0
> > -#define SP_TX_LANE_COUNT_SET_REG 0xA1
> > +#define TX_HDCP_CTRL0			0x01
> > +#define STORE_AN			BIT(7)
> > +#define RX_REPEATER			BIT(6)
> > +#define RE_AUTHEN			BIT(5)
> > +#define SW_AUTH_OK			BIT(4)
> > +#define HARD_AUTH_EN			BIT(3)
> > +#define ENC_EN				BIT(2)
> > +#define BKSV_SRM_PASS			BIT(1)
> > +#define KSVLIST_VLD			BIT(0)
> > +
> > +#define SP_TX_WAIT_R0_TIME		0x40
> > +#define SP_TX_WAIT_KSVR_TIME		0x42
> > +#define SP_TX_SYS_CTRL1_REG		0x80
> > +#define HDCP2TX_FW_EN			BIT(4)
> > +
> > +#define SP_TX_LINK_BW_SET_REG		0xA0
> > +#define SP_TX_LANE_COUNT_SET_REG	0xA1
> >   #define M_VID_0 0xC0
> >   #define M_VID_1 0xC1
> > @@ -71,6 +84,12 @@
> >   #define N_VID_1 0xC4
> >   #define N_VID_2 0xC5
> > +#define KEY_START_ADDR			0x9000
> > +#define KEY_RESERVED			416
> > +
> > +#define HDCP14KEY_START_ADDR		(KEY_START_ADDR + KEY_RESERVED)
> > +#define HDCP14KEY_SIZE			624
> > +
> >   /***************************************************************/
> >   /* Register definition of device address 0x72 */
> >   #define AUX_RST	0x04
> > @@ -155,9 +174,43 @@
> >   #define  I2C_ADDR_7E_FLASH_CONTROLLER  0x7E
> > +#define R_BOOT_RETRY		0x00
> > +#define R_RAM_ADDR_H		0x01
> > +#define R_RAM_ADDR_L		0x02
> > +#define R_RAM_LEN_H		0x03
> > +#define R_RAM_LEN_L		0x04
> >   #define FLASH_LOAD_STA          0x05
> >   #define FLASH_LOAD_STA_CHK	BIT(7)
> > +#define R_RAM_CTRL              0x05
> > +/* bit positions */
> > +#define FLASH_DONE              BIT(7)
> > +#define BOOT_LOAD_DONE          BIT(6)
> > +#define CRC_OK                  BIT(5)
> > +#define LOAD_DONE               BIT(4)
> > +#define O_RW_DONE               BIT(3)
> > +#define FUSE_BUSY               BIT(2)
> > +#define DECRYPT_EN              BIT(1)
> > +#define LOAD_START              BIT(0)
> > +
> > +#define FLASH_ADDR_HIGH         0x0F
> > +#define FLASH_ADDR_LOW          0x10
> > +#define FLASH_LEN_HIGH          0x31
> > +#define FLASH_LEN_LOW           0x32
> > +#define R_FLASH_RW_CTRL         0x33
> > +/* bit positions */
> > +#define READ_DELAY_SELECT       BIT(7)
> > +#define GENERAL_INSTRUCTION_EN  BIT(6)
> > +#define FLASH_ERASE_EN          BIT(5)
> > +#define RDID_READ_EN            BIT(4)
> > +#define REMS_READ_EN            BIT(3)
> > +#define WRITE_STATUS_EN         BIT(2)
> > +#define FLASH_READ              BIT(1)
> > +#define FLASH_WRITE             BIT(0)
> > +
> > +#define FLASH_BUF_BASE_ADDR     0x60
> > +#define FLASH_BUF_LEN           0x20
> > +
> >   #define  XTAL_FRQ_SEL    0x3F
> >   /* bit field positions */
> >   #define  XTAL_FRQ_SEL_POS    5
> > @@ -392,21 +445,29 @@ struct anx7625_data {
> >   	struct platform_device *audio_pdev;
> >   	int hpd_status;
> >   	int hpd_high_cnt;
> > +	int dp_en;
> > +	int hdcp_cp;
> >   	/* Lock for work queue */
> >   	struct mutex lock;
> >   	struct i2c_client *client;
> >   	struct anx7625_i2c_client i2c;
> >   	struct i2c_client *last_client;
> > +	struct timer_list hdcp_timer;
> >   	struct s_edid_data slimport_edid_p;
> >   	struct device *codec_dev;
> >   	hdmi_codec_plugged_cb plugged_cb;
> >   	struct work_struct work;
> >   	struct workqueue_struct *workqueue;
> > +	struct delayed_work hdcp_work;
> > +	struct workqueue_struct *hdcp_workqueue;
> > +	/* Lock for hdcp work queue */
> > +	struct mutex hdcp_wq_lock;
> >   	char edid_block;
> >   	struct display_timing dt;
> >   	u8 display_timing_valid;
> >   	struct drm_bridge bridge;
> >   	u8 bridge_attached;
> > +	struct drm_connector *connector;
> >   	struct mipi_dsi_device *dsi;
> >   };

^ permalink raw reply

* [PATCH] docs: reSTify virtio-balloon-stats documentation and move to docs/interop
From: Thomas Huth @ 2022-01-05 11:52 UTC (permalink / raw)
  To: qemu-devel, Michael S. Tsirkin, David Hildenbrand

The virtio-balloon-stats documentation might be useful for people that
are implementing software that talks to QEMU via QMP, so this should
reside in the docs/interop/ directory. While we're at it, also convert
the file to restructured text and mention it in the MAINTAINERS file.

Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 MAINTAINERS                                   |  1 +
 docs/interop/index.rst                        |  1 +
 .../virtio-balloon-stats.rst}                 | 58 ++++++++++---------
 3 files changed, 32 insertions(+), 28 deletions(-)
 rename docs/{virtio-balloon-stats.txt => interop/virtio-balloon-stats.rst} (66%)

diff --git a/MAINTAINERS b/MAINTAINERS
index 53cf0fdc00..3c587410f4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1929,6 +1929,7 @@ virtio-balloon
 M: Michael S. Tsirkin <mst@redhat.com>
 M: David Hildenbrand <david@redhat.com>
 S: Maintained
+F: docs/interop/virtio-balloon-stats.rst
 F: hw/virtio/virtio-balloon*.c
 F: include/hw/virtio/virtio-balloon.h
 F: softmmu/balloon.c
diff --git a/docs/interop/index.rst b/docs/interop/index.rst
index c59bac9834..b7632acb7b 100644
--- a/docs/interop/index.rst
+++ b/docs/interop/index.rst
@@ -22,3 +22,4 @@ are useful for making QEMU interoperate with other software.
    vhost-user
    vhost-user-gpu
    vhost-vdpa
+   virtio-balloon-stats
diff --git a/docs/virtio-balloon-stats.txt b/docs/interop/virtio-balloon-stats.rst
similarity index 66%
rename from docs/virtio-balloon-stats.txt
rename to docs/interop/virtio-balloon-stats.rst
index 1732cc8c8a..b9a6a6edb2 100644
--- a/docs/virtio-balloon-stats.txt
+++ b/docs/interop/virtio-balloon-stats.rst
@@ -1,4 +1,4 @@
-virtio balloon memory statistics
+Virtio balloon memory statistics
 ================================
 
 The virtio balloon driver supports guest memory statistics reporting. These
@@ -9,10 +9,12 @@ Before querying the available stats, clients first have to enable polling.
 This is done by writing a time interval value (in seconds) to the
 guest-stats-polling-interval property. This value can be:
 
-  > 0  enables polling in the specified interval. If polling is already
+  > 0
+       enables polling in the specified interval. If polling is already
        enabled, the polling time interval is changed to the new value
 
-  0    disables polling. Previous polled statistics are still valid and
+  0
+       disables polling. Previous polled statistics are still valid and
        can be queried.
 
 Once polling is enabled, the virtio-balloon device in QEMU will start
@@ -22,7 +24,7 @@ interval.
 To retrieve those stats, clients have to query the guest-stats property,
 which will return a dictionary containing:
 
-  o A key named 'stats', containing all available stats. If the guest
+  * A key named 'stats', containing all available stats. If the guest
     doesn't support a particular stat, or if it couldn't be retrieved,
     its value will be -1. Currently, the following stats are supported:
 
@@ -37,7 +39,7 @@ which will return a dictionary containing:
       - stat-htlb-pgalloc
       - stat-htlb-pgfail
 
-  o A key named last-update, which contains the last stats update
+  * A key named last-update, which contains the last stats update
     timestamp in seconds. Since this timestamp is generated by the host,
     a buggy guest can't influence its value. The value is 0 if the guest
     has not updated the stats (yet).
@@ -61,32 +63,32 @@ It's also important to note the following:
    respond to the request the timer will never be re-armed, which has
    the same effect as disabling polling
 
-Here are a few examples. QEMU is started with '-device virtio-balloon',
-which generates '/machine/peripheral-anon/device[1]' as the QOM path for
+Here are a few examples. QEMU is started with ``-device virtio-balloon``,
+which generates ``/machine/peripheral-anon/device[1]`` as the QOM path for
 the balloon device.
 
-Enable polling with 2 seconds interval:
+Enable polling with 2 seconds interval::
 
-{ "execute": "qom-set",
-             "arguments": { "path": "/machine/peripheral-anon/device[1]",
-			 "property": "guest-stats-polling-interval", "value": 2 } }
+  { "execute": "qom-set",
+               "arguments": { "path": "/machine/peripheral-anon/device[1]",
+               "property": "guest-stats-polling-interval", "value": 2 } }
 
-{ "return": {} }
+  { "return": {} }
 
-Change polling to 10 seconds:
+Change polling to 10 seconds::
 
-{ "execute": "qom-set",
-             "arguments": { "path": "/machine/peripheral-anon/device[1]",
-			 "property": "guest-stats-polling-interval", "value": 10 } }
+  { "execute": "qom-set",
+               "arguments": { "path": "/machine/peripheral-anon/device[1]",
+               "property": "guest-stats-polling-interval", "value": 10 } }
 
-{ "return": {} }
+  { "return": {} }
 
-Get stats:
+Get stats::
 
-{ "execute": "qom-get",
-  "arguments": { "path": "/machine/peripheral-anon/device[1]",
-  "property": "guest-stats" } }
-{
+  { "execute": "qom-get",
+               "arguments": { "path": "/machine/peripheral-anon/device[1]",
+               "property": "guest-stats" } }
+  {
     "return": {
         "stats": {
             "stat-swap-out": 0,
@@ -98,12 +100,12 @@ Get stats:
         },
         "last-update": 1358529861
     }
-}
+  }
 
-Disable polling:
+Disable polling::
 
-{ "execute": "qom-set",
-             "arguments": { "path": "/machine/peripheral-anon/device[1]",
-			 "property": "stats-polling-interval", "value": 0 } }
+  { "execute": "qom-set",
+               "arguments": { "path": "/machine/peripheral-anon/device[1]",
+               "property": "stats-polling-interval", "value": 0 } }
 
-{ "return": {} }
+  { "return": {} }
-- 
2.27.0



^ permalink raw reply related

* [RESEND][PATCH v2] Input: xpad - Poweroff XBOX360W on mode button long press
From: Benjamin Valentin @ 2022-01-05 11:53 UTC (permalink / raw)
  To: Cameron Gutman; +Cc: Dmitry Torokhov, linux-input, Lee Jones, lawl
In-Reply-To: <3b25f4b1-3ec0-0878-99bc-0da06ce7c2f2@gmail.com>

Newer gamepads turn themselves off when the mode button is held down.
For XBOX360W gamepads we must do this in the driver.

Power off the gamepad after 5s of holding down the button.

Signed-off-by: lawl <github@dumbinter.net>
Signed-off-by: Benjamin Valentin <benpicco@googlemail.com>
---
Changed the timeout back to 5s

 drivers/input/joystick/xpad.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 18caaf436ed4..e36c4b0abd4b 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -619,11 +619,13 @@ struct usb_xpad {
 	int pad_nr;			/* the order x360 pads were attached */
 	const char *name;		/* name of the device */
 	struct work_struct work;	/* init/remove device from callback */
+	time64_t mode_btn_down_ts;	/* timestamp when mode button was pressed */
 };
 
 static int xpad_init_input(struct usb_xpad *xpad);
 static void xpad_deinit_input(struct usb_xpad *xpad);
 static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num);
+static void xpad360w_poweroff_controller(struct usb_xpad *xpad);
 
 /*
  *	xpad_process_packet
@@ -775,6 +777,24 @@ static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev,
 	}
 
 	input_sync(dev);
+
+	/* xbox360w controllers can't be turned off without driver assistance */
+	if (xpad->xtype == XTYPE_XBOX360W) {
+		if (xpad->mode_btn_down_ts > 0
+		    && xpad->pad_present
+		    /* send power off after 5s of holding the button */
+		    && (ktime_get_seconds() - xpad->mode_btn_down_ts) >= 5) {
+			xpad360w_poweroff_controller(xpad);
+			xpad->mode_btn_down_ts = 0;
+			return;
+		}
+
+		/* mode button down/up */
+		if (data[3] & 0x04)
+			xpad->mode_btn_down_ts = ktime_get_seconds();
+		else
+			xpad->mode_btn_down_ts = 0;
+	}
 }
 
 static void xpad_presence_work(struct work_struct *work)
-- 
2.32.0

^ permalink raw reply related

* Re: Linux 4.9.296
From: Greg Kroah-Hartman @ 2022-01-05 11:52 UTC (permalink / raw)
  To: linux-kernel, akpm, torvalds, stable; +Cc: lwn, jslaby, Greg Kroah-Hartman
In-Reply-To: <164138352914056@kroah.com>

diff --git a/Makefile b/Makefile
index b5afdb8a7521..1ec880bcdb2d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 4
 PATCHLEVEL = 9
-SUBLEVEL = 295
+SUBLEVEL = 296
 EXTRAVERSION =
 NAME = Roaring Lionus
 
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 2d2422705ccf..da9813f09d7d 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -136,6 +136,7 @@ config HID_APPLEIR
 
 config HID_ASUS
 	tristate "Asus"
+	depends on USB_HID
 	depends on I2C_HID
 	---help---
 	Support for Asus notebook built-in keyboard via i2c.
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index f4445a4e8d6a..cfa1be4ad868 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -35,6 +35,7 @@
 #include <linux/module.h>
 #include <linux/input.h>
 #include <linux/serio.h>
+#include <asm/unaligned.h>
 
 #define DRIVER_DESC	"SpaceTec SpaceBall 2003/3003/4000 FLX driver"
 
@@ -91,9 +92,15 @@ static void spaceball_process_packet(struct spaceball* spaceball)
 
 		case 'D':					/* Ball data */
 			if (spaceball->idx != 15) return;
-			for (i = 0; i < 6; i++)
+			/*
+			 * Skip first three bytes; read six axes worth of data.
+			 * Axis values are signed 16-bit big-endian.
+			 */
+			data += 3;
+			for (i = 0; i < ARRAY_SIZE(spaceball_axes); i++) {
 				input_report_abs(dev, spaceball_axes[i],
-					(__s16)((data[2 * i + 3] << 8) | data[2 * i + 2]));
+					(__s16)get_unaligned_be16(&data[i * 2]));
+			}
 			break;
 
 		case 'K':					/* Button data */
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index ef234c9b2f2f..11773838a34d 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -929,6 +929,8 @@ static int atp_probe(struct usb_interface *iface,
 	set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
 	set_bit(BTN_LEFT, input_dev->keybit);
 
+	INIT_WORK(&dev->work, atp_reinit);
+
 	error = input_register_device(dev->input);
 	if (error)
 		goto err_free_buffer;
@@ -936,8 +938,6 @@ static int atp_probe(struct usb_interface *iface,
 	/* save our data pointer in this interface device */
 	usb_set_intfdata(iface, dev);
 
-	INIT_WORK(&dev->work, atp_reinit);
-
 	return 0;
 
  err_free_buffer:
diff --git a/drivers/net/ethernet/freescale/fman/fman_port.c b/drivers/net/ethernet/freescale/fman/fman_port.c
index 4986f6ba278a..45ac5cf717ea 100644
--- a/drivers/net/ethernet/freescale/fman/fman_port.c
+++ b/drivers/net/ethernet/freescale/fman/fman_port.c
@@ -1658,7 +1658,7 @@ static int fman_port_probe(struct platform_device *of_dev)
 	fman = dev_get_drvdata(&fm_pdev->dev);
 	if (!fman) {
 		err = -EINVAL;
-		goto return_err;
+		goto put_device;
 	}
 
 	err = of_property_read_u32(port_node, "cell-index", &val);
@@ -1666,7 +1666,7 @@ static int fman_port_probe(struct platform_device *of_dev)
 		dev_err(port->dev, "%s: reading cell-index for %s failed\n",
 			__func__, port_node->full_name);
 		err = -EINVAL;
-		goto return_err;
+		goto put_device;
 	}
 	port_id = (u8)val;
 	port->dts_params.id = port_id;
@@ -1700,7 +1700,7 @@ static int fman_port_probe(struct platform_device *of_dev)
 	}  else {
 		dev_err(port->dev, "%s: Illegal port type\n", __func__);
 		err = -EINVAL;
-		goto return_err;
+		goto put_device;
 	}
 
 	port->dts_params.type = port_type;
@@ -1714,7 +1714,7 @@ static int fman_port_probe(struct platform_device *of_dev)
 			dev_err(port->dev, "%s: incorrect qman-channel-id\n",
 				__func__);
 			err = -EINVAL;
-			goto return_err;
+			goto put_device;
 		}
 		port->dts_params.qman_channel_id = qman_channel_id;
 	}
@@ -1724,7 +1724,7 @@ static int fman_port_probe(struct platform_device *of_dev)
 		dev_err(port->dev, "%s: of_address_to_resource() failed\n",
 			__func__);
 		err = -ENOMEM;
-		goto return_err;
+		goto put_device;
 	}
 
 	port->dts_params.fman = fman;
@@ -1749,6 +1749,8 @@ static int fman_port_probe(struct platform_device *of_dev)
 
 	return 0;
 
+put_device:
+	put_device(&fm_pdev->dev);
 return_err:
 	of_node_put(port_node);
 free_port:
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index a66be137324c..76f5703bc4f6 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -628,7 +628,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
 	}
 
 	gmux_data->iostart = res->start;
-	gmux_data->iolen = res->end - res->start;
+	gmux_data->iolen = resource_size(res);
 
 	if (gmux_data->iolen < GMUX_MIN_IO_LEN) {
 		pr_err("gmux I/O region too small (%lu < %u)\n",
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index 4d2172c115c6..90057c31d01c 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -581,9 +581,12 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter,
 			 * Commands like INQUIRY may transfer less data than
 			 * requested by the initiator via bufflen. Set residual
 			 * count to make upper layer aware of the actual amount
-			 * of data returned.
+			 * of data returned. There are cases when controller
+			 * returns zero dataLen with non zero data - do not set
+			 * residual count in that case.
 			 */
-			scsi_set_resid(cmd, scsi_bufflen(cmd) - e->dataLen);
+			if (e->dataLen && (e->dataLen < scsi_bufflen(cmd)))
+				scsi_set_resid(cmd, scsi_bufflen(cmd) - e->dataLen);
 			cmd->result = (DID_OK << 16);
 			break;
 
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index bcb2daf81b05..033639268693 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -1667,11 +1667,15 @@ static void ffs_data_clear(struct ffs_data *ffs)
 
 	BUG_ON(ffs->gadget);
 
-	if (ffs->epfiles)
+	if (ffs->epfiles) {
 		ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
+		ffs->epfiles = NULL;
+	}
 
-	if (ffs->ffs_eventfd)
+	if (ffs->ffs_eventfd) {
 		eventfd_ctx_put(ffs->ffs_eventfd);
+		ffs->ffs_eventfd = NULL;
+	}
 
 	kfree(ffs->raw_descs_data);
 	kfree(ffs->raw_strings);
@@ -1684,7 +1688,6 @@ static void ffs_data_reset(struct ffs_data *ffs)
 
 	ffs_data_clear(ffs);
 
-	ffs->epfiles = NULL;
 	ffs->raw_descs_data = NULL;
 	ffs->raw_descs = NULL;
 	ffs->raw_strings = NULL;
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index ae67f6383ca3..30c8eeed9507 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -92,7 +92,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
 	/* Look for vendor-specific quirks */
 	if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
 			(pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK ||
-			 pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1100 ||
 			 pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1400)) {
 		if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK &&
 				pdev->revision == 0x0) {
@@ -127,6 +126,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
 			pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1009)
 		xhci->quirks |= XHCI_BROKEN_STREAMS;
 
+	if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
+			pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1100)
+		xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+
 	if (pdev->vendor == PCI_VENDOR_ID_NEC)
 		xhci->quirks |= XHCI_NEC_HOST;
 
diff --git a/include/uapi/linux/nfc.h b/include/uapi/linux/nfc.h
index 399f39ff8048..1b6d54a328ba 100644
--- a/include/uapi/linux/nfc.h
+++ b/include/uapi/linux/nfc.h
@@ -261,7 +261,7 @@ enum nfc_sdp_attr {
 #define NFC_SE_ENABLED  0x1
 
 struct sockaddr_nfc {
-	sa_family_t sa_family;
+	__kernel_sa_family_t sa_family;
 	__u32 dev_idx;
 	__u32 target_idx;
 	__u32 nfc_protocol;
@@ -269,14 +269,14 @@ struct sockaddr_nfc {
 
 #define NFC_LLCP_MAX_SERVICE_NAME 63
 struct sockaddr_nfc_llcp {
-	sa_family_t sa_family;
+	__kernel_sa_family_t sa_family;
 	__u32 dev_idx;
 	__u32 target_idx;
 	__u32 nfc_protocol;
 	__u8 dsap; /* Destination SAP, if known */
 	__u8 ssap; /* Source SAP to be bound to */
 	char service_name[NFC_LLCP_MAX_SERVICE_NAME]; /* Service name URI */;
-	size_t service_name_len;
+	__kernel_size_t service_name_len;
 };
 
 /* NFC socket protocols */
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 689246d079ad..a8563745980b 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1833,6 +1833,10 @@ static int __init inet_init(void)
 
 	tcp_v4_init();
 
+	/* Initialise per-cpu ipv4 mibs */
+	if (init_ipv4_mibs())
+		panic("%s: Cannot init ipv4 mibs\n", __func__);
+
 	/* Setup TCP slab cache for open requests. */
 	tcp_init();
 
@@ -1861,12 +1865,6 @@ static int __init inet_init(void)
 
 	if (init_inet_pernet_ops())
 		pr_crit("%s: Cannot init ipv4 inet pernet ops\n", __func__);
-	/*
-	 *	Initialise per-cpu ipv4 mibs
-	 */
-
-	if (init_ipv4_mibs())
-		pr_crit("%s: Cannot init ipv4 mibs\n", __func__);
 
 	ipv4_proc_init();
 
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl
index 21da2831e05b..796174fd9032 100755
--- a/scripts/recordmcount.pl
+++ b/scripts/recordmcount.pl
@@ -250,7 +250,7 @@ if ($arch eq "x86_64") {
 
 } elsif ($arch eq "s390" && $bits == 64) {
     if ($cc =~ /-DCC_USING_HOTPATCH/) {
-	$mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*(bcrl\\s*0,|jgnop\\s*)[0-9a-f]+ <([^\+]*)>\$";
+	$mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*(brcl\\s*0,|jgnop\\s*)[0-9a-f]+ <([^\+]*)>\$";
 	$mcount_adjust = 0;
     } else {
 	$mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$";
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 607c7fc4f24d..eb9e2b4e81d9 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5194,7 +5194,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
 	struct common_audit_data ad;
 	struct lsm_network_audit net = {0,};
 	char *addrp;
-	u8 proto;
+	u8 proto = 0;
 
 	if (sk == NULL)
 		return NF_ACCEPT;

^ permalink raw reply related

* Linux 4.9.296
From: Greg Kroah-Hartman @ 2022-01-05 11:52 UTC (permalink / raw)
  To: linux-kernel, akpm, torvalds, stable; +Cc: lwn, jslaby, Greg Kroah-Hartman

I'm announcing the release of the 4.9.296 kernel.

All users of the 4.9 kernel series must upgrade.

The updated 4.9.y git tree can be found at:
	git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git linux-4.9.y
and can be browsed at the normal kernel.org git web browser:
	https://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git;a=summary

thanks,

greg k-h

------------

 Makefile                                        |    2 +-
 drivers/hid/Kconfig                             |    1 +
 drivers/input/joystick/spaceball.c              |   11 +++++++++--
 drivers/input/mouse/appletouch.c                |    4 ++--
 drivers/net/ethernet/freescale/fman/fman_port.c |   12 +++++++-----
 drivers/platform/x86/apple-gmux.c               |    2 +-
 drivers/scsi/vmw_pvscsi.c                       |    7 +++++--
 drivers/usb/gadget/function/f_fs.c              |    9 ++++++---
 drivers/usb/host/xhci-pci.c                     |    5 ++++-
 include/uapi/linux/nfc.h                        |    6 +++---
 net/ipv4/af_inet.c                              |   10 ++++------
 scripts/recordmcount.pl                         |    2 +-
 security/selinux/hooks.c                        |    2 +-
 13 files changed, 45 insertions(+), 28 deletions(-)

Alexey Makhalov (1):
      scsi: vmw_pvscsi: Set residual data length conditionally

Dmitry V. Levin (1):
      uapi: fix linux/nfc.h userspace compilation errors

Greg Kroah-Hartman (1):
      Linux 4.9.296

Hans de Goede (1):
      HID: asus: Add depends on USB_HID to HID_ASUS Kconfig option

Heiko Carstens (1):
      recordmcount.pl: fix typo in s390 mcount regex

Krzysztof Kozlowski (1):
      nfc: uapi: use kernel size_t to fix user-space builds

Leo L. Schwab (1):
      Input: spaceball - fix parsing of movement data packets

Mathias Nyman (1):
      xhci: Fresco FL1100 controller should not have BROKEN_MSI quirk set.

Miaoqian Lin (1):
      fsl/fman: Fix missing put_device() call in fman_port_probe

Muchun Song (1):
      net: fix use-after-free in tw_timer_handler

Pavel Skripkin (1):
      Input: appletouch - initialize work before device registration

Tom Rix (1):
      selinux: initialize proto variable in selinux_ip_postroute_compat()

Vincent Pelletier (1):
      usb: gadget: f_fs: Clear ffs_eventfd in ffs_data_clear.

Wang Qing (1):
      platform/x86: apple-gmux: use resource_size() with res


^ permalink raw reply

* Re: Linux 4.4.298
From: Greg Kroah-Hartman @ 2022-01-05 11:52 UTC (permalink / raw)
  To: linux-kernel, akpm, torvalds, stable; +Cc: lwn, jslaby, Greg Kroah-Hartman
In-Reply-To: <1641383524120143@kroah.com>

diff --git a/Makefile b/Makefile
index 6bc764fb1b97..f35474e260f1 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 4
 PATCHLEVEL = 4
-SUBLEVEL = 297
+SUBLEVEL = 298
 EXTRAVERSION =
 NAME = Blurry Fish Butt
 
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index f4445a4e8d6a..cfa1be4ad868 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -35,6 +35,7 @@
 #include <linux/module.h>
 #include <linux/input.h>
 #include <linux/serio.h>
+#include <asm/unaligned.h>
 
 #define DRIVER_DESC	"SpaceTec SpaceBall 2003/3003/4000 FLX driver"
 
@@ -91,9 +92,15 @@ static void spaceball_process_packet(struct spaceball* spaceball)
 
 		case 'D':					/* Ball data */
 			if (spaceball->idx != 15) return;
-			for (i = 0; i < 6; i++)
+			/*
+			 * Skip first three bytes; read six axes worth of data.
+			 * Axis values are signed 16-bit big-endian.
+			 */
+			data += 3;
+			for (i = 0; i < ARRAY_SIZE(spaceball_axes); i++) {
 				input_report_abs(dev, spaceball_axes[i],
-					(__s16)((data[2 * i + 3] << 8) | data[2 * i + 2]));
+					(__s16)get_unaligned_be16(&data[i * 2]));
+			}
 			break;
 
 		case 'K':					/* Button data */
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index ef234c9b2f2f..11773838a34d 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -929,6 +929,8 @@ static int atp_probe(struct usb_interface *iface,
 	set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
 	set_bit(BTN_LEFT, input_dev->keybit);
 
+	INIT_WORK(&dev->work, atp_reinit);
+
 	error = input_register_device(dev->input);
 	if (error)
 		goto err_free_buffer;
@@ -936,8 +938,6 @@ static int atp_probe(struct usb_interface *iface,
 	/* save our data pointer in this interface device */
 	usb_set_intfdata(iface, dev);
 
-	INIT_WORK(&dev->work, atp_reinit);
-
 	return 0;
 
  err_free_buffer:
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index 976efeb3f2ba..a0f10ccdca3e 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -461,7 +461,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
 	}
 
 	gmux_data->iostart = res->start;
-	gmux_data->iolen = res->end - res->start;
+	gmux_data->iolen = resource_size(res);
 
 	if (gmux_data->iolen < GMUX_MIN_IO_LEN) {
 		pr_err("gmux I/O region too small (%lu < %u)\n",
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index d25cf084afe7..b0fd017abebd 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -562,9 +562,12 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter,
 			 * Commands like INQUIRY may transfer less data than
 			 * requested by the initiator via bufflen. Set residual
 			 * count to make upper layer aware of the actual amount
-			 * of data returned.
+			 * of data returned. There are cases when controller
+			 * returns zero dataLen with non zero data - do not set
+			 * residual count in that case.
 			 */
-			scsi_set_resid(cmd, scsi_bufflen(cmd) - e->dataLen);
+			if (e->dataLen && (e->dataLen < scsi_bufflen(cmd)))
+				scsi_set_resid(cmd, scsi_bufflen(cmd) - e->dataLen);
 			cmd->result = (DID_OK << 16);
 			break;
 
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index c045d4176a9c..390e592358e6 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -1476,11 +1476,15 @@ static void ffs_data_clear(struct ffs_data *ffs)
 
 	BUG_ON(ffs->gadget);
 
-	if (ffs->epfiles)
+	if (ffs->epfiles) {
 		ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
+		ffs->epfiles = NULL;
+	}
 
-	if (ffs->ffs_eventfd)
+	if (ffs->ffs_eventfd) {
 		eventfd_ctx_put(ffs->ffs_eventfd);
+		ffs->ffs_eventfd = NULL;
+	}
 
 	kfree(ffs->raw_descs_data);
 	kfree(ffs->raw_strings);
@@ -1493,7 +1497,6 @@ static void ffs_data_reset(struct ffs_data *ffs)
 
 	ffs_data_clear(ffs);
 
-	ffs->epfiles = NULL;
 	ffs->raw_descs_data = NULL;
 	ffs->raw_descs = NULL;
 	ffs->raw_strings = NULL;
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index fd7925f20a6a..2fb202da44b8 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -91,7 +91,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
 	/* Look for vendor-specific quirks */
 	if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
 			(pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK ||
-			 pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1100 ||
 			 pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1400)) {
 		if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK &&
 				pdev->revision == 0x0) {
@@ -126,6 +125,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
 			pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1009)
 		xhci->quirks |= XHCI_BROKEN_STREAMS;
 
+	if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
+			pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1100)
+		xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+
 	if (pdev->vendor == PCI_VENDOR_ID_NEC)
 		xhci->quirks |= XHCI_NEC_HOST;
 
diff --git a/include/uapi/linux/nfc.h b/include/uapi/linux/nfc.h
index 399f39ff8048..1b6d54a328ba 100644
--- a/include/uapi/linux/nfc.h
+++ b/include/uapi/linux/nfc.h
@@ -261,7 +261,7 @@ enum nfc_sdp_attr {
 #define NFC_SE_ENABLED  0x1
 
 struct sockaddr_nfc {
-	sa_family_t sa_family;
+	__kernel_sa_family_t sa_family;
 	__u32 dev_idx;
 	__u32 target_idx;
 	__u32 nfc_protocol;
@@ -269,14 +269,14 @@ struct sockaddr_nfc {
 
 #define NFC_LLCP_MAX_SERVICE_NAME 63
 struct sockaddr_nfc_llcp {
-	sa_family_t sa_family;
+	__kernel_sa_family_t sa_family;
 	__u32 dev_idx;
 	__u32 target_idx;
 	__u32 nfc_protocol;
 	__u8 dsap; /* Destination SAP, if known */
 	__u8 ssap; /* Source SAP to be bound to */
 	char service_name[NFC_LLCP_MAX_SERVICE_NAME]; /* Service name URI */;
-	size_t service_name_len;
+	__kernel_size_t service_name_len;
 };
 
 /* NFC socket protocols */
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index b12721ecb0b6..48d2ae83e268 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1770,6 +1770,10 @@ static int __init inet_init(void)
 
 	tcp_v4_init();
 
+	/* Initialise per-cpu ipv4 mibs */
+	if (init_ipv4_mibs())
+		panic("%s: Cannot init ipv4 mibs\n", __func__);
+
 	/* Setup TCP slab cache for open requests. */
 	tcp_init();
 
@@ -1798,12 +1802,6 @@ static int __init inet_init(void)
 
 	if (init_inet_pernet_ops())
 		pr_crit("%s: Cannot init ipv4 inet pernet ops\n", __func__);
-	/*
-	 *	Initialise per-cpu ipv4 mibs
-	 */
-
-	if (init_ipv4_mibs())
-		pr_crit("%s: Cannot init ipv4 mibs\n", __func__);
 
 	ipv4_proc_init();
 
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl
index b690b294fc36..e1de4423abce 100755
--- a/scripts/recordmcount.pl
+++ b/scripts/recordmcount.pl
@@ -248,7 +248,7 @@ if ($arch eq "x86_64") {
 
 } elsif ($arch eq "s390" && $bits == 64) {
     if ($cc =~ /-DCC_USING_HOTPATCH/) {
-	$mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*(bcrl\\s*0,|jgnop\\s*)[0-9a-f]+ <([^\+]*)>\$";
+	$mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*(brcl\\s*0,|jgnop\\s*)[0-9a-f]+ <([^\+]*)>\$";
 	$mcount_adjust = 0;
     } else {
 	$mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$";
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 44f4495e3fbd..55d253c6ab2f 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4974,7 +4974,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
 	struct common_audit_data ad;
 	struct lsm_network_audit net = {0,};
 	char *addrp;
-	u8 proto;
+	u8 proto = 0;
 
 	if (sk == NULL)
 		return NF_ACCEPT;

^ permalink raw reply related


This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.