From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.2 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 60786C43381 for ; Wed, 20 Feb 2019 13:05:33 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id EF3782147A for ; Wed, 20 Feb 2019 13:05:32 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="IgFHcxNd" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728117AbfBTNFb (ORCPT ); Wed, 20 Feb 2019 08:05:31 -0500 Received: from fllv0015.ext.ti.com ([198.47.19.141]:54510 "EHLO fllv0015.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726455AbfBTNFa (ORCPT ); Wed, 20 Feb 2019 08:05:30 -0500 Received: from lelv0266.itg.ti.com ([10.180.67.225]) by fllv0015.ext.ti.com (8.15.2/8.15.2) with ESMTP id x1KD4xIb090854; Wed, 20 Feb 2019 07:04:59 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1550667899; bh=vIQgL1ykm2WAtN8xEkkGVHAISyw9Y2lKwR8Wpn5EDjc=; h=Subject:To:CC:References:From:Date:In-Reply-To; b=IgFHcxNdMEmE87/XTg4oz9/m363LtDLYrHXz/EzNrxR57yVcI+zzhBgTmxNC+Gx1+ UMyvnvKcHLuBt4WKJptzc6zIE02EXLe+qWKN8f1uSXNScGRwRu7tQdATx2DQOZfwj+ 5R2DjoSKkVQxUtrQRBs7MahDDm7dPWfkiJnANIXw= Received: from DFLE114.ent.ti.com (dfle114.ent.ti.com [10.64.6.35]) by lelv0266.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x1KD4xBs004504 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 20 Feb 2019 07:04:59 -0600 Received: from DFLE110.ent.ti.com (10.64.6.31) by DFLE114.ent.ti.com (10.64.6.35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10; Wed, 20 Feb 2019 07:04:58 -0600 Received: from dlep32.itg.ti.com (157.170.170.100) by DFLE110.ent.ti.com (10.64.6.31) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1591.10 via Frontend Transport; Wed, 20 Feb 2019 07:04:58 -0600 Received: from [192.168.2.6] (ileax41-snat.itg.ti.com [10.172.224.153]) by dlep32.itg.ti.com (8.14.3/8.13.8) with ESMTP id x1KD4sZC024874; Wed, 20 Feb 2019 07:04:54 -0600 Subject: Re: [PATCH v4 5/6] usb:cdns3 Add Cadence USB3 DRD Driver To: Pawel Laszczak , CC: , , , , , , , , , , , , , , References: <1550173514-23573-1-git-send-email-pawell@cadence.com> <1550173514-23573-6-git-send-email-pawell@cadence.com> From: Roger Quadros Message-ID: <3af305e0-40bf-28cc-48d5-4afa241e7899@ti.com> Date: Wed, 20 Feb 2019 15:04:53 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.4.0 MIME-Version: 1.0 In-Reply-To: <1550173514-23573-6-git-send-email-pawell@cadence.com> Content-Type: text/plain; charset="utf-8" Content-Language: en-GB Content-Transfer-Encoding: 7bit X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Pawel, On 14/02/2019 21:45, Pawel Laszczak wrote: > This patch introduce new Cadence USBSS DRD driver to linux kernel. > > The Cadence USBSS DRD Driver is a highly configurable IP Core whichi > can be instantiated as Dual-Role Device (DRD), Peripheral Only and > Host Only (XHCI)configurations. > > The current driver has been validated with FPGA burned. We have support > for PCIe bus, which is used on FPGA prototyping. > > The host side of USBSS-DRD controller is compliance with XHCI > specification, so it works with standard XHCI linux driver. > > Signed-off-by: Pawel Laszczak > --- > drivers/usb/Kconfig | 2 + > drivers/usb/Makefile | 2 + > drivers/usb/cdns3/Kconfig | 44 + > drivers/usb/cdns3/Makefile | 14 + > drivers/usb/cdns3/cdns3-pci-wrap.c | 155 +++ > drivers/usb/cdns3/core.c | 403 ++++++ > drivers/usb/cdns3/core.h | 116 ++ > drivers/usb/cdns3/debug.h | 168 +++ > drivers/usb/cdns3/debugfs.c | 164 +++ > drivers/usb/cdns3/drd.c | 365 +++++ > drivers/usb/cdns3/drd.h | 162 +++ > drivers/usb/cdns3/ep0.c | 907 +++++++++++++ > drivers/usb/cdns3/gadget-export.h | 28 + > drivers/usb/cdns3/gadget.c | 2003 ++++++++++++++++++++++++++++ > drivers/usb/cdns3/gadget.h | 1207 +++++++++++++++++ > drivers/usb/cdns3/host-export.h | 28 + > drivers/usb/cdns3/host.c | 72 + > drivers/usb/cdns3/trace.c | 23 + > drivers/usb/cdns3/trace.h | 404 ++++++ > 19 files changed, 6267 insertions(+) > create mode 100644 drivers/usb/cdns3/Kconfig > create mode 100644 drivers/usb/cdns3/Makefile > create mode 100644 drivers/usb/cdns3/cdns3-pci-wrap.c > create mode 100644 drivers/usb/cdns3/core.c > create mode 100644 drivers/usb/cdns3/core.h > create mode 100644 drivers/usb/cdns3/debug.h > create mode 100644 drivers/usb/cdns3/debugfs.c > create mode 100644 drivers/usb/cdns3/drd.c > create mode 100644 drivers/usb/cdns3/drd.h > create mode 100644 drivers/usb/cdns3/ep0.c > create mode 100644 drivers/usb/cdns3/gadget-export.h > create mode 100644 drivers/usb/cdns3/gadget.c > create mode 100644 drivers/usb/cdns3/gadget.h > create mode 100644 drivers/usb/cdns3/host-export.h > create mode 100644 drivers/usb/cdns3/host.c > create mode 100644 drivers/usb/cdns3/trace.c > create mode 100644 drivers/usb/cdns3/trace.h > > diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig > index 987fc5ba6321..5f9334019d04 100644 > --- a/drivers/usb/Kconfig > +++ b/drivers/usb/Kconfig > @@ -112,6 +112,8 @@ source "drivers/usb/usbip/Kconfig" > > endif > > +source "drivers/usb/cdns3/Kconfig" > + > source "drivers/usb/mtu3/Kconfig" > > source "drivers/usb/musb/Kconfig" > diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile > index 7d1b8c82b208..ab125b966cac 100644 > --- a/drivers/usb/Makefile > +++ b/drivers/usb/Makefile > @@ -12,6 +12,8 @@ obj-$(CONFIG_USB_DWC3) += dwc3/ > obj-$(CONFIG_USB_DWC2) += dwc2/ > obj-$(CONFIG_USB_ISP1760) += isp1760/ > > +obj-$(CONFIG_USB_CDNS3) += cdns3/ > + > obj-$(CONFIG_USB_MON) += mon/ > obj-$(CONFIG_USB_MTU3) += mtu3/ > > diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig > new file mode 100644 > index 000000000000..27cb3d8dbe3d > --- /dev/null > +++ b/drivers/usb/cdns3/Kconfig > @@ -0,0 +1,44 @@ > +config USB_CDNS3 > + tristate "Cadence USB3 Dual-Role Controller" > + depends on USB_SUPPORT && (USB || USB_GADGET) && HAS_DMA > + help > + Say Y here if your system has a cadence USB3 dual-role controller. > + It supports: dual-role switch, Host-only, and Peripheral-only. > + > + If you choose to build this driver is a dynamically linked > + as module, the module will be called cdns3.ko. > + > +if USB_CDNS3 > + > +config USB_CDNS3_GADGET > + bool "Cadence USB3 device controller" > + depends on USB_GADGET > + help > + Say Y here to enable device controller functionality of the > + cadence USBSS-DEV driver. "Cadence" ? > + > + This controller supports FF, HS and SS mode. It doesn't support > + LS and SSP mode. > + > +config USB_CDNS3_HOST > + bool "Cadence USB3 host controller" > + depends on USB_XHCI_HCD > + help > + Say Y here to enable host controller functionality of the > + cadence driver. > + > + Host controller is compliant with XHCI so it will use > + standard XHCI driver. > + > +config USB_CDNS3_PCI_WRAP > + tristate "Cadence USB3 support on PCIe-based platforms" > + depends on USB_PCI && ACPI > + default USB_CDNS3 > + help > + If you're using the USBSS Core IP with a PCIe, please say > + 'Y' or 'M' here. > + > + If you choose to build this driver as module it will > + be dynamically linked and module will be called cdns3-pci.ko > + > +endif > diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile > new file mode 100644 > index 000000000000..8f9438593375 > --- /dev/null > +++ b/drivers/usb/cdns3/Makefile > @@ -0,0 +1,14 @@ > +# SPDX-License-Identifier: GPL-2.0 > +# define_trace.h needs to know how to find our header > +CFLAGS_trace.o := -I$(src) > + > +cdns3-y := core.o drd.o trace.o > + > +obj-$(CONFIG_USB_CDNS3) += cdns3.o > +ifneq ($(CONFIG_DEBUG_FS),) > + cdns3-y += debugfs.o > +endif > + > +cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o ep0.o > +cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o > +obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci-wrap.o > diff --git a/drivers/usb/cdns3/cdns3-pci-wrap.c b/drivers/usb/cdns3/cdns3-pci-wrap.c > new file mode 100644 > index 000000000000..d0b2d3d9b983 > --- /dev/null > +++ b/drivers/usb/cdns3/cdns3-pci-wrap.c > @@ -0,0 +1,155 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Cadence USBSS PCI Glue driver > + * > + * Copyright (C) 2018 Cadence. 2018-2019? > + * > + * Author: Pawel Laszczak > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +struct cdns3_wrap { > + struct platform_device *plat_dev; > + struct pci_dev *hg_dev; > + struct resource dev_res[4]; > +}; > + > +struct cdns3_wrap wrap; > + > +#define RES_IRQ_ID 0 > +#define RES_HOST_ID 1 > +#define RES_DEV_ID 2 > +#define RES_DRD_ID 3 > + > +#define PCI_BAR_HOST 0 > +#define PCI_BAR_DEV 2 > +#define PCI_BAR_OTG 4 > + > +#define PCI_DEV_FN_HOST_DEVICE 0 > +#define PCI_DEV_FN_OTG 1 > + > +#define PCI_DRIVER_NAME "cdns3-pci-usbss" > +#define PLAT_DRIVER_NAME "cdns-usb3" > + > +#define CDNS_VENDOR_ID 0x17cd > +#define CDNS_DEVICE_ID 0x0100 > + > +/** > + * cdns3_pci_probe - Probe function for Cadence USB wrapper driver > + * @pdev: platform device object > + * @id: pci device id > + * > + * Returns 0 on success otherwise negative errno > + */ > +static int cdns3_pci_probe(struct pci_dev *pdev, > + const struct pci_device_id *id) > +{ > + struct platform_device_info plat_info; > + struct cdns3_wrap *wrap; > + struct resource *res; > + int err; > + > + /* > + * for GADGET/HOST PCI (devfn) function number is 0, > + * for OTG PCI (devfn) function number is 1 > + */ > + if (!id || pdev->devfn != PCI_DEV_FN_HOST_DEVICE) > + return -EINVAL; > + > + err = pcim_enable_device(pdev); > + if (err) { > + dev_err(&pdev->dev, "Enabling PCI device has failed %d\n", err); > + return err; > + } > + > + pci_set_master(pdev); > + wrap = devm_kzalloc(&pdev->dev, sizeof(*wrap), GFP_KERNEL); > + if (!wrap) { > + dev_err(&pdev->dev, "Failed to allocate memory\n"); > + return -ENOMEM; > + } > + > + /* function 0: host(BAR_0) + device(BAR_1) + otg(BAR_2)). */ > + memset(wrap->dev_res, 0x00, > + sizeof(struct resource) * ARRAY_SIZE(wrap->dev_res)); > + dev_dbg(&pdev->dev, "Initialize Device resources\n"); > + res = wrap->dev_res; > + > + res[RES_DEV_ID].start = pci_resource_start(pdev, PCI_BAR_DEV); > + res[RES_DEV_ID].end = pci_resource_end(pdev, PCI_BAR_DEV); > + res[RES_DEV_ID].name = "dev"; > + res[RES_DEV_ID].flags = IORESOURCE_MEM; > + dev_dbg(&pdev->dev, "USBSS-DEV physical base addr: %pa\n", > + &res[RES_DEV_ID].start); > + > + res[RES_HOST_ID].start = pci_resource_start(pdev, PCI_BAR_HOST); > + res[RES_HOST_ID].end = pci_resource_end(pdev, PCI_BAR_HOST); > + res[RES_HOST_ID].name = "xhci"; > + res[RES_HOST_ID].flags = IORESOURCE_MEM; > + dev_dbg(&pdev->dev, "USBSS-XHCI physical base addr: %pa\n", > + &res[RES_HOST_ID].start); > + > + res[RES_DRD_ID].start = pci_resource_start(pdev, PCI_BAR_OTG); > + res[RES_DRD_ID].end = pci_resource_end(pdev, PCI_BAR_OTG); > + res[RES_DRD_ID].name = "otg"; > + res[RES_DRD_ID].flags = IORESOURCE_MEM; > + dev_dbg(&pdev->dev, "USBSS-DRD physical base addr: %pa\n", > + &res[RES_DRD_ID].start); > + > + /* Interrupt common for both device and XHCI */ > + wrap->dev_res[RES_IRQ_ID].start = pdev->irq; > + wrap->dev_res[RES_IRQ_ID].name = "cdns3-irq"; > + wrap->dev_res[RES_IRQ_ID].flags = IORESOURCE_IRQ; > + > + /* set up platform device info */ > + memset(&plat_info, 0, sizeof(plat_info)); > + plat_info.parent = &pdev->dev; > + plat_info.fwnode = pdev->dev.fwnode; > + plat_info.name = PLAT_DRIVER_NAME; > + plat_info.id = pdev->devfn; > + plat_info.res = wrap->dev_res; > + plat_info.num_res = ARRAY_SIZE(wrap->dev_res); > + plat_info.dma_mask = pdev->dma_mask; > + > + /* register platform device */ > + wrap->plat_dev = platform_device_register_full(&plat_info); > + if (IS_ERR(wrap->plat_dev)) > + return PTR_ERR(wrap->plat_dev); > + > + pci_set_drvdata(pdev, wrap); > + > + return err; > +} > + > +void cdns3_pci_remove(struct pci_dev *pdev) > +{ > + struct cdns3_wrap *wrap = (struct cdns3_wrap *)pci_get_drvdata(pdev); > + > + platform_device_unregister(wrap->plat_dev); > +} > + > +static const struct pci_device_id cdns3_pci_ids[] = { > + { PCI_DEVICE(CDNS_VENDOR_ID, CDNS_DEVICE_ID), }, > + { 0, } > +}; > + > +static struct pci_driver cdns3_pci_driver = { > + .name = PCI_DRIVER_NAME, > + .id_table = cdns3_pci_ids, > + .probe = cdns3_pci_probe, > + .remove = cdns3_pci_remove, > +}; > + > +module_pci_driver(cdns3_pci_driver); > +MODULE_DEVICE_TABLE(pci, cdns3_pci_ids); > + > +MODULE_AUTHOR("Pawel Laszczak "); > +MODULE_LICENSE("GPL v2"); > +MODULE_DESCRIPTION("Cadence USBSS PCI wrapperr"); > + > diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c > new file mode 100644 > index 000000000000..aa2f63241dab > --- /dev/null > +++ b/drivers/usb/cdns3/core.c > @@ -0,0 +1,403 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Cadence USBSS DRD Driver. > + * > + * Copyright (C) 2018 Cadence. > + * Copyright (C) 2017-2018 NXP > + * > + * Author: Peter Chen > + * Pawel Laszczak > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "gadget.h" > +#include "core.h" > +#include "host-export.h" > +#include "gadget-export.h" > +#include "drd.h" > +#include "debug.h" > + > +static inline > +struct cdns3_role_driver *cdns3_get_current_role_driver(struct cdns3 *cdns) > +{ > + WARN_ON(cdns->role >= CDNS3_ROLE_END || !cdns->roles[cdns->role]); > + return cdns->roles[cdns->role]; > +} > + > +static int cdns3_role_start(struct cdns3 *cdns, enum cdns3_roles role) > +{ > + int ret; > + > + if (WARN_ON(role >= CDNS3_ROLE_END)) > + return 0; > + > + if (!cdns->roles[role]) > + return -ENXIO; > + > + if (cdns->roles[role]->state == CDNS3_ROLE_STATE_ACTIVE) > + return 0; > + > + mutex_lock(&cdns->mutex); > + cdns->role = role; > + ret = cdns->roles[role]->start(cdns); > + if (!ret) > + cdns->roles[role]->state = CDNS3_ROLE_STATE_ACTIVE; > + mutex_unlock(&cdns->mutex); > + return ret; > +} > + > +void cdns3_role_stop(struct cdns3 *cdns) > +{ > + enum cdns3_roles role = cdns->role; > + > + if (role >= CDNS3_ROLE_END) { > + WARN_ON(role > CDNS3_ROLE_END); > + return; > + } > + > + if (cdns->roles[role]->state == CDNS3_ROLE_STATE_INACTIVE) > + return; > + > + mutex_lock(&cdns->mutex); > + cdns->roles[role]->stop(cdns); > + cdns->roles[role]->state = CDNS3_ROLE_STATE_INACTIVE; > + mutex_unlock(&cdns->mutex); > +} > + > +/* > + * cdns->role gets from cdns3_get_initial_role, and this API tells role at the > + * runtime. > + * If both roles are supported, the role is selected based on vbus/id. > + * It could be read from OTG register or external connector. > + * If only single role is supported, only one role structure > + * is allocated, cdns->roles[CDNS3_ROLE_HOST] or cdns->roles[CDNS3_ROLE_GADGET]. > + */ > +static enum cdns3_roles cdns3_get_initial_role(struct cdns3 *cdns) > +{ > + if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) { > + if (cdns3_is_host(cdns)) > + return CDNS3_ROLE_HOST; > + if (cdns3_is_device(cdns)) > + return CDNS3_ROLE_GADGET; > + } > + return cdns->roles[CDNS3_ROLE_HOST] > + ? CDNS3_ROLE_HOST > + : CDNS3_ROLE_GADGET; > +} > + > +static void cdns3_exit_roles(struct cdns3 *cdns) > +{ > + cdns3_role_stop(cdns); > + cdns3_drd_exit(cdns); > +} > + > +/** > + * cdns3_core_init_role - initialize role of operation > + * @cdns: Pointer to cdns3 structure > + * > + * Returns 0 on success otherwise negative errno > + */ > +static int cdns3_core_init_role(struct cdns3 *cdns) > +{ > + struct device *dev = cdns->dev; > + enum usb_dr_mode best_dr_mode; > + enum usb_dr_mode dr_mode; > + int ret = 0; > + > + dr_mode = usb_get_dr_mode(dev); > + cdns->role = CDNS3_ROLE_END; > + > + /* > + * If driver can't read mode by means of usb_get_dr_mdoe function then s/mdoe/mode > + * chooses mode according with Kernel configuration. This setting > + * can be restricted later depending on strap pin configuration. > + */ > + if (dr_mode == USB_DR_MODE_UNKNOWN) { > + if (IS_ENABLED(CONFIG_USB_CDNS3_HOST) && > + IS_ENABLED(CONFIG_USB_CDNS3_GADGET)) > + dr_mode = USB_DR_MODE_OTG; > + else if (IS_ENABLED(CONFIG_USB_CDNS3_HOST)) > + dr_mode = USB_DR_MODE_HOST; > + else if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET)) > + dr_mode = USB_DR_MODE_PERIPHERAL; > + } > + > + best_dr_mode = USB_DR_MODE_OTG; Might be worth mentioning that cdns->dr_mode is strap configuration at this point. What exactly are we trying to do here? My guess is that choosen dr_mode can be equal to or subset of strap configuration? Does this work? if (cdns->dr_mode != USB_DR_MODE_OTG) { if (cdns->dr_mode != dr_mode) { dev_err(dev, "Incorrect dr_mode configuration: strap %d: requested %d\n", cdns->dr_mode, dr_mode); } } At this point, dr_mode contains the mode we need to use. > + > + if (dr_mode == USB_DR_MODE_OTG) { > + best_dr_mode = cdns->dr_mode; > + } else if (cdns->dr_mode == USB_DR_MODE_OTG) { > + best_dr_mode = dr_mode; > + } else if (cdns->dr_mode != dr_mode) { > + dev_err(dev, "Incorrect DRD configuration\n"); > + return -EINVAL; > + } > + > + dr_mode = best_dr_mode; > + > + if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { > + ret = cdns3_host_init(cdns); > + if (ret) { > + dev_err(dev, "Host initialization failed with %d\n", > + ret); > + goto err; > + } > + } > + > + if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { > + ret = cdns3_gadget_init(cdns); > + if (ret) { > + dev_err(dev, "Device initialization failed with %d\n", > + ret); > + goto err; > + } > + }> + > + cdns->desired_dr_mode = dr_mode; > + cdns->dr_mode = dr_mode; > + /* > + * dr_mode could be change so DRD must update controller "desired_dr_mode might have changed so we need to update the controller configuration"? > + * configuration > + */ > + ret = cdns3_drd_update_mode(cdns); > + if (ret) > + goto err; > + > + cdns->role = cdns3_get_initial_role(cdns); > + > + ret = cdns3_role_start(cdns, cdns->role); > + if (ret) { > + dev_err(dev, "can't start %s role\n", > + cdns3_get_current_role_driver(cdns)->name); > + goto err; > + } > + > + return ret; > +err: > + cdns3_exit_roles(cdns); > + return ret; > +} > + > +/** > + * cdsn3_get_real_role - get real role of controller based on hardware settings. > + * @cdns: Pointer to cdns3 structure > + * > + * Returns role > + */ > +enum cdns3_roles cdsn3_get_real_role(struct cdns3 *cdns) > +{ > + enum cdns3_roles role = CDNS3_ROLE_END; > + > + if (cdns->current_dr_mode == USB_DR_MODE_OTG) { > + if (cdns3_get_id(cdns)) > + role = CDNS3_ROLE_GADGET; > + else > + role = CDNS3_ROLE_HOST; > + } else { > + if (cdns3_is_host(cdns)) > + role = CDNS3_ROLE_HOST; > + if (cdns3_is_device(cdns)) > + role = CDNS3_ROLE_GADGET; > + } > + > + return role; > +} > + > +/** > + * cdns3_role_switch - work queue handler for role switch > + * > + * @work: work queue item structure > + * > + * Handles below events: > + * - Role switch for dual-role devices > + * - CDNS3_ROLE_GADGET <--> CDNS3_ROLE_END for peripheral-only devices > + */ > +static void cdns3_role_switch(struct work_struct *work) > +{ > + enum cdns3_roles role = CDNS3_ROLE_END; > + struct cdns3_role_driver *role_drv; > + enum cdns3_roles current_role; > + struct cdns3 *cdns; > + int ret = 0; > + > + cdns = container_of(work, struct cdns3, role_switch_wq); > + > + /* During switching cdns->role can be different then role */ s/then/than The comment is a bit misleading. The purpose of this switch function is to do a switch if the role needs to be changed. > + role = cdsn3_get_real_role(cdns); > + > + role_drv = cdns3_get_current_role_driver(cdns); > + > + pm_runtime_get_sync(cdns->dev); pm_runtime_get_sync() must be moved to before cdsn3_get_real_role() as that function accesses a device register. > + > + /* Disable current role. This state can be forced from user space. */ /* Disable current role if requrested from debugfs */? > + if (cdns->debug_disable && role_drv->state == CDNS3_ROLE_STATE_ACTIVE) { > + cdns3_role_stop(cdns); > + goto exit; > + } > + > + /* Do nothing if nothing changed */ > + if (cdns->role == role && role_drv->state == CDNS3_ROLE_STATE_ACTIVE) > + goto exit; > + > + cdns3_role_stop(cdns); > + > + role = cdsn3_get_real_role(cdns); You already did cdns3_get_real_role before. This is redundant. > + > + current_role = cdns->role; > + dev_dbg(cdns->dev, "Switching role"); > + > + ret = cdns3_role_start(cdns, role); > + if (ret) { > + /* Back to current role */ > + dev_err(cdns->dev, "set %d has failed, back to %d\n", > + role, current_role); > + cdns3_role_start(cdns, current_role); Need to check return value here as well? And complain loud if that fails too. > + } > +exit: > + pm_runtime_put_sync(cdns->dev); > +} > + > +/** > + * cdns3_probe - probe for cdns3 core device > + * @pdev: Pointer to cdns3 core platform device > + * > + * Returns 0 on success otherwise negative errno > + */ > +static int cdns3_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct resource *res; > + struct cdns3 *cdns; > + void __iomem *regs; > + int ret; > + > + cdns = devm_kzalloc(dev, sizeof(*cdns), GFP_KERNEL); > + if (!cdns) > + return -ENOMEM; > + > + cdns->dev = dev; > + > + platform_set_drvdata(pdev, cdns); > + > + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); > + if (!res) { > + dev_err(dev, "missing IRQ\n"); > + return -ENODEV; > + } > + cdns->irq = res->start; > + > + cdns->xhci_res[0] = *res; > + > + /* > + * Request memory region > + * region-0: xHCI > + * region-1: Peripheral > + * region-2: OTG registers > + */ > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "xhci"); > + if (!res) > + return -ENXIO; > + > + cdns->xhci_res[1] = *res; > + > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dev"); > + regs = devm_ioremap_resource(dev, res); > + if (IS_ERR(regs)) > + return PTR_ERR(regs); > + cdns->dev_regs = regs; > + > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otg"); > + if (!res) > + return -ENXIO; > + > + cdns->otg_res = *res; > + > + mutex_init(&cdns->mutex); > + > + cdns->phy = devm_phy_optional_get(dev, "cdns3,usbphy"); > + if (IS_ERR(cdns->phy)) > + return PTR_ERR(cdns->phy); > + > + phy_init(cdns->phy); > + > + INIT_WORK(&cdns->role_switch_wq, cdns3_role_switch); > + > + ret = cdns3_drd_init(cdns); > + if (ret) > + goto err; > + > + ret = cdns3_core_init_role(cdns); > + if (ret) > + goto err; > + > + cdns3_debugfs_init(cdns); > + device_set_wakeup_capable(dev, true); > + pm_runtime_set_active(dev); > + pm_runtime_enable(dev); > + > + /* > + * The controller needs less time between bus and controller suspend, > + * and we also needs a small delay to avoid frequently entering low > + * power mode. > + */ > + pm_runtime_set_autosuspend_delay(dev, 20); > + pm_runtime_mark_last_busy(dev); > + pm_runtime_use_autosuspend(dev); > + dev_dbg(dev, "Cadence USB3 core: probe succeed\n"); > + > + return 0; > + > +err: > + phy_exit(cdns->phy); > + return ret; > +} > + > +/** > + * cdns3_remove - unbind drd driver and clean up > + * @pdev: Pointer to Linux platform device > + * > + * Returns 0 on success otherwise negative errno > + */ > +static int cdns3_remove(struct platform_device *pdev) > +{ > + struct cdns3 *cdns = platform_get_drvdata(pdev); > + > + pm_runtime_get_sync(&pdev->dev); > + pm_runtime_disable(&pdev->dev); > + pm_runtime_put_noidle(&pdev->dev); I'm not sure if this is handled right. You are still accessing the device in below cnds3_*() calls. > + cdns3_debugfs_exit(cdns); > + cdns3_exit_roles(cdns);> + phy_exit(cdns->phy); Is the device is in runtime suspended state at this point? > + return 0; > +} > + > +#ifdef CONFIG_OF > +static const struct of_device_id of_cdns3_match[] = { > + { .compatible = "cdns,usb3-1.0.0" }, > + { .compatible = "cdns,usb3-1.0.1" }, > + { }, > +}; > +MODULE_DEVICE_TABLE(of, of_cdns3_match); > +#endif > + > +static struct platform_driver cdns3_driver = { > + .probe = cdns3_probe, > + .remove = cdns3_remove, > + .driver = { > + .name = "cdns-usb3", > + .of_match_table = of_match_ptr(of_cdns3_match), > + }, > +}; > + > +module_platform_driver(cdns3_driver); > + > +MODULE_ALIAS("platform:cdns3"); > +MODULE_AUTHOR("Pawel Laszczak "); > +MODULE_LICENSE("GPL v2"); > +MODULE_DESCRIPTION("Cadence USB3 DRD Controller Driver"); > diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h > new file mode 100644 > index 000000000000..fb4b39206158 > --- /dev/null > +++ b/drivers/usb/cdns3/core.h > @@ -0,0 +1,116 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Cadence USBSS DRD Header File. > + * > + * Copyright (C) 2017-2018 NXP > + * Copyright (C) 2018 Cadence. > + * > + * Authors: Peter Chen > + * Pawel Laszczak > + */ > +#include > + > +#ifndef __LINUX_CDNS3_CORE_H > +#define __LINUX_CDNS3_CORE_H > + > +struct cdns3; > +enum cdns3_roles { > + CDNS3_ROLE_HOST = 0, > + CDNS3_ROLE_GADGET, > + CDNS3_ROLE_END, > +}; > + > +/** > + * struct cdns3_role_driver - host/gadget role driver > + * @start: start this role > + * @stop: stop this role > + * @suspend: suspend callback for this role > + * @resume: resume callback for this role > + * @irq: irq handler for this role > + * @name: role name string (host/gadget) > + * @state: current state > + */ > +struct cdns3_role_driver { > + int (*start)(struct cdns3 *cdns); > + void (*stop)(struct cdns3 *cdns); > + int (*suspend)(struct cdns3 *cdns, bool do_wakeup); > + int (*resume)(struct cdns3 *cdns, bool hibernated); > + const char *name; > +#define CDNS3_ROLE_STATE_INACTIVE 0 > +#define CDNS3_ROLE_STATE_ACTIVE 1 > + int state; > +}; > + > +#define CDNS3_XHCI_RESOURCES_NUM 2 > +/** > + * struct cdns3 - Representation of Cadence USB3 DRD controller. > + * @dev: pointer to Cadence device struct > + * @xhci_regs: pointer to base of xhci registers > + * @xhci_res: the resource for xhci > + * @dev_regs: pointer to base of dev registers > + * @otg_regs: pointer to base of otg registers > + * @irq: irq number for controller > + * @roles: array of supported roles for this controller > + * @role: current role > + * @host_dev: the child host device pointer for cdns3 core > + * @gadget_dev: the child gadget device pointer for cdns3 core > + * @usb: phy for this controller > + * @role_switch_wq: work queue item for role switch > + * @in_lpm: the controller in low power mode > + * @wakeup_int: the wakeup interrupt > + * @mutex: the mutex for concurrent code at driver > + * @dr_mode: supported mode of operation it can be only Host, only Device > + * or OTG mode that allow to switch between Device and Host mode. > + * This field based on firmware setting, kernel configuration > + * and hardware configuration. > + * @current_dr_mode: current mode of operation when in dual-role mode > + * @desired_dr_mode: desired mode of operation when in dual-role mode. > + * This value can be changed during runtime. > + * Available options depends on dr_mode: > + * dr_mode | desired_dr_mode and current_dr_mode > + * ---------------------------------------------------------------- > + * USB_DR_MODE_HOST | only USB_DR_MODE_HOST > + * USB_DR_MODE_PERIPHERAL | only USB_DR_MODE_PERIPHERAL > + * USB_DR_MODE_OTG | only USB_DR_MODE_HOST > + * USB_DR_MODE_OTG | only USB_DR_MODE_PERIPHERAL > + * USB_DR_MODE_OTG | USB_DR_MODE_OTG Last 3 lines should be reduced to USB_DR_MODE_OTG | USB_DR_MODE_OTG, USB_DR_MODE_HOST or | USB_DR_MODE_PERIPHERAL > + * > + * Desired_dr_role can be changed by means of debugfs. > + * @root: debugfs root folder pointer > + * @debug_disable: > + */ > +struct cdns3 { > + struct device *dev; > + void __iomem *xhci_regs; > + struct resource xhci_res[CDNS3_XHCI_RESOURCES_NUM]; > + struct cdns3_usb_regs __iomem *dev_regs; > + > + struct resource otg_res; > + struct cdns3_otg_legacy_regs *otg_v0_regs; > + struct cdns3_otg_regs *otg_v1_regs; > + struct cdns3_otg_common_regs *otg_regs; > +#define CDNS3_CONTROLLER_V0 0 > +#define CDNS3_CONTROLLER_V1 1 > + u32 version; > + > + int irq; > + struct cdns3_role_driver *roles[CDNS3_ROLE_END]; > + enum cdns3_roles role; > + struct platform_device *host_dev; > + struct cdns3_device *gadget_dev; > + struct phy *phy; > + struct work_struct role_switch_wq; > + int in_lpm:1; > + int wakeup_int:1; > + /* mutext used in workqueue*/ > + struct mutex mutex; > + enum usb_dr_mode dr_mode; > + enum usb_dr_mode current_dr_mode; > + enum usb_dr_mode desired_dr_mode; > + struct dentry *root; > + int debug_disable:1; > +}; > + > +void cdns3_role_stop(struct cdns3 *cdns); > + > +#endif /* __LINUX_CDNS3_CORE_H */ > diff --git a/drivers/usb/cdns3/debug.h b/drivers/usb/cdns3/debug.h > new file mode 100644 > index 000000000000..1929edb3a521 > --- /dev/null > +++ b/drivers/usb/cdns3/debug.h > @@ -0,0 +1,168 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Cadence USBSS DRD Driver. > + * Debug header file. > + * > + * Copyright (C) 2018 Cadence. > + * > + * Author: Pawel Laszczak > + */ > +#ifndef __LINUX_CDNS3_DEBUG > +#define __LINUX_CDNS3_DEBUG > + > +#include "core.h" > + > +static inline char *cdns3_decode_usb_irq(char *str, > + enum usb_device_speed speed, > + u32 usb_ists) > +{ > + int ret; > + > + ret = sprintf(str, "IRQ %08x = ", usb_ists); > + > + if (usb_ists & (USB_ISTS_CON2I | USB_ISTS_CONI)) { > + ret += sprintf(str + ret, "Connection %s\n", > + usb_speed_string(speed)); > + } > + if (usb_ists & USB_ISTS_CON2I || usb_ists & USB_ISTS_CONI) > + ret += sprintf(str + ret, "Disconnection "); > + if (usb_ists & USB_ISTS_L2ENTI) > + ret += sprintf(str + ret, "suspended "); > + > + if (usb_ists & USB_ISTS_L2EXTI) > + ret += sprintf(str + ret, "L2 exit "); > + if (usb_ists & USB_ISTS_U3EXTI) > + ret += sprintf(str + ret, "U3 exit "); > + if (usb_ists & USB_ISTS_UWRESI) > + ret += sprintf(str + ret, "Warm Reset "); > + if (usb_ists & USB_ISTS_UHRESI) > + ret += sprintf(str + ret, "Hot Reset "); > + if (usb_ists & USB_ISTS_U2RESI) > + ret += sprintf(str + ret, "Reset"); > + > + return str; > +} > + > +static inline char *cdns3_decode_ep_irq(char *str, > + u32 ep_sts, > + const char *ep_name) > +{ > + int ret; > + > + ret = sprintf(str, "IRQ for %s: %08x ", ep_name, ep_sts); > + > + if (ep_sts & EP_STS_SETUP) > + ret += sprintf(str + ret, "SETUP "); > + if (ep_sts & EP_STS_IOC) > + ret += sprintf(str + ret, "IOC "); > + if (ep_sts & EP_STS_ISP) > + ret += sprintf(str + ret, "ISP "); > + if (ep_sts & EP_STS_DESCMIS) > + ret += sprintf(str + ret, "DESCMIS "); > + if (ep_sts & EP_STS_STREAMR) > + ret += sprintf(str + ret, "STREAMR "); > + if (ep_sts & EP_STS_MD_EXIT) > + ret += sprintf(str + ret, "MD_EXIT "); > + if (ep_sts & EP_STS_TRBERR) > + ret += sprintf(str + ret, "TRBERR "); > + if (ep_sts & EP_STS_NRDY) > + ret += sprintf(str + ret, "NRDY "); > + if (ep_sts & EP_STS_PRIME) > + ret += sprintf(str + ret, "PRIME "); > + if (ep_sts & EP_STS_SIDERR) > + ret += sprintf(str + ret, "SIDERRT "); > + if (ep_sts & EP_STS_OUTSMM) > + ret += sprintf(str + ret, "OUTSMM "); > + if (ep_sts & EP_STS_ISOERR) > + ret += sprintf(str + ret, "ISOERR "); > + if (ep_sts & EP_STS_IOT) > + ret += sprintf(str + ret, "IOT "); > + > + return str; > +} > + > +static inline char *cdns3_decode_epx_irq(char *str, > + char *ep_name, > + u32 ep_sts) > +{ > + return cdns3_decode_ep_irq(str, ep_sts, ep_name); > +} > + > +static inline char *cdns3_decode_ep0_irq(char *str, > + int dir, > + u32 ep_sts) > +{ > + return cdns3_decode_ep_irq(str, ep_sts, > + dir ? "ep0IN" : "ep0OUT"); > +} > + > +/** > + * Debug a transfer ring. > + * > + * Prints out all TRBs in the endpoint ring, even those after the Link TRB. > + *. > + */ > +static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, > + struct cdns3_trb *ring, char *str) > +{ > + dma_addr_t addr = priv_ep->trb_pool_dma; > + struct cdns3_trb *trb; > + int trb_per_sector; > + int ret = 0; > + int i; > + > + trb_per_sector = GET_TRBS_PER_SEGMENT(priv_ep->type); > + > + trb = &priv_ep->trb_pool[priv_ep->dequeue]; > + ret += sprintf(str + ret, "\n\t\tRing contents for %s:", priv_ep->name); > + > + ret += sprintf(str + ret, > + "\n\t\tRing deq index: %d, trb: %p (virt), 0x%llx (dma)\n", > + priv_ep->dequeue, trb, > + (unsigned long long)cdns3_trb_virt_to_dma(priv_ep, trb)); > + > + trb = &priv_ep->trb_pool[priv_ep->enqueue]; > + ret += sprintf(str + ret, > + "\t\tRing enq index: %d, trb: %p (virt), 0x%llx (dma)\n", > + priv_ep->enqueue, trb, > + (unsigned long long)cdns3_trb_virt_to_dma(priv_ep, trb)); > + > + ret += sprintf(str + ret, > + "\t\tfree trbs: %d, CCS=%d, PCS=%d\n", > + priv_ep->free_trbs, priv_ep->ccs, priv_ep->pcs); > + > + if (trb_per_sector > TRBS_PER_SEGMENT) > + trb_per_sector = TRBS_PER_SEGMENT; > + > + if (trb_per_sector > TRBS_PER_SEGMENT) { > + sprintf(str + ret, "\t\tTo big transfer ring %d\n", > + trb_per_sector); > + return str; > + } > + > + for (i = 0; i < trb_per_sector; ++i) { > + trb = &ring[i]; > + ret += sprintf(str + ret, > + "\t\t@%pad %08x %08x %08x\n", &addr, > + le32_to_cpu(trb->buffer), > + le32_to_cpu(trb->length), > + le32_to_cpu(trb->control)); > + addr += sizeof(*trb); > + } > + > + return str; > +} > + > +void cdns3_dbg(struct cdns3_device *priv_dev, const char *fmt, ...); > + > +#ifdef CONFIG_DEBUG_FS > +void cdns3_debugfs_init(struct cdns3 *cdns); > +void cdns3_debugfs_exit(struct cdns3 *cdns); > +#else > +void cdns3_debugfs_init(struct cdns3 *cdns); > +{ } > +void cdns3_debugfs_exit(struct cdns3 *cdns); > +{ } > +#endif > + > +#endif /*__LINUX_CDNS3_DEBUG*/ > diff --git a/drivers/usb/cdns3/debugfs.c b/drivers/usb/cdns3/debugfs.c > new file mode 100644 > index 000000000000..d8fcd90d05b3 > --- /dev/null > +++ b/drivers/usb/cdns3/debugfs.c > @@ -0,0 +1,164 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Cadence USBSS DRD Controller DebugFS filer. > + * > + * Copyright (C) 2018 Cadence. > + * > + * Author: Pawel Laszczak > + */ > + > +#include > +#include > +#include > +#include > + > +#include "core.h" > +#include "gadget.h" > +#include "drd.h" > + > +static int cdns3_mode_show(struct seq_file *s, void *unused) > +{ > + struct cdns3 *cdns = s->private; > + > + switch (cdns->current_dr_mode) { > + case USB_DR_MODE_HOST: > + seq_puts(s, "host\n"); > + break; > + case USB_DR_MODE_PERIPHERAL: > + seq_puts(s, "device\n"); > + break; > + case USB_DR_MODE_OTG: > + seq_puts(s, "otg\n"); > + break; > + default: > + seq_puts(s, "UNKNOWN mode\n"); > + } > + > + return 0; > +} > + > +static int cdns3_mode_open(struct inode *inode, struct file *file) > +{ > + return single_open(file, cdns3_mode_show, inode->i_private); > +} > + > +static ssize_t cdns3_mode_write(struct file *file, > + const char __user *ubuf, > + size_t count, loff_t *ppos) > +{ > + struct seq_file *s = file->private_data; > + struct cdns3 *cdns = s->private; > + u32 mode = USB_DR_MODE_UNKNOWN; > + char buf[32]; > + > + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) > + return -EFAULT; > + > + if (!strncmp(buf, "host", 4)) { > + if (cdns->dr_mode == USB_DR_MODE_HOST || > + cdns->dr_mode == USB_DR_MODE_OTG) { > + mode = USB_DR_MODE_HOST; > + } > + } > + > + if (!strncmp(buf, "device", 6)) > + if (cdns->dr_mode == USB_DR_MODE_PERIPHERAL || > + cdns->dr_mode == USB_DR_MODE_OTG) > + mode = USB_DR_MODE_PERIPHERAL; > + > + if (!strncmp(buf, "otg", 3) && cdns->dr_mode == USB_DR_MODE_OTG) > + mode = USB_DR_MODE_OTG; > + > + if (mode == USB_DR_MODE_UNKNOWN) { > + dev_err(cdns->dev, "Failed: incorrect mode setting\n"); > + return -EFAULT; > + } > + > + if (cdns->current_dr_mode != mode) { > + cdns->desired_dr_mode = mode; > + cdns->debug_disable = 0; Instead of forcing debug_disable here maybe you hould check if it is set and complain that mode can't be changed when debug_disable is set? > + cdns3_role_stop(cdns); > + cdns3_drd_update_mode(cdns); Need to check return value. > + queue_work(system_freezable_wq, &cdns->role_switch_wq); > + } > + > + return count; > +} > + > +static const struct file_operations cdns3_mode_fops = { > + .open = cdns3_mode_open, > + .write = cdns3_mode_write, > + .read = seq_read, > + .llseek = seq_lseek, > + .release = single_release, > +}; > + > +static int cdns3_disable_show(struct seq_file *s, void *unused) > +{ > + struct cdns3 *cdns = s->private; > + > + if (!cdns->debug_disable) > + seq_puts(s, "0\n"); > + else > + seq_puts(s, "1\n"); > + > + return 0; > +} > + > +static ssize_t cdns3_disable_write(struct file *file, > + const char __user *ubuf, > + size_t count, loff_t *ppos) > +{ > + struct seq_file *s = file->private_data; > + struct cdns3 *cdns = s->private; > + bool disable; > + char buf[16]; > + > + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) > + return -EFAULT; > + > + if (kstrtobool(buf, &disable)) { > + dev_err(cdns->dev, "wrong setting\n"); > + return -EINVAL; > + } > + > + if (disable != cdns->debug_disable) { > + cdns->debug_disable = disable; > + queue_work(system_freezable_wq, &cdns->role_switch_wq); What is the purpose of this disable debugfs file? To stop the currently active role? > + } > + > + return count; > +} > + > +static int cdns3_disable_open(struct inode *inode, struct file *file) > +{ > + return single_open(file, cdns3_disable_show, inode->i_private); > +} > + > +static const struct file_operations cdns3_disable_fops = { > + .open = cdns3_disable_open, > + .write = cdns3_disable_write, > + .read = seq_read, > + .llseek = seq_lseek, > + .release = single_release, > +}; > + > +void cdns3_debugfs_init(struct cdns3 *cdns) > +{ > + struct dentry *root; > + > + root = debugfs_create_dir(dev_name(cdns->dev), NULL); > + cdns->root = root; > + if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET) && > + IS_ENABLED(CONFIG_USB_CDNS3_HOST)) > + debugfs_create_file("mode", 0644, root, cdns, > + &cdns3_mode_fops); > + > + debugfs_create_file("disable", 0644, root, cdns, > + &cdns3_disable_fops); > +} > + > +void cdns3_debugfs_exit(struct cdns3 *cdns) > +{ > + debugfs_remove_recursive(cdns->root); > +} > diff --git a/drivers/usb/cdns3/drd.c b/drivers/usb/cdns3/drd.c > new file mode 100644 > index 000000000000..3e56338cd7b9 > --- /dev/null > +++ b/drivers/usb/cdns3/drd.c > @@ -0,0 +1,365 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Cadence USBSS DRD Driver. > + * > + * Copyright (C) 2018 Cadence. > + * > + * Author: Pawel Laszczak + * > + */ > +#include > +#include > +#include > +#include > + > +#include "gadget.h" > +#include "drd.h" > +#include "core.h" > + > +static int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on); > +static int cdns3_drd_switch_host(struct cdns3 *cdns, int on); > + > +/** > + * cdns3_set_mode - change mode of OTG Core > + * @cdns: pointer to context structure > + * @mode: selected mode from cdns_role > + * > + * Returns 0 on success otherwise negative errno > + */ > +int cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode) > +{ > + int ret = 0; > + u32 reg; > + > + cdns->current_dr_mode = mode; > + > + switch (mode) { > + case USB_DR_MODE_PERIPHERAL: > + dev_info(cdns->dev, "Set controller to Gadget mode\n"); dev_dbg()? > + ret = cdns3_drd_switch_gadget(cdns, 1); > + break; > + case USB_DR_MODE_HOST: > + dev_info(cdns->dev, "Set controller to Host mode\n"); dev_dbg() > + ret = cdns3_drd_switch_host(cdns, 1); > + break; > + case USB_DR_MODE_OTG: > + dev_info(cdns->dev, "Set controller to OTG mode\n"); dev_dbg() > + if (cdns->version == CDNS3_CONTROLLER_V1) { > + reg = readl(&cdns->otg_v1_regs->override); > + reg |= OVERRIDE_IDPULLUP; > + writel(reg, &cdns->otg_v1_regs->override); > + } else { > + reg = readl(&cdns->otg_v0_regs->ctrl1); > + reg |= OVERRIDE_IDPULLUP_V0; > + writel(reg, &cdns->otg_v0_regs->ctrl1); > + } > + Don't you have to clear IDPULLUP when you switch to PERIPHERAL or HOST mode? > + /* > + * Hardware specification says: "ID_VALUE must be valid within > + * 50ms after idpullup is set to '1" so driver must wait > + * 50ms before reading this pin. > + */ > + usleep_range(50000, 60000); > + break; > + default: > + cdns->current_dr_mode = USB_DR_MODE_UNKNOWN; > + dev_err(cdns->dev, "Unsupported mode of operation %d\n", mode); > + return -EINVAL; > + } > + > + return ret; > +} > + > +int cdns3_get_id(struct cdns3 *cdns) > +{ > + int id; > + > + id = readl(&cdns->otg_regs->sts) & OTGSTS_ID_VALUE; > + dev_dbg(cdns->dev, "OTG ID: %d", id); > + return id; > +} > + > +int cdns3_is_host(struct cdns3 *cdns) > +{ > + if (cdns->current_dr_mode == USB_DR_MODE_HOST) > + return 1; don't you have to return 0 if current_dr_mode == USB_DR_MODE_PERIPHERAL? > + else if (!cdns3_get_id(cdns)) > + return 1; > + > + return 0; > +} > + > +int cdns3_is_device(struct cdns3 *cdns) > +{ > + if (cdns->current_dr_mode == USB_DR_MODE_PERIPHERAL) > + return 1; don't you have to return 0 if current_dr_mode == USB_DR_MODE_HOST? > + else if (cdns->current_dr_mode == USB_DR_MODE_OTG) > + if (cdns3_get_id(cdns)) > + return 1; > + > + return 0; > +} > + > +/** > + * cdns3_otg_disable_irq - Disable all OTG interrupts > + * @cdns: Pointer to controller context structure > + */ > +static void cdns3_otg_disable_irq(struct cdns3 *cdns) > +{ > + writel(0, &cdns->otg_regs->ien); > +} > + > +/** > + * cdns3_otg_enable_irq - enable id and sess_valid interrupts > + * @cdns: Pointer to controller context structure > + */ > +static void cdns3_otg_enable_irq(struct cdns3 *cdns) > +{ > + writel(OTGIEN_ID_CHANGE_INT | OTGIEN_VBUSVALID_RISE_INT | > + OTGIEN_VBUSVALID_FALL_INT, &cdns->otg_regs->ien); > +} > + > +/** > + * cdns3_drd_switch_host - start/stop host > + * @cdns: Pointer to controller context structure > + * @on: 1 for start, 0 for stop > + * > + * Returns 0 on success otherwise negative errno > + */ > +static int cdns3_drd_switch_host(struct cdns3 *cdns, int on) > +{ > + int ret; > + u32 reg = OTGCMD_OTG_DIS; > + > + /* switch OTG core */ > + if (on) { > + writel(OTGCMD_HOST_BUS_REQ | reg, &cdns->otg_regs->cmd); > + > + dev_dbg(cdns->dev, "Waiting for Host mode is turned on\n"); s/for/till > + ret = cdns3_handshake(&cdns->otg_regs->sts, OTGSTS_XHCI_READY, > + OTGSTS_XHCI_READY, 100000); > + > + if (ret) > + return ret; > + } else { > + usleep_range(30, 40); > + writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP | > + OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF, > + &cdns->otg_regs->cmd); > + usleep_range(3000, 4000); why do you need delays before and after the write? > + } > + > + return 0; > +} > + > +/** > + * cdns3_drd_switch_gadget - start/stop gadget > + * @cdns: Pointer to controller context structure > + * @on: 1 for start, 0 for stop > + * > + * Returns 0 on success otherwise negative errno > + */ > +static int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on) > +{ > + int ret; > + u32 reg = OTGCMD_OTG_DIS; > + > + /* switch OTG core */ > + if (on) { > + writel(OTGCMD_DEV_BUS_REQ | reg, &cdns->otg_regs->cmd); > + > + dev_dbg(cdns->dev, "Waiting for Device mode is turned on\n"); s/for/till > + > + ret = cdns3_handshake(&cdns->otg_regs->sts, OTGSTS_DEV_READY, > + OTGSTS_DEV_READY, 100000); > + > + if (ret) > + return ret; > + } else { > + /* > + * driver should wait at least 10us after disabling Device > + * before turning-off Device (DEV_BUS_DROP) > + */ > + usleep_range(20, 30); > + writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP | > + OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF, > + &cdns->otg_regs->cmd); > + usleep_range(3000, 4000); why do you need a delay after the write? > + } > + > + return 0; > +} > + > +/** > + * cdns3_init_otg_mode - initialize drd controller > + * @cdns: Pointer to controller context structure > + * > + * Returns 0 on success otherwise negative errno > + */ > +static int cdns3_init_otg_mode(struct cdns3 *cdns) > +{ > + int ret = 0; > + > + cdns3_otg_disable_irq(cdns); > + /* clear all interrupts */ > + writel(~0, &cdns->otg_regs->ivect); > + > + ret = cdns3_set_mode(cdns, USB_DR_MODE_OTG); > + if (ret) > + return ret; > + > + if (cdns3_is_host(cdns)) > + ret = cdns3_drd_switch_host(cdns, 1); > + else > + ret = cdns3_drd_switch_gadget(cdns, 1); > + > + if (ret) > + return ret; > + > + cdns3_otg_enable_irq(cdns); Schedule switch workqueue to deal with updated ID state? > + return ret; > +} > + > +/** > + * cdns3_drd_update_mode - initialize mode of operation > + * @cdns: Pointer to controller context structure > + * > + * Returns 0 on success otherwise negative errno > + */ > +int cdns3_drd_update_mode(struct cdns3 *cdns) > +{ > + int ret = 0; > + > + if (cdns->desired_dr_mode == cdns->current_dr_mode) > + return ret; > + > + cdns3_drd_switch_gadget(cdns, 0); > + cdns3_drd_switch_host(cdns, 0); Why are you stopping gadget/host here? One or both of might not have been started. > + > + switch (cdns->desired_dr_mode) { > + case USB_DR_MODE_PERIPHERAL: > + ret = cdns3_set_mode(cdns, USB_DR_MODE_PERIPHERAL); > + break; > + case USB_DR_MODE_HOST: > + ret = cdns3_set_mode(cdns, USB_DR_MODE_HOST); > + break; > + case USB_DR_MODE_OTG: > + ret = cdns3_init_otg_mode(cdns); > + break; > + default: > + dev_err(cdns->dev, "Unsupported mode of operation %d\n", > + cdns->dr_mode); > + return -EINVAL; > + } > + > + return ret; > +} > + > +/** > + * cdns3_drd_irq - interrupt handler for OTG events > + * > + * @irq: irq number for cdns3 core device > + * @data: structure of cdns3 > + * > + * Returns IRQ_HANDLED or IRQ_NONE > + */ > +static irqreturn_t cdns3_drd_irq(int irq, void *data) > +{ > + irqreturn_t ret = IRQ_NONE; > + struct cdns3 *cdns = data; > + u32 reg; > + > + if (cdns->dr_mode != USB_DR_MODE_OTG) > + return ret; > + > + reg = readl(&cdns->otg_regs->ivect); > + > + if (!reg) > + return ret; > + > + if (reg & OTGIEN_ID_CHANGE_INT) { > + dev_dbg(cdns->dev, "OTG IRQ: new ID: %d\n", > + cdns3_get_id(cdns)); > + > + queue_work(system_freezable_wq, &cdns->role_switch_wq); > + > + ret = IRQ_HANDLED; > + } > + > + writel(~0, &cdns->otg_regs->ivect); > + return ret; > +} > + > +int cdns3_drd_init(struct cdns3 *cdns) > +{ > + void __iomem *regs; > + int ret = 0; > + u32 state; > + > + regs = devm_ioremap_resource(cdns->dev, &cdns->otg_res); > + if (IS_ERR(regs)) > + return PTR_ERR(regs); > + > + /* Detection of DRD version. Controller has been released > + * in two versions. Both are similar, but they have same changes > + * in register maps. > + * The first register in old version is command register and it's read > + * only, so driver should read 0 from it. On the other hand, in v1 > + * the first register contains device ID number which is not set to 0. > + * Driver uses this fact to detect the proper version of > + * controller. > + */ > + cdns->otg_v0_regs = regs; > + if (!readl(&cdns->otg_v0_regs->cmd)) { > + cdns->version = CDNS3_CONTROLLER_V0; > + cdns->otg_v1_regs = NULL; > + cdns->otg_regs = regs; > + dev_info(cdns->dev, "DRD version v0 (%08x)\n", > + readl(&cdns->otg_v0_regs->version)); > + } else { > + cdns->otg_v0_regs = NULL; > + cdns->otg_v1_regs = regs; > + cdns->otg_regs = (void *)&cdns->otg_v1_regs->cmd; > + cdns->version = CDNS3_CONTROLLER_V1; > + dev_info(cdns->dev, "DRD version v1 (ID: %08x, rev: %08x)\n", > + readl(&cdns->otg_v1_regs->did), > + readl(&cdns->otg_v1_regs->rid)); > + } > + > + state = OTGSTS_STRAP(readl(&cdns->otg_regs->sts)); > + > + /* Update dr_mode according to STRAP configuration. */ > + cdns->dr_mode = USB_DR_MODE_OTG; > + if (state == OTGSTS_STRAP_HOST) { > + dev_info(cdns->dev, "Controller strapped to HOST\n"); > + cdns->dr_mode = USB_DR_MODE_HOST; > + } else if (state == OTGSTS_STRAP_GADGET) { > + dev_info(cdns->dev, "Controller strapped to PERIPHERAL\n"); > + cdns->dr_mode = USB_DR_MODE_PERIPHERAL; > + } > + > + cdns->desired_dr_mode = cdns->dr_mode; > + cdns->current_dr_mode = USB_DR_MODE_UNKNOWN; > + > + ret = devm_request_threaded_irq(cdns->dev, cdns->irq, cdns3_drd_irq, > + NULL, IRQF_SHARED, > + dev_name(cdns->dev), cdns); > + > + if (ret) > + return ret; > + > + state = readl(&cdns->otg_regs->sts); > + if (OTGSTS_OTG_NRDY(state) != 0) { > + dev_err(cdns->dev, "Cadence USB3 OTG device not ready\n"); > + return -ENODEV; > + } > + > + ret = cdns3_drd_update_mode(cdns); > + > + return ret; > +} > + > +int cdns3_drd_exit(struct cdns3 *cdns) > +{ > + return cdns3_drd_switch_host(cdns, 0); Why only stopping host? I think we need to stop active role, disable IRQ generation and free irq? > +} > diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c > new file mode 100644 > index 000000000000..7f7f24ee3c4b > --- /dev/null > +++ b/drivers/usb/cdns3/gadget.c > @@ -0,0 +1,2003 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Cadence USBSS DRD Driver - gadget side. > + * > + * Copyright (C) 2018 Cadence Design Systems. > + * Copyright (C) 2017-2018 NXP > + * > + * Authors: Pawel Jez , > + * Pawel Laszczak > + * Peter Chen > + */ > + > + > +static void cdns3_gadget_disable(struct cdns3 *cdns) > +{ > + struct cdns3_device *priv_dev; > + > + priv_dev = cdns->gadget_dev; > + > + if (priv_dev->gadget_driver) > + priv_dev->gadget_driver->disconnect(&priv_dev->gadget);> + > + usb_gadget_disconnect(&priv_dev->gadget); > + priv_dev->gadget.speed = USB_SPEED_UNKNOWN; > +} > + > +void cdns3_gadget_exit(struct cdns3 *cdns) > +{ > + struct cdns3_device *priv_dev; > + > + priv_dev = cdns->gadget_dev; > + > + cdns3_gadget_disable(cdns); > + > + devm_free_irq(cdns->dev, cdns->irq, cdns); > + > + pm_runtime_mark_last_busy(cdns->dev); > + pm_runtime_put_autosuspend(cdns->dev); > + > + usb_del_gadget_udc(&priv_dev->gadget); > + > + cdns3_free_all_eps(priv_dev); > + > + dma_free_coherent(priv_dev->sysdev, 8, priv_dev->setup_buf, > + priv_dev->setup_dma); > + > + kfree(priv_dev->zlp_buf); > + kfree(priv_dev); > + cdns->gadget_dev = NULL; > +} > + > +static int cdns3_gadget_start(struct cdns3 *cdns) > +{ > + struct cdns3_device *priv_dev; > + u32 max_speed; > + int ret; > + > + priv_dev = kzalloc(sizeof(*priv_dev), GFP_KERNEL); > + if (!priv_dev) > + return -ENOMEM; > + > + cdns->gadget_dev = priv_dev; > + priv_dev->sysdev = cdns->dev; > + priv_dev->dev = cdns->dev; > + priv_dev->regs = cdns->dev_regs; > + > + max_speed = usb_get_maximum_speed(cdns->dev); > + > + /* Check the maximum_speed parameter */ > + switch (max_speed) { > + case USB_SPEED_FULL: > + case USB_SPEED_HIGH: > + case USB_SPEED_SUPER: > + break; > + default: > + dev_err(cdns->dev, "invalid maximum_speed parameter %d\n", > + max_speed); > + /* fall through */ > + case USB_SPEED_UNKNOWN: > + /* default to superspeed */ > + max_speed = USB_SPEED_SUPER; > + break; > + } > + > + /* fill gadget fields */ > + priv_dev->gadget.max_speed = max_speed; > + priv_dev->gadget.speed = USB_SPEED_UNKNOWN; > + priv_dev->gadget.ops = &cdns3_gadget_ops; > + priv_dev->gadget.name = "usb-ss-gadget"; > + priv_dev->gadget.sg_supported = 1; > + > + spin_lock_init(&priv_dev->lock); > + INIT_WORK(&priv_dev->pending_status_wq, > + cdns3_pending_setup_status_handler); > + > + /* initialize endpoint container */ > + INIT_LIST_HEAD(&priv_dev->gadget.ep_list); > + > + ret = cdns3_init_eps(priv_dev); > + if (ret) { > + dev_err(priv_dev->dev, "Failed to create endpoints\n"); > + goto err1; > + } > + > + /* allocate memory for setup packet buffer */ > + priv_dev->setup_buf = dma_alloc_coherent(priv_dev->sysdev, 8, > + &priv_dev->setup_dma, GFP_DMA); > + if (!priv_dev->setup_buf) { > + dev_err(priv_dev->dev, "Failed to allocate memory for SETUP buffer\n"); > + ret = -ENOMEM; > + goto err2; > + } > + > + priv_dev->dev_ver = readl(&priv_dev->regs->usb_cap6); > + dev_dbg(priv_dev->dev, "Device Controller version: %08x\n", > + readl(&priv_dev->regs->usb_cap6)); > + dev_dbg(priv_dev->dev, "USB Capabilities:: %08x\n", > + readl(&priv_dev->regs->usb_cap1)); > + dev_dbg(priv_dev->dev, "On-Chip memory cnfiguration: %08x\n", > + readl(&priv_dev->regs->usb_cap2)); > + > + priv_dev->zlp_buf = kzalloc(CDNS3_EP_ZLP_BUF_SIZE, GFP_KERNEL); > + if (!priv_dev->zlp_buf) { > + ret = -ENOMEM; > + goto err3; > + } > + > + /* add USB gadget device */ > + ret = usb_add_gadget_udc(priv_dev->dev, &priv_dev->gadget); > + if (ret < 0) { > + dev_err(priv_dev->dev, > + "Failed to register USB device controller\n"); > + goto err4; > + } > + > + return 0; > +err4: > + kfree(priv_dev->zlp_buf); > +err3: > + dma_free_coherent(priv_dev->sysdev, 8, priv_dev->setup_buf, > + priv_dev->setup_dma); > +err2: > + cdns3_free_all_eps(priv_dev); > +err1: > + cdns->gadget_dev = NULL; > + return ret; > +} > + > +static int __cdns3_gadget_init(struct cdns3 *cdns) > +{ > + struct cdns3_device *priv_dev; > + unsigned long flags; > + int ret = 0; > + > + ret = cdns3_gadget_start(cdns); > + if (ret) > + return ret; > + > + priv_dev = cdns->gadget_dev; > + ret = devm_request_threaded_irq(cdns->dev, cdns->irq, > + cdns3_device_irq_handler, > + cdns3_device_thread_irq_handler, > + IRQF_SHARED, dev_name(cdns->dev), cdns); > + if (ret) > + goto err0; > + > + pm_runtime_get_sync(cdns->dev); pm_runtime_get_sync() should be done before cdns3_gadget_start() > + spin_lock_irqsave(&priv_dev->lock, flags); > + spin_unlock_irqrestore(&priv_dev->lock, flags); Redundant spinlock usage? > + return 0; > +err0: > + cdns3_gadget_exit(cdns); > + return ret; > +} > + > +static int cdns3_gadget_suspend(struct cdns3 *cdns, bool do_wakeup) > +{ > + cdns3_gadget_disable(cdns); Does this ensure gadget controller is stopped? > + return 0; > +} > + > +static int cdns3_gadget_resume(struct cdns3 *cdns, bool hibernated) > +{ > + struct cdns3_device *priv_dev; > + unsigned long flags; > + > + priv_dev = cdns->gadget_dev; > + spin_lock_irqsave(&priv_dev->lock, flags); > + > + if (!priv_dev->gadget_driver) { > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return 0; > + } > + > + cdns3_gadget_config(priv_dev); > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return 0; > +} > + > +/** > + * cdns3_gadget_init - initialize device structure > + * > + * cdns: cdns3 instance > + * > + * This function initializes the gadget. > + */ > +int cdns3_gadget_init(struct cdns3 *cdns) > +{ > + struct cdns3_role_driver *rdrv; > + > + rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL); > + if (!rdrv) > + return -ENOMEM; > + > + rdrv->start = __cdns3_gadget_init; > + rdrv->stop = cdns3_gadget_exit; > + rdrv->suspend = cdns3_gadget_suspend; > + rdrv->resume = cdns3_gadget_resume; > + rdrv->state = CDNS3_ROLE_STATE_INACTIVE; > + rdrv->name = "gadget"; > + cdns->roles[CDNS3_ROLE_GADGET] = rdrv; > + > + return 0; > +} -- cheers, -roger Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki From mboxrd@z Thu Jan 1 00:00:00 1970 From: Roger Quadros Subject: Re: [PATCH v4 5/6] usb:cdns3 Add Cadence USB3 DRD Driver Date: Wed, 20 Feb 2019 15:04:53 +0200 Message-ID: <3af305e0-40bf-28cc-48d5-4afa241e7899@ti.com> References: <1550173514-23573-1-git-send-email-pawell@cadence.com> <1550173514-23573-6-git-send-email-pawell@cadence.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1550173514-23573-6-git-send-email-pawell@cadence.com> Content-Language: en-GB Sender: linux-kernel-owner@vger.kernel.org To: Pawel Laszczak , devicetree@vger.kernel.org Cc: gregkh@linuxfoundation.org, felipe.balbi@linux.intel.com, mark.rutland@arm.com, linux-usb@vger.kernel.org, hdegoede@redhat.com, heikki.krogerus@linux.intel.com, andy.shevchenko@gmail.com, robh+dt@kernel.org, linux-kernel@vger.kernel.org, jbergsagel@ti.com, nsekhar@ti.com, nm@ti.com, sureshp@cadence.com, peter.chen@nxp.com, kurahul@cadence.com List-Id: devicetree@vger.kernel.org Pawel, On 14/02/2019 21:45, Pawel Laszczak wrote: > This patch introduce new Cadence USBSS DRD driver to linux kernel. > > The Cadence USBSS DRD Driver is a highly configurable IP Core whichi > can be instantiated as Dual-Role Device (DRD), Peripheral Only and > Host Only (XHCI)configurations. > > The current driver has been validated with FPGA burned. We have support > for PCIe bus, which is used on FPGA prototyping. > > The host side of USBSS-DRD controller is compliance with XHCI > specification, so it works with standard XHCI linux driver. > > Signed-off-by: Pawel Laszczak > --- > drivers/usb/Kconfig | 2 + > drivers/usb/Makefile | 2 + > drivers/usb/cdns3/Kconfig | 44 + > drivers/usb/cdns3/Makefile | 14 + > drivers/usb/cdns3/cdns3-pci-wrap.c | 155 +++ > drivers/usb/cdns3/core.c | 403 ++++++ > drivers/usb/cdns3/core.h | 116 ++ > drivers/usb/cdns3/debug.h | 168 +++ > drivers/usb/cdns3/debugfs.c | 164 +++ > drivers/usb/cdns3/drd.c | 365 +++++ > drivers/usb/cdns3/drd.h | 162 +++ > drivers/usb/cdns3/ep0.c | 907 +++++++++++++ > drivers/usb/cdns3/gadget-export.h | 28 + > drivers/usb/cdns3/gadget.c | 2003 ++++++++++++++++++++++++++++ > drivers/usb/cdns3/gadget.h | 1207 +++++++++++++++++ > drivers/usb/cdns3/host-export.h | 28 + > drivers/usb/cdns3/host.c | 72 + > drivers/usb/cdns3/trace.c | 23 + > drivers/usb/cdns3/trace.h | 404 ++++++ > 19 files changed, 6267 insertions(+) > create mode 100644 drivers/usb/cdns3/Kconfig > create mode 100644 drivers/usb/cdns3/Makefile > create mode 100644 drivers/usb/cdns3/cdns3-pci-wrap.c > create mode 100644 drivers/usb/cdns3/core.c > create mode 100644 drivers/usb/cdns3/core.h > create mode 100644 drivers/usb/cdns3/debug.h > create mode 100644 drivers/usb/cdns3/debugfs.c > create mode 100644 drivers/usb/cdns3/drd.c > create mode 100644 drivers/usb/cdns3/drd.h > create mode 100644 drivers/usb/cdns3/ep0.c > create mode 100644 drivers/usb/cdns3/gadget-export.h > create mode 100644 drivers/usb/cdns3/gadget.c > create mode 100644 drivers/usb/cdns3/gadget.h > create mode 100644 drivers/usb/cdns3/host-export.h > create mode 100644 drivers/usb/cdns3/host.c > create mode 100644 drivers/usb/cdns3/trace.c > create mode 100644 drivers/usb/cdns3/trace.h > > diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig > index 987fc5ba6321..5f9334019d04 100644 > --- a/drivers/usb/Kconfig > +++ b/drivers/usb/Kconfig > @@ -112,6 +112,8 @@ source "drivers/usb/usbip/Kconfig" > > endif > > +source "drivers/usb/cdns3/Kconfig" > + > source "drivers/usb/mtu3/Kconfig" > > source "drivers/usb/musb/Kconfig" > diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile > index 7d1b8c82b208..ab125b966cac 100644 > --- a/drivers/usb/Makefile > +++ b/drivers/usb/Makefile > @@ -12,6 +12,8 @@ obj-$(CONFIG_USB_DWC3) += dwc3/ > obj-$(CONFIG_USB_DWC2) += dwc2/ > obj-$(CONFIG_USB_ISP1760) += isp1760/ > > +obj-$(CONFIG_USB_CDNS3) += cdns3/ > + > obj-$(CONFIG_USB_MON) += mon/ > obj-$(CONFIG_USB_MTU3) += mtu3/ > > diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig > new file mode 100644 > index 000000000000..27cb3d8dbe3d > --- /dev/null > +++ b/drivers/usb/cdns3/Kconfig > @@ -0,0 +1,44 @@ > +config USB_CDNS3 > + tristate "Cadence USB3 Dual-Role Controller" > + depends on USB_SUPPORT && (USB || USB_GADGET) && HAS_DMA > + help > + Say Y here if your system has a cadence USB3 dual-role controller. > + It supports: dual-role switch, Host-only, and Peripheral-only. > + > + If you choose to build this driver is a dynamically linked > + as module, the module will be called cdns3.ko. > + > +if USB_CDNS3 > + > +config USB_CDNS3_GADGET > + bool "Cadence USB3 device controller" > + depends on USB_GADGET > + help > + Say Y here to enable device controller functionality of the > + cadence USBSS-DEV driver. "Cadence" ? > + > + This controller supports FF, HS and SS mode. It doesn't support > + LS and SSP mode. > + > +config USB_CDNS3_HOST > + bool "Cadence USB3 host controller" > + depends on USB_XHCI_HCD > + help > + Say Y here to enable host controller functionality of the > + cadence driver. > + > + Host controller is compliant with XHCI so it will use > + standard XHCI driver. > + > +config USB_CDNS3_PCI_WRAP > + tristate "Cadence USB3 support on PCIe-based platforms" > + depends on USB_PCI && ACPI > + default USB_CDNS3 > + help > + If you're using the USBSS Core IP with a PCIe, please say > + 'Y' or 'M' here. > + > + If you choose to build this driver as module it will > + be dynamically linked and module will be called cdns3-pci.ko > + > +endif > diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile > new file mode 100644 > index 000000000000..8f9438593375 > --- /dev/null > +++ b/drivers/usb/cdns3/Makefile > @@ -0,0 +1,14 @@ > +# SPDX-License-Identifier: GPL-2.0 > +# define_trace.h needs to know how to find our header > +CFLAGS_trace.o := -I$(src) > + > +cdns3-y := core.o drd.o trace.o > + > +obj-$(CONFIG_USB_CDNS3) += cdns3.o > +ifneq ($(CONFIG_DEBUG_FS),) > + cdns3-y += debugfs.o > +endif > + > +cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o ep0.o > +cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o > +obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci-wrap.o > diff --git a/drivers/usb/cdns3/cdns3-pci-wrap.c b/drivers/usb/cdns3/cdns3-pci-wrap.c > new file mode 100644 > index 000000000000..d0b2d3d9b983 > --- /dev/null > +++ b/drivers/usb/cdns3/cdns3-pci-wrap.c > @@ -0,0 +1,155 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Cadence USBSS PCI Glue driver > + * > + * Copyright (C) 2018 Cadence. 2018-2019? > + * > + * Author: Pawel Laszczak > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +struct cdns3_wrap { > + struct platform_device *plat_dev; > + struct pci_dev *hg_dev; > + struct resource dev_res[4]; > +}; > + > +struct cdns3_wrap wrap; > + > +#define RES_IRQ_ID 0 > +#define RES_HOST_ID 1 > +#define RES_DEV_ID 2 > +#define RES_DRD_ID 3 > + > +#define PCI_BAR_HOST 0 > +#define PCI_BAR_DEV 2 > +#define PCI_BAR_OTG 4 > + > +#define PCI_DEV_FN_HOST_DEVICE 0 > +#define PCI_DEV_FN_OTG 1 > + > +#define PCI_DRIVER_NAME "cdns3-pci-usbss" > +#define PLAT_DRIVER_NAME "cdns-usb3" > + > +#define CDNS_VENDOR_ID 0x17cd > +#define CDNS_DEVICE_ID 0x0100 > + > +/** > + * cdns3_pci_probe - Probe function for Cadence USB wrapper driver > + * @pdev: platform device object > + * @id: pci device id > + * > + * Returns 0 on success otherwise negative errno > + */ > +static int cdns3_pci_probe(struct pci_dev *pdev, > + const struct pci_device_id *id) > +{ > + struct platform_device_info plat_info; > + struct cdns3_wrap *wrap; > + struct resource *res; > + int err; > + > + /* > + * for GADGET/HOST PCI (devfn) function number is 0, > + * for OTG PCI (devfn) function number is 1 > + */ > + if (!id || pdev->devfn != PCI_DEV_FN_HOST_DEVICE) > + return -EINVAL; > + > + err = pcim_enable_device(pdev); > + if (err) { > + dev_err(&pdev->dev, "Enabling PCI device has failed %d\n", err); > + return err; > + } > + > + pci_set_master(pdev); > + wrap = devm_kzalloc(&pdev->dev, sizeof(*wrap), GFP_KERNEL); > + if (!wrap) { > + dev_err(&pdev->dev, "Failed to allocate memory\n"); > + return -ENOMEM; > + } > + > + /* function 0: host(BAR_0) + device(BAR_1) + otg(BAR_2)). */ > + memset(wrap->dev_res, 0x00, > + sizeof(struct resource) * ARRAY_SIZE(wrap->dev_res)); > + dev_dbg(&pdev->dev, "Initialize Device resources\n"); > + res = wrap->dev_res; > + > + res[RES_DEV_ID].start = pci_resource_start(pdev, PCI_BAR_DEV); > + res[RES_DEV_ID].end = pci_resource_end(pdev, PCI_BAR_DEV); > + res[RES_DEV_ID].name = "dev"; > + res[RES_DEV_ID].flags = IORESOURCE_MEM; > + dev_dbg(&pdev->dev, "USBSS-DEV physical base addr: %pa\n", > + &res[RES_DEV_ID].start); > + > + res[RES_HOST_ID].start = pci_resource_start(pdev, PCI_BAR_HOST); > + res[RES_HOST_ID].end = pci_resource_end(pdev, PCI_BAR_HOST); > + res[RES_HOST_ID].name = "xhci"; > + res[RES_HOST_ID].flags = IORESOURCE_MEM; > + dev_dbg(&pdev->dev, "USBSS-XHCI physical base addr: %pa\n", > + &res[RES_HOST_ID].start); > + > + res[RES_DRD_ID].start = pci_resource_start(pdev, PCI_BAR_OTG); > + res[RES_DRD_ID].end = pci_resource_end(pdev, PCI_BAR_OTG); > + res[RES_DRD_ID].name = "otg"; > + res[RES_DRD_ID].flags = IORESOURCE_MEM; > + dev_dbg(&pdev->dev, "USBSS-DRD physical base addr: %pa\n", > + &res[RES_DRD_ID].start); > + > + /* Interrupt common for both device and XHCI */ > + wrap->dev_res[RES_IRQ_ID].start = pdev->irq; > + wrap->dev_res[RES_IRQ_ID].name = "cdns3-irq"; > + wrap->dev_res[RES_IRQ_ID].flags = IORESOURCE_IRQ; > + > + /* set up platform device info */ > + memset(&plat_info, 0, sizeof(plat_info)); > + plat_info.parent = &pdev->dev; > + plat_info.fwnode = pdev->dev.fwnode; > + plat_info.name = PLAT_DRIVER_NAME; > + plat_info.id = pdev->devfn; > + plat_info.res = wrap->dev_res; > + plat_info.num_res = ARRAY_SIZE(wrap->dev_res); > + plat_info.dma_mask = pdev->dma_mask; > + > + /* register platform device */ > + wrap->plat_dev = platform_device_register_full(&plat_info); > + if (IS_ERR(wrap->plat_dev)) > + return PTR_ERR(wrap->plat_dev); > + > + pci_set_drvdata(pdev, wrap); > + > + return err; > +} > + > +void cdns3_pci_remove(struct pci_dev *pdev) > +{ > + struct cdns3_wrap *wrap = (struct cdns3_wrap *)pci_get_drvdata(pdev); > + > + platform_device_unregister(wrap->plat_dev); > +} > + > +static const struct pci_device_id cdns3_pci_ids[] = { > + { PCI_DEVICE(CDNS_VENDOR_ID, CDNS_DEVICE_ID), }, > + { 0, } > +}; > + > +static struct pci_driver cdns3_pci_driver = { > + .name = PCI_DRIVER_NAME, > + .id_table = cdns3_pci_ids, > + .probe = cdns3_pci_probe, > + .remove = cdns3_pci_remove, > +}; > + > +module_pci_driver(cdns3_pci_driver); > +MODULE_DEVICE_TABLE(pci, cdns3_pci_ids); > + > +MODULE_AUTHOR("Pawel Laszczak "); > +MODULE_LICENSE("GPL v2"); > +MODULE_DESCRIPTION("Cadence USBSS PCI wrapperr"); > + > diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c > new file mode 100644 > index 000000000000..aa2f63241dab > --- /dev/null > +++ b/drivers/usb/cdns3/core.c > @@ -0,0 +1,403 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Cadence USBSS DRD Driver. > + * > + * Copyright (C) 2018 Cadence. > + * Copyright (C) 2017-2018 NXP > + * > + * Author: Peter Chen > + * Pawel Laszczak > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "gadget.h" > +#include "core.h" > +#include "host-export.h" > +#include "gadget-export.h" > +#include "drd.h" > +#include "debug.h" > + > +static inline > +struct cdns3_role_driver *cdns3_get_current_role_driver(struct cdns3 *cdns) > +{ > + WARN_ON(cdns->role >= CDNS3_ROLE_END || !cdns->roles[cdns->role]); > + return cdns->roles[cdns->role]; > +} > + > +static int cdns3_role_start(struct cdns3 *cdns, enum cdns3_roles role) > +{ > + int ret; > + > + if (WARN_ON(role >= CDNS3_ROLE_END)) > + return 0; > + > + if (!cdns->roles[role]) > + return -ENXIO; > + > + if (cdns->roles[role]->state == CDNS3_ROLE_STATE_ACTIVE) > + return 0; > + > + mutex_lock(&cdns->mutex); > + cdns->role = role; > + ret = cdns->roles[role]->start(cdns); > + if (!ret) > + cdns->roles[role]->state = CDNS3_ROLE_STATE_ACTIVE; > + mutex_unlock(&cdns->mutex); > + return ret; > +} > + > +void cdns3_role_stop(struct cdns3 *cdns) > +{ > + enum cdns3_roles role = cdns->role; > + > + if (role >= CDNS3_ROLE_END) { > + WARN_ON(role > CDNS3_ROLE_END); > + return; > + } > + > + if (cdns->roles[role]->state == CDNS3_ROLE_STATE_INACTIVE) > + return; > + > + mutex_lock(&cdns->mutex); > + cdns->roles[role]->stop(cdns); > + cdns->roles[role]->state = CDNS3_ROLE_STATE_INACTIVE; > + mutex_unlock(&cdns->mutex); > +} > + > +/* > + * cdns->role gets from cdns3_get_initial_role, and this API tells role at the > + * runtime. > + * If both roles are supported, the role is selected based on vbus/id. > + * It could be read from OTG register or external connector. > + * If only single role is supported, only one role structure > + * is allocated, cdns->roles[CDNS3_ROLE_HOST] or cdns->roles[CDNS3_ROLE_GADGET]. > + */ > +static enum cdns3_roles cdns3_get_initial_role(struct cdns3 *cdns) > +{ > + if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) { > + if (cdns3_is_host(cdns)) > + return CDNS3_ROLE_HOST; > + if (cdns3_is_device(cdns)) > + return CDNS3_ROLE_GADGET; > + } > + return cdns->roles[CDNS3_ROLE_HOST] > + ? CDNS3_ROLE_HOST > + : CDNS3_ROLE_GADGET; > +} > + > +static void cdns3_exit_roles(struct cdns3 *cdns) > +{ > + cdns3_role_stop(cdns); > + cdns3_drd_exit(cdns); > +} > + > +/** > + * cdns3_core_init_role - initialize role of operation > + * @cdns: Pointer to cdns3 structure > + * > + * Returns 0 on success otherwise negative errno > + */ > +static int cdns3_core_init_role(struct cdns3 *cdns) > +{ > + struct device *dev = cdns->dev; > + enum usb_dr_mode best_dr_mode; > + enum usb_dr_mode dr_mode; > + int ret = 0; > + > + dr_mode = usb_get_dr_mode(dev); > + cdns->role = CDNS3_ROLE_END; > + > + /* > + * If driver can't read mode by means of usb_get_dr_mdoe function then s/mdoe/mode > + * chooses mode according with Kernel configuration. This setting > + * can be restricted later depending on strap pin configuration. > + */ > + if (dr_mode == USB_DR_MODE_UNKNOWN) { > + if (IS_ENABLED(CONFIG_USB_CDNS3_HOST) && > + IS_ENABLED(CONFIG_USB_CDNS3_GADGET)) > + dr_mode = USB_DR_MODE_OTG; > + else if (IS_ENABLED(CONFIG_USB_CDNS3_HOST)) > + dr_mode = USB_DR_MODE_HOST; > + else if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET)) > + dr_mode = USB_DR_MODE_PERIPHERAL; > + } > + > + best_dr_mode = USB_DR_MODE_OTG; Might be worth mentioning that cdns->dr_mode is strap configuration at this point. What exactly are we trying to do here? My guess is that choosen dr_mode can be equal to or subset of strap configuration? Does this work? if (cdns->dr_mode != USB_DR_MODE_OTG) { if (cdns->dr_mode != dr_mode) { dev_err(dev, "Incorrect dr_mode configuration: strap %d: requested %d\n", cdns->dr_mode, dr_mode); } } At this point, dr_mode contains the mode we need to use. > + > + if (dr_mode == USB_DR_MODE_OTG) { > + best_dr_mode = cdns->dr_mode; > + } else if (cdns->dr_mode == USB_DR_MODE_OTG) { > + best_dr_mode = dr_mode; > + } else if (cdns->dr_mode != dr_mode) { > + dev_err(dev, "Incorrect DRD configuration\n"); > + return -EINVAL; > + } > + > + dr_mode = best_dr_mode; > + > + if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { > + ret = cdns3_host_init(cdns); > + if (ret) { > + dev_err(dev, "Host initialization failed with %d\n", > + ret); > + goto err; > + } > + } > + > + if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { > + ret = cdns3_gadget_init(cdns); > + if (ret) { > + dev_err(dev, "Device initialization failed with %d\n", > + ret); > + goto err; > + } > + }> + > + cdns->desired_dr_mode = dr_mode; > + cdns->dr_mode = dr_mode; > + /* > + * dr_mode could be change so DRD must update controller "desired_dr_mode might have changed so we need to update the controller configuration"? > + * configuration > + */ > + ret = cdns3_drd_update_mode(cdns); > + if (ret) > + goto err; > + > + cdns->role = cdns3_get_initial_role(cdns); > + > + ret = cdns3_role_start(cdns, cdns->role); > + if (ret) { > + dev_err(dev, "can't start %s role\n", > + cdns3_get_current_role_driver(cdns)->name); > + goto err; > + } > + > + return ret; > +err: > + cdns3_exit_roles(cdns); > + return ret; > +} > + > +/** > + * cdsn3_get_real_role - get real role of controller based on hardware settings. > + * @cdns: Pointer to cdns3 structure > + * > + * Returns role > + */ > +enum cdns3_roles cdsn3_get_real_role(struct cdns3 *cdns) > +{ > + enum cdns3_roles role = CDNS3_ROLE_END; > + > + if (cdns->current_dr_mode == USB_DR_MODE_OTG) { > + if (cdns3_get_id(cdns)) > + role = CDNS3_ROLE_GADGET; > + else > + role = CDNS3_ROLE_HOST; > + } else { > + if (cdns3_is_host(cdns)) > + role = CDNS3_ROLE_HOST; > + if (cdns3_is_device(cdns)) > + role = CDNS3_ROLE_GADGET; > + } > + > + return role; > +} > + > +/** > + * cdns3_role_switch - work queue handler for role switch > + * > + * @work: work queue item structure > + * > + * Handles below events: > + * - Role switch for dual-role devices > + * - CDNS3_ROLE_GADGET <--> CDNS3_ROLE_END for peripheral-only devices > + */ > +static void cdns3_role_switch(struct work_struct *work) > +{ > + enum cdns3_roles role = CDNS3_ROLE_END; > + struct cdns3_role_driver *role_drv; > + enum cdns3_roles current_role; > + struct cdns3 *cdns; > + int ret = 0; > + > + cdns = container_of(work, struct cdns3, role_switch_wq); > + > + /* During switching cdns->role can be different then role */ s/then/than The comment is a bit misleading. The purpose of this switch function is to do a switch if the role needs to be changed. > + role = cdsn3_get_real_role(cdns); > + > + role_drv = cdns3_get_current_role_driver(cdns); > + > + pm_runtime_get_sync(cdns->dev); pm_runtime_get_sync() must be moved to before cdsn3_get_real_role() as that function accesses a device register. > + > + /* Disable current role. This state can be forced from user space. */ /* Disable current role if requrested from debugfs */? > + if (cdns->debug_disable && role_drv->state == CDNS3_ROLE_STATE_ACTIVE) { > + cdns3_role_stop(cdns); > + goto exit; > + } > + > + /* Do nothing if nothing changed */ > + if (cdns->role == role && role_drv->state == CDNS3_ROLE_STATE_ACTIVE) > + goto exit; > + > + cdns3_role_stop(cdns); > + > + role = cdsn3_get_real_role(cdns); You already did cdns3_get_real_role before. This is redundant. > + > + current_role = cdns->role; > + dev_dbg(cdns->dev, "Switching role"); > + > + ret = cdns3_role_start(cdns, role); > + if (ret) { > + /* Back to current role */ > + dev_err(cdns->dev, "set %d has failed, back to %d\n", > + role, current_role); > + cdns3_role_start(cdns, current_role); Need to check return value here as well? And complain loud if that fails too. > + } > +exit: > + pm_runtime_put_sync(cdns->dev); > +} > + > +/** > + * cdns3_probe - probe for cdns3 core device > + * @pdev: Pointer to cdns3 core platform device > + * > + * Returns 0 on success otherwise negative errno > + */ > +static int cdns3_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct resource *res; > + struct cdns3 *cdns; > + void __iomem *regs; > + int ret; > + > + cdns = devm_kzalloc(dev, sizeof(*cdns), GFP_KERNEL); > + if (!cdns) > + return -ENOMEM; > + > + cdns->dev = dev; > + > + platform_set_drvdata(pdev, cdns); > + > + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); > + if (!res) { > + dev_err(dev, "missing IRQ\n"); > + return -ENODEV; > + } > + cdns->irq = res->start; > + > + cdns->xhci_res[0] = *res; > + > + /* > + * Request memory region > + * region-0: xHCI > + * region-1: Peripheral > + * region-2: OTG registers > + */ > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "xhci"); > + if (!res) > + return -ENXIO; > + > + cdns->xhci_res[1] = *res; > + > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dev"); > + regs = devm_ioremap_resource(dev, res); > + if (IS_ERR(regs)) > + return PTR_ERR(regs); > + cdns->dev_regs = regs; > + > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otg"); > + if (!res) > + return -ENXIO; > + > + cdns->otg_res = *res; > + > + mutex_init(&cdns->mutex); > + > + cdns->phy = devm_phy_optional_get(dev, "cdns3,usbphy"); > + if (IS_ERR(cdns->phy)) > + return PTR_ERR(cdns->phy); > + > + phy_init(cdns->phy); > + > + INIT_WORK(&cdns->role_switch_wq, cdns3_role_switch); > + > + ret = cdns3_drd_init(cdns); > + if (ret) > + goto err; > + > + ret = cdns3_core_init_role(cdns); > + if (ret) > + goto err; > + > + cdns3_debugfs_init(cdns); > + device_set_wakeup_capable(dev, true); > + pm_runtime_set_active(dev); > + pm_runtime_enable(dev); > + > + /* > + * The controller needs less time between bus and controller suspend, > + * and we also needs a small delay to avoid frequently entering low > + * power mode. > + */ > + pm_runtime_set_autosuspend_delay(dev, 20); > + pm_runtime_mark_last_busy(dev); > + pm_runtime_use_autosuspend(dev); > + dev_dbg(dev, "Cadence USB3 core: probe succeed\n"); > + > + return 0; > + > +err: > + phy_exit(cdns->phy); > + return ret; > +} > + > +/** > + * cdns3_remove - unbind drd driver and clean up > + * @pdev: Pointer to Linux platform device > + * > + * Returns 0 on success otherwise negative errno > + */ > +static int cdns3_remove(struct platform_device *pdev) > +{ > + struct cdns3 *cdns = platform_get_drvdata(pdev); > + > + pm_runtime_get_sync(&pdev->dev); > + pm_runtime_disable(&pdev->dev); > + pm_runtime_put_noidle(&pdev->dev); I'm not sure if this is handled right. You are still accessing the device in below cnds3_*() calls. > + cdns3_debugfs_exit(cdns); > + cdns3_exit_roles(cdns);> + phy_exit(cdns->phy); Is the device is in runtime suspended state at this point? > + return 0; > +} > + > +#ifdef CONFIG_OF > +static const struct of_device_id of_cdns3_match[] = { > + { .compatible = "cdns,usb3-1.0.0" }, > + { .compatible = "cdns,usb3-1.0.1" }, > + { }, > +}; > +MODULE_DEVICE_TABLE(of, of_cdns3_match); > +#endif > + > +static struct platform_driver cdns3_driver = { > + .probe = cdns3_probe, > + .remove = cdns3_remove, > + .driver = { > + .name = "cdns-usb3", > + .of_match_table = of_match_ptr(of_cdns3_match), > + }, > +}; > + > +module_platform_driver(cdns3_driver); > + > +MODULE_ALIAS("platform:cdns3"); > +MODULE_AUTHOR("Pawel Laszczak "); > +MODULE_LICENSE("GPL v2"); > +MODULE_DESCRIPTION("Cadence USB3 DRD Controller Driver"); > diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h > new file mode 100644 > index 000000000000..fb4b39206158 > --- /dev/null > +++ b/drivers/usb/cdns3/core.h > @@ -0,0 +1,116 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Cadence USBSS DRD Header File. > + * > + * Copyright (C) 2017-2018 NXP > + * Copyright (C) 2018 Cadence. > + * > + * Authors: Peter Chen > + * Pawel Laszczak > + */ > +#include > + > +#ifndef __LINUX_CDNS3_CORE_H > +#define __LINUX_CDNS3_CORE_H > + > +struct cdns3; > +enum cdns3_roles { > + CDNS3_ROLE_HOST = 0, > + CDNS3_ROLE_GADGET, > + CDNS3_ROLE_END, > +}; > + > +/** > + * struct cdns3_role_driver - host/gadget role driver > + * @start: start this role > + * @stop: stop this role > + * @suspend: suspend callback for this role > + * @resume: resume callback for this role > + * @irq: irq handler for this role > + * @name: role name string (host/gadget) > + * @state: current state > + */ > +struct cdns3_role_driver { > + int (*start)(struct cdns3 *cdns); > + void (*stop)(struct cdns3 *cdns); > + int (*suspend)(struct cdns3 *cdns, bool do_wakeup); > + int (*resume)(struct cdns3 *cdns, bool hibernated); > + const char *name; > +#define CDNS3_ROLE_STATE_INACTIVE 0 > +#define CDNS3_ROLE_STATE_ACTIVE 1 > + int state; > +}; > + > +#define CDNS3_XHCI_RESOURCES_NUM 2 > +/** > + * struct cdns3 - Representation of Cadence USB3 DRD controller. > + * @dev: pointer to Cadence device struct > + * @xhci_regs: pointer to base of xhci registers > + * @xhci_res: the resource for xhci > + * @dev_regs: pointer to base of dev registers > + * @otg_regs: pointer to base of otg registers > + * @irq: irq number for controller > + * @roles: array of supported roles for this controller > + * @role: current role > + * @host_dev: the child host device pointer for cdns3 core > + * @gadget_dev: the child gadget device pointer for cdns3 core > + * @usb: phy for this controller > + * @role_switch_wq: work queue item for role switch > + * @in_lpm: the controller in low power mode > + * @wakeup_int: the wakeup interrupt > + * @mutex: the mutex for concurrent code at driver > + * @dr_mode: supported mode of operation it can be only Host, only Device > + * or OTG mode that allow to switch between Device and Host mode. > + * This field based on firmware setting, kernel configuration > + * and hardware configuration. > + * @current_dr_mode: current mode of operation when in dual-role mode > + * @desired_dr_mode: desired mode of operation when in dual-role mode. > + * This value can be changed during runtime. > + * Available options depends on dr_mode: > + * dr_mode | desired_dr_mode and current_dr_mode > + * ---------------------------------------------------------------- > + * USB_DR_MODE_HOST | only USB_DR_MODE_HOST > + * USB_DR_MODE_PERIPHERAL | only USB_DR_MODE_PERIPHERAL > + * USB_DR_MODE_OTG | only USB_DR_MODE_HOST > + * USB_DR_MODE_OTG | only USB_DR_MODE_PERIPHERAL > + * USB_DR_MODE_OTG | USB_DR_MODE_OTG Last 3 lines should be reduced to USB_DR_MODE_OTG | USB_DR_MODE_OTG, USB_DR_MODE_HOST or | USB_DR_MODE_PERIPHERAL > + * > + * Desired_dr_role can be changed by means of debugfs. > + * @root: debugfs root folder pointer > + * @debug_disable: > + */ > +struct cdns3 { > + struct device *dev; > + void __iomem *xhci_regs; > + struct resource xhci_res[CDNS3_XHCI_RESOURCES_NUM]; > + struct cdns3_usb_regs __iomem *dev_regs; > + > + struct resource otg_res; > + struct cdns3_otg_legacy_regs *otg_v0_regs; > + struct cdns3_otg_regs *otg_v1_regs; > + struct cdns3_otg_common_regs *otg_regs; > +#define CDNS3_CONTROLLER_V0 0 > +#define CDNS3_CONTROLLER_V1 1 > + u32 version; > + > + int irq; > + struct cdns3_role_driver *roles[CDNS3_ROLE_END]; > + enum cdns3_roles role; > + struct platform_device *host_dev; > + struct cdns3_device *gadget_dev; > + struct phy *phy; > + struct work_struct role_switch_wq; > + int in_lpm:1; > + int wakeup_int:1; > + /* mutext used in workqueue*/ > + struct mutex mutex; > + enum usb_dr_mode dr_mode; > + enum usb_dr_mode current_dr_mode; > + enum usb_dr_mode desired_dr_mode; > + struct dentry *root; > + int debug_disable:1; > +}; > + > +void cdns3_role_stop(struct cdns3 *cdns); > + > +#endif /* __LINUX_CDNS3_CORE_H */ > diff --git a/drivers/usb/cdns3/debug.h b/drivers/usb/cdns3/debug.h > new file mode 100644 > index 000000000000..1929edb3a521 > --- /dev/null > +++ b/drivers/usb/cdns3/debug.h > @@ -0,0 +1,168 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Cadence USBSS DRD Driver. > + * Debug header file. > + * > + * Copyright (C) 2018 Cadence. > + * > + * Author: Pawel Laszczak > + */ > +#ifndef __LINUX_CDNS3_DEBUG > +#define __LINUX_CDNS3_DEBUG > + > +#include "core.h" > + > +static inline char *cdns3_decode_usb_irq(char *str, > + enum usb_device_speed speed, > + u32 usb_ists) > +{ > + int ret; > + > + ret = sprintf(str, "IRQ %08x = ", usb_ists); > + > + if (usb_ists & (USB_ISTS_CON2I | USB_ISTS_CONI)) { > + ret += sprintf(str + ret, "Connection %s\n", > + usb_speed_string(speed)); > + } > + if (usb_ists & USB_ISTS_CON2I || usb_ists & USB_ISTS_CONI) > + ret += sprintf(str + ret, "Disconnection "); > + if (usb_ists & USB_ISTS_L2ENTI) > + ret += sprintf(str + ret, "suspended "); > + > + if (usb_ists & USB_ISTS_L2EXTI) > + ret += sprintf(str + ret, "L2 exit "); > + if (usb_ists & USB_ISTS_U3EXTI) > + ret += sprintf(str + ret, "U3 exit "); > + if (usb_ists & USB_ISTS_UWRESI) > + ret += sprintf(str + ret, "Warm Reset "); > + if (usb_ists & USB_ISTS_UHRESI) > + ret += sprintf(str + ret, "Hot Reset "); > + if (usb_ists & USB_ISTS_U2RESI) > + ret += sprintf(str + ret, "Reset"); > + > + return str; > +} > + > +static inline char *cdns3_decode_ep_irq(char *str, > + u32 ep_sts, > + const char *ep_name) > +{ > + int ret; > + > + ret = sprintf(str, "IRQ for %s: %08x ", ep_name, ep_sts); > + > + if (ep_sts & EP_STS_SETUP) > + ret += sprintf(str + ret, "SETUP "); > + if (ep_sts & EP_STS_IOC) > + ret += sprintf(str + ret, "IOC "); > + if (ep_sts & EP_STS_ISP) > + ret += sprintf(str + ret, "ISP "); > + if (ep_sts & EP_STS_DESCMIS) > + ret += sprintf(str + ret, "DESCMIS "); > + if (ep_sts & EP_STS_STREAMR) > + ret += sprintf(str + ret, "STREAMR "); > + if (ep_sts & EP_STS_MD_EXIT) > + ret += sprintf(str + ret, "MD_EXIT "); > + if (ep_sts & EP_STS_TRBERR) > + ret += sprintf(str + ret, "TRBERR "); > + if (ep_sts & EP_STS_NRDY) > + ret += sprintf(str + ret, "NRDY "); > + if (ep_sts & EP_STS_PRIME) > + ret += sprintf(str + ret, "PRIME "); > + if (ep_sts & EP_STS_SIDERR) > + ret += sprintf(str + ret, "SIDERRT "); > + if (ep_sts & EP_STS_OUTSMM) > + ret += sprintf(str + ret, "OUTSMM "); > + if (ep_sts & EP_STS_ISOERR) > + ret += sprintf(str + ret, "ISOERR "); > + if (ep_sts & EP_STS_IOT) > + ret += sprintf(str + ret, "IOT "); > + > + return str; > +} > + > +static inline char *cdns3_decode_epx_irq(char *str, > + char *ep_name, > + u32 ep_sts) > +{ > + return cdns3_decode_ep_irq(str, ep_sts, ep_name); > +} > + > +static inline char *cdns3_decode_ep0_irq(char *str, > + int dir, > + u32 ep_sts) > +{ > + return cdns3_decode_ep_irq(str, ep_sts, > + dir ? "ep0IN" : "ep0OUT"); > +} > + > +/** > + * Debug a transfer ring. > + * > + * Prints out all TRBs in the endpoint ring, even those after the Link TRB. > + *. > + */ > +static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, > + struct cdns3_trb *ring, char *str) > +{ > + dma_addr_t addr = priv_ep->trb_pool_dma; > + struct cdns3_trb *trb; > + int trb_per_sector; > + int ret = 0; > + int i; > + > + trb_per_sector = GET_TRBS_PER_SEGMENT(priv_ep->type); > + > + trb = &priv_ep->trb_pool[priv_ep->dequeue]; > + ret += sprintf(str + ret, "\n\t\tRing contents for %s:", priv_ep->name); > + > + ret += sprintf(str + ret, > + "\n\t\tRing deq index: %d, trb: %p (virt), 0x%llx (dma)\n", > + priv_ep->dequeue, trb, > + (unsigned long long)cdns3_trb_virt_to_dma(priv_ep, trb)); > + > + trb = &priv_ep->trb_pool[priv_ep->enqueue]; > + ret += sprintf(str + ret, > + "\t\tRing enq index: %d, trb: %p (virt), 0x%llx (dma)\n", > + priv_ep->enqueue, trb, > + (unsigned long long)cdns3_trb_virt_to_dma(priv_ep, trb)); > + > + ret += sprintf(str + ret, > + "\t\tfree trbs: %d, CCS=%d, PCS=%d\n", > + priv_ep->free_trbs, priv_ep->ccs, priv_ep->pcs); > + > + if (trb_per_sector > TRBS_PER_SEGMENT) > + trb_per_sector = TRBS_PER_SEGMENT; > + > + if (trb_per_sector > TRBS_PER_SEGMENT) { > + sprintf(str + ret, "\t\tTo big transfer ring %d\n", > + trb_per_sector); > + return str; > + } > + > + for (i = 0; i < trb_per_sector; ++i) { > + trb = &ring[i]; > + ret += sprintf(str + ret, > + "\t\t@%pad %08x %08x %08x\n", &addr, > + le32_to_cpu(trb->buffer), > + le32_to_cpu(trb->length), > + le32_to_cpu(trb->control)); > + addr += sizeof(*trb); > + } > + > + return str; > +} > + > +void cdns3_dbg(struct cdns3_device *priv_dev, const char *fmt, ...); > + > +#ifdef CONFIG_DEBUG_FS > +void cdns3_debugfs_init(struct cdns3 *cdns); > +void cdns3_debugfs_exit(struct cdns3 *cdns); > +#else > +void cdns3_debugfs_init(struct cdns3 *cdns); > +{ } > +void cdns3_debugfs_exit(struct cdns3 *cdns); > +{ } > +#endif > + > +#endif /*__LINUX_CDNS3_DEBUG*/ > diff --git a/drivers/usb/cdns3/debugfs.c b/drivers/usb/cdns3/debugfs.c > new file mode 100644 > index 000000000000..d8fcd90d05b3 > --- /dev/null > +++ b/drivers/usb/cdns3/debugfs.c > @@ -0,0 +1,164 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Cadence USBSS DRD Controller DebugFS filer. > + * > + * Copyright (C) 2018 Cadence. > + * > + * Author: Pawel Laszczak > + */ > + > +#include > +#include > +#include > +#include > + > +#include "core.h" > +#include "gadget.h" > +#include "drd.h" > + > +static int cdns3_mode_show(struct seq_file *s, void *unused) > +{ > + struct cdns3 *cdns = s->private; > + > + switch (cdns->current_dr_mode) { > + case USB_DR_MODE_HOST: > + seq_puts(s, "host\n"); > + break; > + case USB_DR_MODE_PERIPHERAL: > + seq_puts(s, "device\n"); > + break; > + case USB_DR_MODE_OTG: > + seq_puts(s, "otg\n"); > + break; > + default: > + seq_puts(s, "UNKNOWN mode\n"); > + } > + > + return 0; > +} > + > +static int cdns3_mode_open(struct inode *inode, struct file *file) > +{ > + return single_open(file, cdns3_mode_show, inode->i_private); > +} > + > +static ssize_t cdns3_mode_write(struct file *file, > + const char __user *ubuf, > + size_t count, loff_t *ppos) > +{ > + struct seq_file *s = file->private_data; > + struct cdns3 *cdns = s->private; > + u32 mode = USB_DR_MODE_UNKNOWN; > + char buf[32]; > + > + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) > + return -EFAULT; > + > + if (!strncmp(buf, "host", 4)) { > + if (cdns->dr_mode == USB_DR_MODE_HOST || > + cdns->dr_mode == USB_DR_MODE_OTG) { > + mode = USB_DR_MODE_HOST; > + } > + } > + > + if (!strncmp(buf, "device", 6)) > + if (cdns->dr_mode == USB_DR_MODE_PERIPHERAL || > + cdns->dr_mode == USB_DR_MODE_OTG) > + mode = USB_DR_MODE_PERIPHERAL; > + > + if (!strncmp(buf, "otg", 3) && cdns->dr_mode == USB_DR_MODE_OTG) > + mode = USB_DR_MODE_OTG; > + > + if (mode == USB_DR_MODE_UNKNOWN) { > + dev_err(cdns->dev, "Failed: incorrect mode setting\n"); > + return -EFAULT; > + } > + > + if (cdns->current_dr_mode != mode) { > + cdns->desired_dr_mode = mode; > + cdns->debug_disable = 0; Instead of forcing debug_disable here maybe you hould check if it is set and complain that mode can't be changed when debug_disable is set? > + cdns3_role_stop(cdns); > + cdns3_drd_update_mode(cdns); Need to check return value. > + queue_work(system_freezable_wq, &cdns->role_switch_wq); > + } > + > + return count; > +} > + > +static const struct file_operations cdns3_mode_fops = { > + .open = cdns3_mode_open, > + .write = cdns3_mode_write, > + .read = seq_read, > + .llseek = seq_lseek, > + .release = single_release, > +}; > + > +static int cdns3_disable_show(struct seq_file *s, void *unused) > +{ > + struct cdns3 *cdns = s->private; > + > + if (!cdns->debug_disable) > + seq_puts(s, "0\n"); > + else > + seq_puts(s, "1\n"); > + > + return 0; > +} > + > +static ssize_t cdns3_disable_write(struct file *file, > + const char __user *ubuf, > + size_t count, loff_t *ppos) > +{ > + struct seq_file *s = file->private_data; > + struct cdns3 *cdns = s->private; > + bool disable; > + char buf[16]; > + > + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) > + return -EFAULT; > + > + if (kstrtobool(buf, &disable)) { > + dev_err(cdns->dev, "wrong setting\n"); > + return -EINVAL; > + } > + > + if (disable != cdns->debug_disable) { > + cdns->debug_disable = disable; > + queue_work(system_freezable_wq, &cdns->role_switch_wq); What is the purpose of this disable debugfs file? To stop the currently active role? > + } > + > + return count; > +} > + > +static int cdns3_disable_open(struct inode *inode, struct file *file) > +{ > + return single_open(file, cdns3_disable_show, inode->i_private); > +} > + > +static const struct file_operations cdns3_disable_fops = { > + .open = cdns3_disable_open, > + .write = cdns3_disable_write, > + .read = seq_read, > + .llseek = seq_lseek, > + .release = single_release, > +}; > + > +void cdns3_debugfs_init(struct cdns3 *cdns) > +{ > + struct dentry *root; > + > + root = debugfs_create_dir(dev_name(cdns->dev), NULL); > + cdns->root = root; > + if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET) && > + IS_ENABLED(CONFIG_USB_CDNS3_HOST)) > + debugfs_create_file("mode", 0644, root, cdns, > + &cdns3_mode_fops); > + > + debugfs_create_file("disable", 0644, root, cdns, > + &cdns3_disable_fops); > +} > + > +void cdns3_debugfs_exit(struct cdns3 *cdns) > +{ > + debugfs_remove_recursive(cdns->root); > +} > diff --git a/drivers/usb/cdns3/drd.c b/drivers/usb/cdns3/drd.c > new file mode 100644 > index 000000000000..3e56338cd7b9 > --- /dev/null > +++ b/drivers/usb/cdns3/drd.c > @@ -0,0 +1,365 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Cadence USBSS DRD Driver. > + * > + * Copyright (C) 2018 Cadence. > + * > + * Author: Pawel Laszczak + * > + */ > +#include > +#include > +#include > +#include > + > +#include "gadget.h" > +#include "drd.h" > +#include "core.h" > + > +static int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on); > +static int cdns3_drd_switch_host(struct cdns3 *cdns, int on); > + > +/** > + * cdns3_set_mode - change mode of OTG Core > + * @cdns: pointer to context structure > + * @mode: selected mode from cdns_role > + * > + * Returns 0 on success otherwise negative errno > + */ > +int cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode) > +{ > + int ret = 0; > + u32 reg; > + > + cdns->current_dr_mode = mode; > + > + switch (mode) { > + case USB_DR_MODE_PERIPHERAL: > + dev_info(cdns->dev, "Set controller to Gadget mode\n"); dev_dbg()? > + ret = cdns3_drd_switch_gadget(cdns, 1); > + break; > + case USB_DR_MODE_HOST: > + dev_info(cdns->dev, "Set controller to Host mode\n"); dev_dbg() > + ret = cdns3_drd_switch_host(cdns, 1); > + break; > + case USB_DR_MODE_OTG: > + dev_info(cdns->dev, "Set controller to OTG mode\n"); dev_dbg() > + if (cdns->version == CDNS3_CONTROLLER_V1) { > + reg = readl(&cdns->otg_v1_regs->override); > + reg |= OVERRIDE_IDPULLUP; > + writel(reg, &cdns->otg_v1_regs->override); > + } else { > + reg = readl(&cdns->otg_v0_regs->ctrl1); > + reg |= OVERRIDE_IDPULLUP_V0; > + writel(reg, &cdns->otg_v0_regs->ctrl1); > + } > + Don't you have to clear IDPULLUP when you switch to PERIPHERAL or HOST mode? > + /* > + * Hardware specification says: "ID_VALUE must be valid within > + * 50ms after idpullup is set to '1" so driver must wait > + * 50ms before reading this pin. > + */ > + usleep_range(50000, 60000); > + break; > + default: > + cdns->current_dr_mode = USB_DR_MODE_UNKNOWN; > + dev_err(cdns->dev, "Unsupported mode of operation %d\n", mode); > + return -EINVAL; > + } > + > + return ret; > +} > + > +int cdns3_get_id(struct cdns3 *cdns) > +{ > + int id; > + > + id = readl(&cdns->otg_regs->sts) & OTGSTS_ID_VALUE; > + dev_dbg(cdns->dev, "OTG ID: %d", id); > + return id; > +} > + > +int cdns3_is_host(struct cdns3 *cdns) > +{ > + if (cdns->current_dr_mode == USB_DR_MODE_HOST) > + return 1; don't you have to return 0 if current_dr_mode == USB_DR_MODE_PERIPHERAL? > + else if (!cdns3_get_id(cdns)) > + return 1; > + > + return 0; > +} > + > +int cdns3_is_device(struct cdns3 *cdns) > +{ > + if (cdns->current_dr_mode == USB_DR_MODE_PERIPHERAL) > + return 1; don't you have to return 0 if current_dr_mode == USB_DR_MODE_HOST? > + else if (cdns->current_dr_mode == USB_DR_MODE_OTG) > + if (cdns3_get_id(cdns)) > + return 1; > + > + return 0; > +} > + > +/** > + * cdns3_otg_disable_irq - Disable all OTG interrupts > + * @cdns: Pointer to controller context structure > + */ > +static void cdns3_otg_disable_irq(struct cdns3 *cdns) > +{ > + writel(0, &cdns->otg_regs->ien); > +} > + > +/** > + * cdns3_otg_enable_irq - enable id and sess_valid interrupts > + * @cdns: Pointer to controller context structure > + */ > +static void cdns3_otg_enable_irq(struct cdns3 *cdns) > +{ > + writel(OTGIEN_ID_CHANGE_INT | OTGIEN_VBUSVALID_RISE_INT | > + OTGIEN_VBUSVALID_FALL_INT, &cdns->otg_regs->ien); > +} > + > +/** > + * cdns3_drd_switch_host - start/stop host > + * @cdns: Pointer to controller context structure > + * @on: 1 for start, 0 for stop > + * > + * Returns 0 on success otherwise negative errno > + */ > +static int cdns3_drd_switch_host(struct cdns3 *cdns, int on) > +{ > + int ret; > + u32 reg = OTGCMD_OTG_DIS; > + > + /* switch OTG core */ > + if (on) { > + writel(OTGCMD_HOST_BUS_REQ | reg, &cdns->otg_regs->cmd); > + > + dev_dbg(cdns->dev, "Waiting for Host mode is turned on\n"); s/for/till > + ret = cdns3_handshake(&cdns->otg_regs->sts, OTGSTS_XHCI_READY, > + OTGSTS_XHCI_READY, 100000); > + > + if (ret) > + return ret; > + } else { > + usleep_range(30, 40); > + writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP | > + OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF, > + &cdns->otg_regs->cmd); > + usleep_range(3000, 4000); why do you need delays before and after the write? > + } > + > + return 0; > +} > + > +/** > + * cdns3_drd_switch_gadget - start/stop gadget > + * @cdns: Pointer to controller context structure > + * @on: 1 for start, 0 for stop > + * > + * Returns 0 on success otherwise negative errno > + */ > +static int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on) > +{ > + int ret; > + u32 reg = OTGCMD_OTG_DIS; > + > + /* switch OTG core */ > + if (on) { > + writel(OTGCMD_DEV_BUS_REQ | reg, &cdns->otg_regs->cmd); > + > + dev_dbg(cdns->dev, "Waiting for Device mode is turned on\n"); s/for/till > + > + ret = cdns3_handshake(&cdns->otg_regs->sts, OTGSTS_DEV_READY, > + OTGSTS_DEV_READY, 100000); > + > + if (ret) > + return ret; > + } else { > + /* > + * driver should wait at least 10us after disabling Device > + * before turning-off Device (DEV_BUS_DROP) > + */ > + usleep_range(20, 30); > + writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP | > + OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF, > + &cdns->otg_regs->cmd); > + usleep_range(3000, 4000); why do you need a delay after the write? > + } > + > + return 0; > +} > + > +/** > + * cdns3_init_otg_mode - initialize drd controller > + * @cdns: Pointer to controller context structure > + * > + * Returns 0 on success otherwise negative errno > + */ > +static int cdns3_init_otg_mode(struct cdns3 *cdns) > +{ > + int ret = 0; > + > + cdns3_otg_disable_irq(cdns); > + /* clear all interrupts */ > + writel(~0, &cdns->otg_regs->ivect); > + > + ret = cdns3_set_mode(cdns, USB_DR_MODE_OTG); > + if (ret) > + return ret; > + > + if (cdns3_is_host(cdns)) > + ret = cdns3_drd_switch_host(cdns, 1); > + else > + ret = cdns3_drd_switch_gadget(cdns, 1); > + > + if (ret) > + return ret; > + > + cdns3_otg_enable_irq(cdns); Schedule switch workqueue to deal with updated ID state? > + return ret; > +} > + > +/** > + * cdns3_drd_update_mode - initialize mode of operation > + * @cdns: Pointer to controller context structure > + * > + * Returns 0 on success otherwise negative errno > + */ > +int cdns3_drd_update_mode(struct cdns3 *cdns) > +{ > + int ret = 0; > + > + if (cdns->desired_dr_mode == cdns->current_dr_mode) > + return ret; > + > + cdns3_drd_switch_gadget(cdns, 0); > + cdns3_drd_switch_host(cdns, 0); Why are you stopping gadget/host here? One or both of might not have been started. > + > + switch (cdns->desired_dr_mode) { > + case USB_DR_MODE_PERIPHERAL: > + ret = cdns3_set_mode(cdns, USB_DR_MODE_PERIPHERAL); > + break; > + case USB_DR_MODE_HOST: > + ret = cdns3_set_mode(cdns, USB_DR_MODE_HOST); > + break; > + case USB_DR_MODE_OTG: > + ret = cdns3_init_otg_mode(cdns); > + break; > + default: > + dev_err(cdns->dev, "Unsupported mode of operation %d\n", > + cdns->dr_mode); > + return -EINVAL; > + } > + > + return ret; > +} > + > +/** > + * cdns3_drd_irq - interrupt handler for OTG events > + * > + * @irq: irq number for cdns3 core device > + * @data: structure of cdns3 > + * > + * Returns IRQ_HANDLED or IRQ_NONE > + */ > +static irqreturn_t cdns3_drd_irq(int irq, void *data) > +{ > + irqreturn_t ret = IRQ_NONE; > + struct cdns3 *cdns = data; > + u32 reg; > + > + if (cdns->dr_mode != USB_DR_MODE_OTG) > + return ret; > + > + reg = readl(&cdns->otg_regs->ivect); > + > + if (!reg) > + return ret; > + > + if (reg & OTGIEN_ID_CHANGE_INT) { > + dev_dbg(cdns->dev, "OTG IRQ: new ID: %d\n", > + cdns3_get_id(cdns)); > + > + queue_work(system_freezable_wq, &cdns->role_switch_wq); > + > + ret = IRQ_HANDLED; > + } > + > + writel(~0, &cdns->otg_regs->ivect); > + return ret; > +} > + > +int cdns3_drd_init(struct cdns3 *cdns) > +{ > + void __iomem *regs; > + int ret = 0; > + u32 state; > + > + regs = devm_ioremap_resource(cdns->dev, &cdns->otg_res); > + if (IS_ERR(regs)) > + return PTR_ERR(regs); > + > + /* Detection of DRD version. Controller has been released > + * in two versions. Both are similar, but they have same changes > + * in register maps. > + * The first register in old version is command register and it's read > + * only, so driver should read 0 from it. On the other hand, in v1 > + * the first register contains device ID number which is not set to 0. > + * Driver uses this fact to detect the proper version of > + * controller. > + */ > + cdns->otg_v0_regs = regs; > + if (!readl(&cdns->otg_v0_regs->cmd)) { > + cdns->version = CDNS3_CONTROLLER_V0; > + cdns->otg_v1_regs = NULL; > + cdns->otg_regs = regs; > + dev_info(cdns->dev, "DRD version v0 (%08x)\n", > + readl(&cdns->otg_v0_regs->version)); > + } else { > + cdns->otg_v0_regs = NULL; > + cdns->otg_v1_regs = regs; > + cdns->otg_regs = (void *)&cdns->otg_v1_regs->cmd; > + cdns->version = CDNS3_CONTROLLER_V1; > + dev_info(cdns->dev, "DRD version v1 (ID: %08x, rev: %08x)\n", > + readl(&cdns->otg_v1_regs->did), > + readl(&cdns->otg_v1_regs->rid)); > + } > + > + state = OTGSTS_STRAP(readl(&cdns->otg_regs->sts)); > + > + /* Update dr_mode according to STRAP configuration. */ > + cdns->dr_mode = USB_DR_MODE_OTG; > + if (state == OTGSTS_STRAP_HOST) { > + dev_info(cdns->dev, "Controller strapped to HOST\n"); > + cdns->dr_mode = USB_DR_MODE_HOST; > + } else if (state == OTGSTS_STRAP_GADGET) { > + dev_info(cdns->dev, "Controller strapped to PERIPHERAL\n"); > + cdns->dr_mode = USB_DR_MODE_PERIPHERAL; > + } > + > + cdns->desired_dr_mode = cdns->dr_mode; > + cdns->current_dr_mode = USB_DR_MODE_UNKNOWN; > + > + ret = devm_request_threaded_irq(cdns->dev, cdns->irq, cdns3_drd_irq, > + NULL, IRQF_SHARED, > + dev_name(cdns->dev), cdns); > + > + if (ret) > + return ret; > + > + state = readl(&cdns->otg_regs->sts); > + if (OTGSTS_OTG_NRDY(state) != 0) { > + dev_err(cdns->dev, "Cadence USB3 OTG device not ready\n"); > + return -ENODEV; > + } > + > + ret = cdns3_drd_update_mode(cdns); > + > + return ret; > +} > + > +int cdns3_drd_exit(struct cdns3 *cdns) > +{ > + return cdns3_drd_switch_host(cdns, 0); Why only stopping host? I think we need to stop active role, disable IRQ generation and free irq? > +} > diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c > new file mode 100644 > index 000000000000..7f7f24ee3c4b > --- /dev/null > +++ b/drivers/usb/cdns3/gadget.c > @@ -0,0 +1,2003 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Cadence USBSS DRD Driver - gadget side. > + * > + * Copyright (C) 2018 Cadence Design Systems. > + * Copyright (C) 2017-2018 NXP > + * > + * Authors: Pawel Jez , > + * Pawel Laszczak > + * Peter Chen > + */ > + > + > +static void cdns3_gadget_disable(struct cdns3 *cdns) > +{ > + struct cdns3_device *priv_dev; > + > + priv_dev = cdns->gadget_dev; > + > + if (priv_dev->gadget_driver) > + priv_dev->gadget_driver->disconnect(&priv_dev->gadget);> + > + usb_gadget_disconnect(&priv_dev->gadget); > + priv_dev->gadget.speed = USB_SPEED_UNKNOWN; > +} > + > +void cdns3_gadget_exit(struct cdns3 *cdns) > +{ > + struct cdns3_device *priv_dev; > + > + priv_dev = cdns->gadget_dev; > + > + cdns3_gadget_disable(cdns); > + > + devm_free_irq(cdns->dev, cdns->irq, cdns); > + > + pm_runtime_mark_last_busy(cdns->dev); > + pm_runtime_put_autosuspend(cdns->dev); > + > + usb_del_gadget_udc(&priv_dev->gadget); > + > + cdns3_free_all_eps(priv_dev); > + > + dma_free_coherent(priv_dev->sysdev, 8, priv_dev->setup_buf, > + priv_dev->setup_dma); > + > + kfree(priv_dev->zlp_buf); > + kfree(priv_dev); > + cdns->gadget_dev = NULL; > +} > + > +static int cdns3_gadget_start(struct cdns3 *cdns) > +{ > + struct cdns3_device *priv_dev; > + u32 max_speed; > + int ret; > + > + priv_dev = kzalloc(sizeof(*priv_dev), GFP_KERNEL); > + if (!priv_dev) > + return -ENOMEM; > + > + cdns->gadget_dev = priv_dev; > + priv_dev->sysdev = cdns->dev; > + priv_dev->dev = cdns->dev; > + priv_dev->regs = cdns->dev_regs; > + > + max_speed = usb_get_maximum_speed(cdns->dev); > + > + /* Check the maximum_speed parameter */ > + switch (max_speed) { > + case USB_SPEED_FULL: > + case USB_SPEED_HIGH: > + case USB_SPEED_SUPER: > + break; > + default: > + dev_err(cdns->dev, "invalid maximum_speed parameter %d\n", > + max_speed); > + /* fall through */ > + case USB_SPEED_UNKNOWN: > + /* default to superspeed */ > + max_speed = USB_SPEED_SUPER; > + break; > + } > + > + /* fill gadget fields */ > + priv_dev->gadget.max_speed = max_speed; > + priv_dev->gadget.speed = USB_SPEED_UNKNOWN; > + priv_dev->gadget.ops = &cdns3_gadget_ops; > + priv_dev->gadget.name = "usb-ss-gadget"; > + priv_dev->gadget.sg_supported = 1; > + > + spin_lock_init(&priv_dev->lock); > + INIT_WORK(&priv_dev->pending_status_wq, > + cdns3_pending_setup_status_handler); > + > + /* initialize endpoint container */ > + INIT_LIST_HEAD(&priv_dev->gadget.ep_list); > + > + ret = cdns3_init_eps(priv_dev); > + if (ret) { > + dev_err(priv_dev->dev, "Failed to create endpoints\n"); > + goto err1; > + } > + > + /* allocate memory for setup packet buffer */ > + priv_dev->setup_buf = dma_alloc_coherent(priv_dev->sysdev, 8, > + &priv_dev->setup_dma, GFP_DMA); > + if (!priv_dev->setup_buf) { > + dev_err(priv_dev->dev, "Failed to allocate memory for SETUP buffer\n"); > + ret = -ENOMEM; > + goto err2; > + } > + > + priv_dev->dev_ver = readl(&priv_dev->regs->usb_cap6); > + dev_dbg(priv_dev->dev, "Device Controller version: %08x\n", > + readl(&priv_dev->regs->usb_cap6)); > + dev_dbg(priv_dev->dev, "USB Capabilities:: %08x\n", > + readl(&priv_dev->regs->usb_cap1)); > + dev_dbg(priv_dev->dev, "On-Chip memory cnfiguration: %08x\n", > + readl(&priv_dev->regs->usb_cap2)); > + > + priv_dev->zlp_buf = kzalloc(CDNS3_EP_ZLP_BUF_SIZE, GFP_KERNEL); > + if (!priv_dev->zlp_buf) { > + ret = -ENOMEM; > + goto err3; > + } > + > + /* add USB gadget device */ > + ret = usb_add_gadget_udc(priv_dev->dev, &priv_dev->gadget); > + if (ret < 0) { > + dev_err(priv_dev->dev, > + "Failed to register USB device controller\n"); > + goto err4; > + } > + > + return 0; > +err4: > + kfree(priv_dev->zlp_buf); > +err3: > + dma_free_coherent(priv_dev->sysdev, 8, priv_dev->setup_buf, > + priv_dev->setup_dma); > +err2: > + cdns3_free_all_eps(priv_dev); > +err1: > + cdns->gadget_dev = NULL; > + return ret; > +} > + > +static int __cdns3_gadget_init(struct cdns3 *cdns) > +{ > + struct cdns3_device *priv_dev; > + unsigned long flags; > + int ret = 0; > + > + ret = cdns3_gadget_start(cdns); > + if (ret) > + return ret; > + > + priv_dev = cdns->gadget_dev; > + ret = devm_request_threaded_irq(cdns->dev, cdns->irq, > + cdns3_device_irq_handler, > + cdns3_device_thread_irq_handler, > + IRQF_SHARED, dev_name(cdns->dev), cdns); > + if (ret) > + goto err0; > + > + pm_runtime_get_sync(cdns->dev); pm_runtime_get_sync() should be done before cdns3_gadget_start() > + spin_lock_irqsave(&priv_dev->lock, flags); > + spin_unlock_irqrestore(&priv_dev->lock, flags); Redundant spinlock usage? > + return 0; > +err0: > + cdns3_gadget_exit(cdns); > + return ret; > +} > + > +static int cdns3_gadget_suspend(struct cdns3 *cdns, bool do_wakeup) > +{ > + cdns3_gadget_disable(cdns); Does this ensure gadget controller is stopped? > + return 0; > +} > + > +static int cdns3_gadget_resume(struct cdns3 *cdns, bool hibernated) > +{ > + struct cdns3_device *priv_dev; > + unsigned long flags; > + > + priv_dev = cdns->gadget_dev; > + spin_lock_irqsave(&priv_dev->lock, flags); > + > + if (!priv_dev->gadget_driver) { > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return 0; > + } > + > + cdns3_gadget_config(priv_dev); > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return 0; > +} > + > +/** > + * cdns3_gadget_init - initialize device structure > + * > + * cdns: cdns3 instance > + * > + * This function initializes the gadget. > + */ > +int cdns3_gadget_init(struct cdns3 *cdns) > +{ > + struct cdns3_role_driver *rdrv; > + > + rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL); > + if (!rdrv) > + return -ENOMEM; > + > + rdrv->start = __cdns3_gadget_init; > + rdrv->stop = cdns3_gadget_exit; > + rdrv->suspend = cdns3_gadget_suspend; > + rdrv->resume = cdns3_gadget_resume; > + rdrv->state = CDNS3_ROLE_STATE_INACTIVE; > + rdrv->name = "gadget"; > + cdns->roles[CDNS3_ROLE_GADGET] = rdrv; > + > + return 0; > +} -- cheers, -roger Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki From mboxrd@z Thu Jan 1 00:00:00 1970 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Subject: [v4,5/6] usb:cdns3 Add Cadence USB3 DRD Driver From: Roger Quadros Message-Id: <3af305e0-40bf-28cc-48d5-4afa241e7899@ti.com> Date: Wed, 20 Feb 2019 15:04:53 +0200 To: Pawel Laszczak , devicetree@vger.kernel.org Cc: gregkh@linuxfoundation.org, felipe.balbi@linux.intel.com, mark.rutland@arm.com, linux-usb@vger.kernel.org, hdegoede@redhat.com, heikki.krogerus@linux.intel.com, andy.shevchenko@gmail.com, robh+dt@kernel.org, linux-kernel@vger.kernel.org, jbergsagel@ti.com, nsekhar@ti.com, nm@ti.com, sureshp@cadence.com, peter.chen@nxp.com, kurahul@cadence.com List-ID: UGF3ZWwsCgpPbiAxNC8wMi8yMDE5IDIxOjQ1LCBQYXdlbCBMYXN6Y3phayB3cm90ZToKPiBUaGlz IHBhdGNoIGludHJvZHVjZSBuZXcgQ2FkZW5jZSBVU0JTUyBEUkQgZHJpdmVyIHRvIGxpbnV4IGtl cm5lbC4KPiAKPiBUaGUgQ2FkZW5jZSBVU0JTUyBEUkQgRHJpdmVyIGlzIGEgaGlnaGx5IGNvbmZp Z3VyYWJsZSBJUCBDb3JlIHdoaWNoaQo+IGNhbiBiZSBpbnN0YW50aWF0ZWQgYXMgRHVhbC1Sb2xl IERldmljZSAoRFJEKSwgUGVyaXBoZXJhbCBPbmx5IGFuZAo+IEhvc3QgT25seSAoWEhDSSljb25m aWd1cmF0aW9ucy4KPiAKPiBUaGUgY3VycmVudCBkcml2ZXIgaGFzIGJlZW4gdmFsaWRhdGVkIHdp dGggRlBHQSBidXJuZWQuIFdlIGhhdmUgc3VwcG9ydAo+IGZvciBQQ0llIGJ1cywgd2hpY2ggaXMg dXNlZCBvbiBGUEdBIHByb3RvdHlwaW5nLgo+IAo+IFRoZSBob3N0IHNpZGUgb2YgVVNCU1MtRFJE IGNvbnRyb2xsZXIgaXMgY29tcGxpYW5jZSB3aXRoIFhIQ0kKPiBzcGVjaWZpY2F0aW9uLCBzbyBp dCB3b3JrcyB3aXRoIHN0YW5kYXJkIFhIQ0kgbGludXggZHJpdmVyLgo+IAo+IFNpZ25lZC1vZmYt Ynk6IFBhd2VsIExhc3pjemFrIDxwYXdlbGxAY2FkZW5jZS5jb20+Cj4gLS0tCj4gIGRyaXZlcnMv dXNiL0tjb25maWcgICAgICAgICAgICAgICAgfCAgICAyICsKPiAgZHJpdmVycy91c2IvTWFrZWZp bGUgICAgICAgICAgICAgICB8ICAgIDIgKwo+ICBkcml2ZXJzL3VzYi9jZG5zMy9LY29uZmlnICAg ICAgICAgIHwgICA0NCArCj4gIGRyaXZlcnMvdXNiL2NkbnMzL01ha2VmaWxlICAgICAgICAgfCAg IDE0ICsKPiAgZHJpdmVycy91c2IvY2RuczMvY2RuczMtcGNpLXdyYXAuYyB8ICAxNTUgKysrCj4g IGRyaXZlcnMvdXNiL2NkbnMzL2NvcmUuYyAgICAgICAgICAgfCAgNDAzICsrKysrKwo+ICBkcml2 ZXJzL3VzYi9jZG5zMy9jb3JlLmggICAgICAgICAgIHwgIDExNiArKwo+ICBkcml2ZXJzL3VzYi9j ZG5zMy9kZWJ1Zy5oICAgICAgICAgIHwgIDE2OCArKysKPiAgZHJpdmVycy91c2IvY2RuczMvZGVi dWdmcy5jICAgICAgICB8ICAxNjQgKysrCj4gIGRyaXZlcnMvdXNiL2NkbnMzL2RyZC5jICAgICAg ICAgICAgfCAgMzY1ICsrKysrCj4gIGRyaXZlcnMvdXNiL2NkbnMzL2RyZC5oICAgICAgICAgICAg fCAgMTYyICsrKwo+ICBkcml2ZXJzL3VzYi9jZG5zMy9lcDAuYyAgICAgICAgICAgIHwgIDkwNyAr KysrKysrKysrKysrCj4gIGRyaXZlcnMvdXNiL2NkbnMzL2dhZGdldC1leHBvcnQuaCAgfCAgIDI4 ICsKPiAgZHJpdmVycy91c2IvY2RuczMvZ2FkZ2V0LmMgICAgICAgICB8IDIwMDMgKysrKysrKysr KysrKysrKysrKysrKysrKysrKwo+ICBkcml2ZXJzL3VzYi9jZG5zMy9nYWRnZXQuaCAgICAgICAg IHwgMTIwNyArKysrKysrKysrKysrKysrKwo+ICBkcml2ZXJzL3VzYi9jZG5zMy9ob3N0LWV4cG9y dC5oICAgIHwgICAyOCArCj4gIGRyaXZlcnMvdXNiL2NkbnMzL2hvc3QuYyAgICAgICAgICAgfCAg IDcyICsKPiAgZHJpdmVycy91c2IvY2RuczMvdHJhY2UuYyAgICAgICAgICB8ICAgMjMgKwo+ICBk cml2ZXJzL3VzYi9jZG5zMy90cmFjZS5oICAgICAgICAgIHwgIDQwNCArKysrKysKPiAgMTkgZmls ZXMgY2hhbmdlZCwgNjI2NyBpbnNlcnRpb25zKCspCj4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2 ZXJzL3VzYi9jZG5zMy9LY29uZmlnCj4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL3VzYi9j ZG5zMy9NYWtlZmlsZQo+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy91c2IvY2RuczMvY2Ru czMtcGNpLXdyYXAuYwo+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy91c2IvY2RuczMvY29y ZS5jCj4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL3VzYi9jZG5zMy9jb3JlLmgKPiAgY3Jl YXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvdXNiL2NkbnMzL2RlYnVnLmgKPiAgY3JlYXRlIG1vZGUg MTAwNjQ0IGRyaXZlcnMvdXNiL2NkbnMzL2RlYnVnZnMuYwo+ICBjcmVhdGUgbW9kZSAxMDA2NDQg ZHJpdmVycy91c2IvY2RuczMvZHJkLmMKPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvdXNi L2NkbnMzL2RyZC5oCj4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL3VzYi9jZG5zMy9lcDAu Ywo+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy91c2IvY2RuczMvZ2FkZ2V0LWV4cG9ydC5o Cj4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL3VzYi9jZG5zMy9nYWRnZXQuYwo+ICBjcmVh dGUgbW9kZSAxMDA2NDQgZHJpdmVycy91c2IvY2RuczMvZ2FkZ2V0LmgKPiAgY3JlYXRlIG1vZGUg MTAwNjQ0IGRyaXZlcnMvdXNiL2NkbnMzL2hvc3QtZXhwb3J0LmgKPiAgY3JlYXRlIG1vZGUgMTAw NjQ0IGRyaXZlcnMvdXNiL2NkbnMzL2hvc3QuYwo+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVy cy91c2IvY2RuczMvdHJhY2UuYwo+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy91c2IvY2Ru czMvdHJhY2UuaAo+IAo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL3VzYi9LY29uZmlnIGIvZHJpdmVy cy91c2IvS2NvbmZpZwo+IGluZGV4IDk4N2ZjNWJhNjMyMS4uNWY5MzM0MDE5ZDA0IDEwMDY0NAo+ IC0tLSBhL2RyaXZlcnMvdXNiL0tjb25maWcKPiArKysgYi9kcml2ZXJzL3VzYi9LY29uZmlnCj4g QEAgLTExMiw2ICsxMTIsOCBAQCBzb3VyY2UgImRyaXZlcnMvdXNiL3VzYmlwL0tjb25maWciCj4g IAo+ICBlbmRpZgo+ICAKPiArc291cmNlICJkcml2ZXJzL3VzYi9jZG5zMy9LY29uZmlnIgo+ICsK PiAgc291cmNlICJkcml2ZXJzL3VzYi9tdHUzL0tjb25maWciCj4gIAo+ICBzb3VyY2UgImRyaXZl cnMvdXNiL211c2IvS2NvbmZpZyIKPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy91c2IvTWFrZWZpbGUg Yi9kcml2ZXJzL3VzYi9NYWtlZmlsZQo+IGluZGV4IDdkMWI4YzgyYjIwOC4uYWIxMjViOTY2Y2Fj IDEwMDY0NAo+IC0tLSBhL2RyaXZlcnMvdXNiL01ha2VmaWxlCj4gKysrIGIvZHJpdmVycy91c2Iv TWFrZWZpbGUKPiBAQCAtMTIsNiArMTIsOCBAQCBvYmotJChDT05GSUdfVVNCX0RXQzMpCQkrPSBk d2MzLwo+ICBvYmotJChDT05GSUdfVVNCX0RXQzIpCQkrPSBkd2MyLwo+ICBvYmotJChDT05GSUdf VVNCX0lTUDE3NjApCSs9IGlzcDE3NjAvCj4gIAo+ICtvYmotJChDT05GSUdfVVNCX0NETlMzKQkJ Kz0gY2RuczMvCj4gKwo+ICBvYmotJChDT05GSUdfVVNCX01PTikJCSs9IG1vbi8KPiAgb2JqLSQo Q09ORklHX1VTQl9NVFUzKQkJKz0gbXR1My8KPiAgCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvdXNi L2NkbnMzL0tjb25maWcgYi9kcml2ZXJzL3VzYi9jZG5zMy9LY29uZmlnCj4gbmV3IGZpbGUgbW9k ZSAxMDA2NDQKPiBpbmRleCAwMDAwMDAwMDAwMDAuLjI3Y2IzZDhkYmUzZAo+IC0tLSAvZGV2L251 bGwKPiArKysgYi9kcml2ZXJzL3VzYi9jZG5zMy9LY29uZmlnCj4gQEAgLTAsMCArMSw0NCBAQAo+ ICtjb25maWcgVVNCX0NETlMzCj4gKwl0cmlzdGF0ZSAiQ2FkZW5jZSBVU0IzIER1YWwtUm9sZSBD b250cm9sbGVyIgo+ICsJZGVwZW5kcyBvbiBVU0JfU1VQUE9SVCAmJiAoVVNCIHx8IFVTQl9HQURH RVQpICYmIEhBU19ETUEKPiArCWhlbHAKPiArCSAgU2F5IFkgaGVyZSBpZiB5b3VyIHN5c3RlbSBo YXMgYSBjYWRlbmNlIFVTQjMgZHVhbC1yb2xlIGNvbnRyb2xsZXIuCj4gKwkgIEl0IHN1cHBvcnRz OiBkdWFsLXJvbGUgc3dpdGNoLCBIb3N0LW9ubHksIGFuZCBQZXJpcGhlcmFsLW9ubHkuCj4gKwo+ ICsJICBJZiB5b3UgY2hvb3NlIHRvIGJ1aWxkIHRoaXMgZHJpdmVyIGlzIGEgZHluYW1pY2FsbHkg bGlua2VkCj4gKwkgIGFzIG1vZHVsZSwgdGhlIG1vZHVsZSB3aWxsIGJlIGNhbGxlZCBjZG5zMy5r by4KPiArCj4gK2lmIFVTQl9DRE5TMwo+ICsKPiArY29uZmlnIFVTQl9DRE5TM19HQURHRVQKPiAr ICAgICAgICBib29sICJDYWRlbmNlIFVTQjMgZGV2aWNlIGNvbnRyb2xsZXIiCj4gKyAgICAgICAg ZGVwZW5kcyBvbiBVU0JfR0FER0VUCj4gKyAgICAgICAgaGVscAo+ICsgICAgICAgICAgU2F5IFkg aGVyZSB0byBlbmFibGUgZGV2aWNlIGNvbnRyb2xsZXIgZnVuY3Rpb25hbGl0eSBvZiB0aGUKPiAr ICAgICAgICAgIGNhZGVuY2UgVVNCU1MtREVWIGRyaXZlci4KCiJDYWRlbmNlIiA/Cgo+ICsKPiAr ICAgICAgICAgIFRoaXMgY29udHJvbGxlciBzdXBwb3J0cyBGRiwgSFMgYW5kIFNTIG1vZGUuIEl0 IGRvZXNuJ3Qgc3VwcG9ydAo+ICsgICAgICAgICAgTFMgYW5kIFNTUCBtb2RlLgo+ICsKPiArY29u ZmlnIFVTQl9DRE5TM19IT1NUCj4gKyAgICAgICAgYm9vbCAiQ2FkZW5jZSBVU0IzIGhvc3QgY29u dHJvbGxlciIKPiArICAgICAgICBkZXBlbmRzIG9uIFVTQl9YSENJX0hDRAo+ICsgICAgICAgIGhl bHAKPiArICAgICAgICAgIFNheSBZIGhlcmUgdG8gZW5hYmxlIGhvc3QgY29udHJvbGxlciBmdW5j dGlvbmFsaXR5IG9mIHRoZQo+ICsgICAgICAgICAgY2FkZW5jZSBkcml2ZXIuCj4gKwo+ICsgICAg ICAgICAgSG9zdCBjb250cm9sbGVyIGlzIGNvbXBsaWFudCB3aXRoIFhIQ0kgc28gaXQgd2lsbCB1 c2UKPiArICAgICAgICAgIHN0YW5kYXJkIFhIQ0kgZHJpdmVyLgo+ICsKPiArY29uZmlnIFVTQl9D RE5TM19QQ0lfV1JBUAo+ICsJdHJpc3RhdGUgIkNhZGVuY2UgVVNCMyBzdXBwb3J0IG9uIFBDSWUt YmFzZWQgcGxhdGZvcm1zIgo+ICsJZGVwZW5kcyBvbiBVU0JfUENJICYmIEFDUEkKPiArCWRlZmF1 bHQgVVNCX0NETlMzCj4gKwloZWxwCj4gKwkgIElmIHlvdSdyZSB1c2luZyB0aGUgVVNCU1MgQ29y ZSBJUCB3aXRoIGEgUENJZSwgcGxlYXNlIHNheQo+ICsJICAnWScgb3IgJ00nIGhlcmUuCj4gKwo+ ICsJICBJZiB5b3UgY2hvb3NlIHRvIGJ1aWxkIHRoaXMgZHJpdmVyIGFzIG1vZHVsZSBpdCB3aWxs Cj4gKwkgIGJlIGR5bmFtaWNhbGx5IGxpbmtlZCBhbmQgbW9kdWxlIHdpbGwgYmUgY2FsbGVkIGNk bnMzLXBjaS5rbwo+ICsKPiArZW5kaWYKPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy91c2IvY2RuczMv TWFrZWZpbGUgYi9kcml2ZXJzL3VzYi9jZG5zMy9NYWtlZmlsZQo+IG5ldyBmaWxlIG1vZGUgMTAw NjQ0Cj4gaW5kZXggMDAwMDAwMDAwMDAwLi44Zjk0Mzg1OTMzNzUKPiAtLS0gL2Rldi9udWxsCj4g KysrIGIvZHJpdmVycy91c2IvY2RuczMvTWFrZWZpbGUKPiBAQCAtMCwwICsxLDE0IEBACj4gKyMg U1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjAKPiArIyBkZWZpbmVfdHJhY2UuaCBuZWVk cyB0byBrbm93IGhvdyB0byBmaW5kIG91ciBoZWFkZXIKPiArQ0ZMQUdTX3RyYWNlLm8JCQkJOj0g LUkkKHNyYykKPiArCj4gK2NkbnMzLXkJCQkJCTo9IGNvcmUubyBkcmQubyB0cmFjZS5vCj4gKwo+ ICtvYmotJChDT05GSUdfVVNCX0NETlMzKQkJCSs9IGNkbnMzLm8KPiAraWZuZXEgKCQoQ09ORklH X0RFQlVHX0ZTKSwpCj4gKwljZG5zMy15CQkJCSs9IGRlYnVnZnMubwo+ICtlbmRpZgo+ICsKPiAr Y2RuczMtJChDT05GSUdfVVNCX0NETlMzX0dBREdFVCkJKz0gZ2FkZ2V0Lm8gZXAwLm8KPiArY2Ru czMtJChDT05GSUdfVVNCX0NETlMzX0hPU1QpCQkrPSBob3N0Lm8KPiArb2JqLSQoQ09ORklHX1VT Ql9DRE5TM19QQ0lfV1JBUCkJKz0gY2RuczMtcGNpLXdyYXAubwo+IGRpZmYgLS1naXQgYS9kcml2 ZXJzL3VzYi9jZG5zMy9jZG5zMy1wY2ktd3JhcC5jIGIvZHJpdmVycy91c2IvY2RuczMvY2RuczMt cGNpLXdyYXAuYwo+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0Cj4gaW5kZXggMDAwMDAwMDAwMDAwLi5k MGIyZDNkOWI5ODMKPiAtLS0gL2Rldi9udWxsCj4gKysrIGIvZHJpdmVycy91c2IvY2RuczMvY2Ru czMtcGNpLXdyYXAuYwo+IEBAIC0wLDAgKzEsMTU1IEBACj4gKy8vIFNQRFgtTGljZW5zZS1JZGVu dGlmaWVyOiBHUEwtMi4wCj4gKy8qCj4gKyAqIENhZGVuY2UgVVNCU1MgUENJIEdsdWUgZHJpdmVy Cj4gKyAqCj4gKyAqIENvcHlyaWdodCAoQykgMjAxOCBDYWRlbmNlLgoKMjAxOC0yMDE5PwoKPiAr ICoKPiArICogQXV0aG9yOiBQYXdlbCBMYXN6Y3phayA8cGF3ZWxsQGNhZGVuY2UuY29tPgo+ICsg Ki8KPiArCj4gKyNpbmNsdWRlIDxsaW51eC9rZXJuZWwuaD4KPiArI2luY2x1ZGUgPGxpbnV4L21v ZHVsZS5oPgo+ICsjaW5jbHVkZSA8bGludXgvcGNpLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9wbGF0 Zm9ybV9kZXZpY2UuaD4KPiArI2luY2x1ZGUgPGxpbnV4L2RtYS1tYXBwaW5nLmg+Cj4gKyNpbmNs dWRlIDxsaW51eC9zbGFiLmg+Cj4gKwo+ICtzdHJ1Y3QgY2RuczNfd3JhcCB7Cj4gKwlzdHJ1Y3Qg cGxhdGZvcm1fZGV2aWNlICpwbGF0X2RldjsKPiArCXN0cnVjdCBwY2lfZGV2ICpoZ19kZXY7Cj4g KwlzdHJ1Y3QgcmVzb3VyY2UgZGV2X3Jlc1s0XTsKPiArfTsKPiArCj4gK3N0cnVjdCBjZG5zM193 cmFwIHdyYXA7Cj4gKwo+ICsjZGVmaW5lIFJFU19JUlFfSUQJCTAKPiArI2RlZmluZSBSRVNfSE9T VF9JRAkJMQo+ICsjZGVmaW5lIFJFU19ERVZfSUQJCTIKPiArI2RlZmluZSBSRVNfRFJEX0lECQkz Cj4gKwo+ICsjZGVmaW5lIFBDSV9CQVJfSE9TVAkJMAo+ICsjZGVmaW5lIFBDSV9CQVJfREVWCQky Cj4gKyNkZWZpbmUgUENJX0JBUl9PVEcJCTQKPiArCj4gKyNkZWZpbmUgUENJX0RFVl9GTl9IT1NU X0RFVklDRQkwCj4gKyNkZWZpbmUgUENJX0RFVl9GTl9PVEcJCTEKPiArCj4gKyNkZWZpbmUgUENJ X0RSSVZFUl9OQU1FCQkiY2RuczMtcGNpLXVzYnNzIgo+ICsjZGVmaW5lIFBMQVRfRFJJVkVSX05B TUUJImNkbnMtdXNiMyIKPiArCj4gKyNkZWZpbmUgQ0ROU19WRU5ET1JfSUQgMHgxN2NkCj4gKyNk ZWZpbmUgQ0ROU19ERVZJQ0VfSUQgMHgwMTAwCj4gKwo+ICsvKioKPiArICogY2RuczNfcGNpX3By b2JlIC0gUHJvYmUgZnVuY3Rpb24gZm9yIENhZGVuY2UgVVNCIHdyYXBwZXIgZHJpdmVyCj4gKyAq IEBwZGV2OiBwbGF0Zm9ybSBkZXZpY2Ugb2JqZWN0Cj4gKyAqIEBpZDogcGNpIGRldmljZSBpZAo+ ICsgKgo+ICsgKiBSZXR1cm5zIDAgb24gc3VjY2VzcyBvdGhlcndpc2UgbmVnYXRpdmUgZXJybm8K PiArICovCj4gK3N0YXRpYyBpbnQgY2RuczNfcGNpX3Byb2JlKHN0cnVjdCBwY2lfZGV2ICpwZGV2 LAo+ICsJCQkgICBjb25zdCBzdHJ1Y3QgcGNpX2RldmljZV9pZCAqaWQpCj4gK3sKPiArCXN0cnVj dCBwbGF0Zm9ybV9kZXZpY2VfaW5mbyBwbGF0X2luZm87Cj4gKwlzdHJ1Y3QgY2RuczNfd3JhcCAq d3JhcDsKPiArCXN0cnVjdCByZXNvdXJjZSAqcmVzOwo+ICsJaW50IGVycjsKPiArCj4gKwkvKgo+ ICsJICogZm9yIEdBREdFVC9IT1NUIFBDSSAoZGV2Zm4pIGZ1bmN0aW9uIG51bWJlciBpcyAwLAo+ ICsJICogZm9yIE9URyBQQ0kgKGRldmZuKSBmdW5jdGlvbiBudW1iZXIgaXMgMQo+ICsJICovCj4g KwlpZiAoIWlkIHx8IHBkZXYtPmRldmZuICE9IFBDSV9ERVZfRk5fSE9TVF9ERVZJQ0UpCj4gKwkJ cmV0dXJuIC1FSU5WQUw7Cj4gKwo+ICsJZXJyID0gcGNpbV9lbmFibGVfZGV2aWNlKHBkZXYpOwo+ ICsJaWYgKGVycikgewo+ICsJCWRldl9lcnIoJnBkZXYtPmRldiwgIkVuYWJsaW5nIFBDSSBkZXZp Y2UgaGFzIGZhaWxlZCAlZFxuIiwgZXJyKTsKPiArCQlyZXR1cm4gZXJyOwo+ICsJfQo+ICsKPiAr CXBjaV9zZXRfbWFzdGVyKHBkZXYpOwo+ICsJd3JhcCA9IGRldm1fa3phbGxvYygmcGRldi0+ZGV2 LCBzaXplb2YoKndyYXApLCBHRlBfS0VSTkVMKTsKPiArCWlmICghd3JhcCkgewo+ICsJCWRldl9l cnIoJnBkZXYtPmRldiwgIkZhaWxlZCB0byBhbGxvY2F0ZSBtZW1vcnlcbiIpOwo+ICsJCXJldHVy biAtRU5PTUVNOwo+ICsJfQo+ICsKPiArCS8qIGZ1bmN0aW9uIDA6IGhvc3QoQkFSXzApICsgZGV2 aWNlKEJBUl8xKSArIG90ZyhCQVJfMikpLiAqLwo+ICsJbWVtc2V0KHdyYXAtPmRldl9yZXMsIDB4 MDAsCj4gKwkgICAgICAgc2l6ZW9mKHN0cnVjdCByZXNvdXJjZSkgKiBBUlJBWV9TSVpFKHdyYXAt PmRldl9yZXMpKTsKPiArCWRldl9kYmcoJnBkZXYtPmRldiwgIkluaXRpYWxpemUgRGV2aWNlIHJl c291cmNlc1xuIik7Cj4gKwlyZXMgPSB3cmFwLT5kZXZfcmVzOwo+ICsKPiArCXJlc1tSRVNfREVW X0lEXS5zdGFydCA9IHBjaV9yZXNvdXJjZV9zdGFydChwZGV2LCBQQ0lfQkFSX0RFVik7Cj4gKwly ZXNbUkVTX0RFVl9JRF0uZW5kID0gICBwY2lfcmVzb3VyY2VfZW5kKHBkZXYsIFBDSV9CQVJfREVW KTsKPiArCXJlc1tSRVNfREVWX0lEXS5uYW1lID0gImRldiI7Cj4gKwlyZXNbUkVTX0RFVl9JRF0u ZmxhZ3MgPSBJT1JFU09VUkNFX01FTTsKPiArCWRldl9kYmcoJnBkZXYtPmRldiwgIlVTQlNTLURF ViBwaHlzaWNhbCBiYXNlIGFkZHI6ICVwYVxuIiwKPiArCQkmcmVzW1JFU19ERVZfSURdLnN0YXJ0 KTsKPiArCj4gKwlyZXNbUkVTX0hPU1RfSURdLnN0YXJ0ID0gcGNpX3Jlc291cmNlX3N0YXJ0KHBk ZXYsIFBDSV9CQVJfSE9TVCk7Cj4gKwlyZXNbUkVTX0hPU1RfSURdLmVuZCA9IHBjaV9yZXNvdXJj ZV9lbmQocGRldiwgUENJX0JBUl9IT1NUKTsKPiArCXJlc1tSRVNfSE9TVF9JRF0ubmFtZSA9ICJ4 aGNpIjsKPiArCXJlc1tSRVNfSE9TVF9JRF0uZmxhZ3MgPSBJT1JFU09VUkNFX01FTTsKPiArCWRl dl9kYmcoJnBkZXYtPmRldiwgIlVTQlNTLVhIQ0kgcGh5c2ljYWwgYmFzZSBhZGRyOiAlcGFcbiIs Cj4gKwkJJnJlc1tSRVNfSE9TVF9JRF0uc3RhcnQpOwo+ICsKPiArCXJlc1tSRVNfRFJEX0lEXS5z dGFydCA9IHBjaV9yZXNvdXJjZV9zdGFydChwZGV2LCBQQ0lfQkFSX09URyk7Cj4gKwlyZXNbUkVT X0RSRF9JRF0uZW5kID0gICBwY2lfcmVzb3VyY2VfZW5kKHBkZXYsIFBDSV9CQVJfT1RHKTsKPiAr CXJlc1tSRVNfRFJEX0lEXS5uYW1lID0gIm90ZyI7Cj4gKwlyZXNbUkVTX0RSRF9JRF0uZmxhZ3Mg PSBJT1JFU09VUkNFX01FTTsKPiArCWRldl9kYmcoJnBkZXYtPmRldiwgIlVTQlNTLURSRCBwaHlz aWNhbCBiYXNlIGFkZHI6ICVwYVxuIiwKPiArCQkmcmVzW1JFU19EUkRfSURdLnN0YXJ0KTsKPiAr Cj4gKwkvKiBJbnRlcnJ1cHQgY29tbW9uIGZvciBib3RoIGRldmljZSBhbmQgWEhDSSAqLwo+ICsJ d3JhcC0+ZGV2X3Jlc1tSRVNfSVJRX0lEXS5zdGFydCA9IHBkZXYtPmlycTsKPiArCXdyYXAtPmRl dl9yZXNbUkVTX0lSUV9JRF0ubmFtZSA9ICJjZG5zMy1pcnEiOwo+ICsJd3JhcC0+ZGV2X3Jlc1tS RVNfSVJRX0lEXS5mbGFncyA9IElPUkVTT1VSQ0VfSVJROwo+ICsKPiArCS8qIHNldCB1cCBwbGF0 Zm9ybSBkZXZpY2UgaW5mbyAqLwo+ICsJbWVtc2V0KCZwbGF0X2luZm8sIDAsIHNpemVvZihwbGF0 X2luZm8pKTsKPiArCXBsYXRfaW5mby5wYXJlbnQgPSAmcGRldi0+ZGV2Owo+ICsJcGxhdF9pbmZv LmZ3bm9kZSA9IHBkZXYtPmRldi5md25vZGU7Cj4gKwlwbGF0X2luZm8ubmFtZSA9IFBMQVRfRFJJ VkVSX05BTUU7Cj4gKwlwbGF0X2luZm8uaWQgPSBwZGV2LT5kZXZmbjsKPiArCXBsYXRfaW5mby5y ZXMgPSB3cmFwLT5kZXZfcmVzOwo+ICsJcGxhdF9pbmZvLm51bV9yZXMgPSBBUlJBWV9TSVpFKHdy YXAtPmRldl9yZXMpOwo+ICsJcGxhdF9pbmZvLmRtYV9tYXNrID0gcGRldi0+ZG1hX21hc2s7Cj4g Kwo+ICsJLyogcmVnaXN0ZXIgcGxhdGZvcm0gZGV2aWNlICovCj4gKwl3cmFwLT5wbGF0X2RldiA9 IHBsYXRmb3JtX2RldmljZV9yZWdpc3Rlcl9mdWxsKCZwbGF0X2luZm8pOwo+ICsJaWYgKElTX0VS Uih3cmFwLT5wbGF0X2RldikpCj4gKwkJcmV0dXJuIFBUUl9FUlIod3JhcC0+cGxhdF9kZXYpOwo+ ICsKPiArCXBjaV9zZXRfZHJ2ZGF0YShwZGV2LCB3cmFwKTsKPiArCj4gKwlyZXR1cm4gZXJyOwo+ ICt9Cj4gKwo+ICt2b2lkIGNkbnMzX3BjaV9yZW1vdmUoc3RydWN0IHBjaV9kZXYgKnBkZXYpCj4g K3sKPiArCXN0cnVjdCBjZG5zM193cmFwICp3cmFwID0gKHN0cnVjdCBjZG5zM193cmFwICopcGNp X2dldF9kcnZkYXRhKHBkZXYpOwo+ICsKPiArCXBsYXRmb3JtX2RldmljZV91bnJlZ2lzdGVyKHdy YXAtPnBsYXRfZGV2KTsKPiArfQo+ICsKPiArc3RhdGljIGNvbnN0IHN0cnVjdCBwY2lfZGV2aWNl X2lkIGNkbnMzX3BjaV9pZHNbXSA9IHsKPiArCXsgUENJX0RFVklDRShDRE5TX1ZFTkRPUl9JRCwg Q0ROU19ERVZJQ0VfSUQpLCB9LAo+ICsJeyAwLCB9Cj4gK307Cj4gKwo+ICtzdGF0aWMgc3RydWN0 IHBjaV9kcml2ZXIgY2RuczNfcGNpX2RyaXZlciA9IHsKPiArCS5uYW1lID0gUENJX0RSSVZFUl9O QU1FLAo+ICsJLmlkX3RhYmxlID0gY2RuczNfcGNpX2lkcywKPiArCS5wcm9iZSA9IGNkbnMzX3Bj aV9wcm9iZSwKPiArCS5yZW1vdmUgPSBjZG5zM19wY2lfcmVtb3ZlLAo+ICt9Owo+ICsKPiArbW9k dWxlX3BjaV9kcml2ZXIoY2RuczNfcGNpX2RyaXZlcik7Cj4gK01PRFVMRV9ERVZJQ0VfVEFCTEUo cGNpLCBjZG5zM19wY2lfaWRzKTsKPiArCj4gK01PRFVMRV9BVVRIT1IoIlBhd2VsIExhc3pjemFr IDxwYXdlbGxAY2FkZW5jZS5jb20+Iik7Cj4gK01PRFVMRV9MSUNFTlNFKCJHUEwgdjIiKTsKPiAr TU9EVUxFX0RFU0NSSVBUSU9OKCJDYWRlbmNlIFVTQlNTIFBDSSB3cmFwcGVyciIpOwo+ICsKPiBk aWZmIC0tZ2l0IGEvZHJpdmVycy91c2IvY2RuczMvY29yZS5jIGIvZHJpdmVycy91c2IvY2RuczMv Y29yZS5jCj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQKPiBpbmRleCAwMDAwMDAwMDAwMDAuLmFhMmY2 MzI0MWRhYgo+IC0tLSAvZGV2L251bGwKPiArKysgYi9kcml2ZXJzL3VzYi9jZG5zMy9jb3JlLmMK PiBAQCAtMCwwICsxLDQwMyBAQAo+ICsvLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogR1BMLTIu MAo+ICsvKgo+ICsgKiBDYWRlbmNlIFVTQlNTIERSRCBEcml2ZXIuCj4gKyAqCj4gKyAqIENvcHly aWdodCAoQykgMjAxOCBDYWRlbmNlLgo+ICsgKiBDb3B5cmlnaHQgKEMpIDIwMTctMjAxOCBOWFAK PiArICoKPiArICogQXV0aG9yOiBQZXRlciBDaGVuIDxwZXRlci5jaGVuQG54cC5jb20+Cj4gKyAq ICAgICAgICAgUGF3ZWwgTGFzemN6YWsgPHBhd2VsbEBjYWRlbmNlLmNvbT4KPiArICovCj4gKwo+ ICsjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9rZXJuZWwuaD4K PiArI2luY2x1ZGUgPGxpbnV4L3BsYXRmb3JtX2RldmljZS5oPgo+ICsjaW5jbHVkZSA8bGludXgv aW50ZXJydXB0Lmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9pby5oPgo+ICsjaW5jbHVkZSA8bGludXgv cG1fcnVudGltZS5oPgo+ICsKPiArI2luY2x1ZGUgImdhZGdldC5oIgo+ICsjaW5jbHVkZSAiY29y ZS5oIgo+ICsjaW5jbHVkZSAiaG9zdC1leHBvcnQuaCIKPiArI2luY2x1ZGUgImdhZGdldC1leHBv cnQuaCIKPiArI2luY2x1ZGUgImRyZC5oIgo+ICsjaW5jbHVkZSAiZGVidWcuaCIKPiArCj4gK3N0 YXRpYyBpbmxpbmUKPiArc3RydWN0IGNkbnMzX3JvbGVfZHJpdmVyICpjZG5zM19nZXRfY3VycmVu dF9yb2xlX2RyaXZlcihzdHJ1Y3QgY2RuczMgKmNkbnMpCj4gK3sKPiArCVdBUk5fT04oY2Rucy0+ cm9sZSA+PSBDRE5TM19ST0xFX0VORCB8fCAhY2Rucy0+cm9sZXNbY2Rucy0+cm9sZV0pOwo+ICsJ cmV0dXJuIGNkbnMtPnJvbGVzW2NkbnMtPnJvbGVdOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGNk bnMzX3JvbGVfc3RhcnQoc3RydWN0IGNkbnMzICpjZG5zLCBlbnVtIGNkbnMzX3JvbGVzIHJvbGUp Cj4gK3sKPiArCWludCByZXQ7Cj4gKwo+ICsJaWYgKFdBUk5fT04ocm9sZSA+PSBDRE5TM19ST0xF X0VORCkpCj4gKwkJcmV0dXJuIDA7Cj4gKwo+ICsJaWYgKCFjZG5zLT5yb2xlc1tyb2xlXSkKPiAr CQlyZXR1cm4gLUVOWElPOwo+ICsKPiArCWlmIChjZG5zLT5yb2xlc1tyb2xlXS0+c3RhdGUgPT0g Q0ROUzNfUk9MRV9TVEFURV9BQ1RJVkUpCj4gKwkJcmV0dXJuIDA7Cj4gKwo+ICsJbXV0ZXhfbG9j aygmY2Rucy0+bXV0ZXgpOwo+ICsJY2Rucy0+cm9sZSA9IHJvbGU7Cj4gKwlyZXQgPSBjZG5zLT5y b2xlc1tyb2xlXS0+c3RhcnQoY2Rucyk7Cj4gKwlpZiAoIXJldCkKPiArCQljZG5zLT5yb2xlc1ty b2xlXS0+c3RhdGUgPSBDRE5TM19ST0xFX1NUQVRFX0FDVElWRTsKPiArCW11dGV4X3VubG9jaygm Y2Rucy0+bXV0ZXgpOwo+ICsJcmV0dXJuIHJldDsKPiArfQo+ICsKPiArdm9pZCBjZG5zM19yb2xl X3N0b3Aoc3RydWN0IGNkbnMzICpjZG5zKQo+ICt7Cj4gKwllbnVtIGNkbnMzX3JvbGVzIHJvbGUg PSBjZG5zLT5yb2xlOwo+ICsKPiArCWlmIChyb2xlID49IENETlMzX1JPTEVfRU5EKSB7Cj4gKwkJ V0FSTl9PTihyb2xlID4gQ0ROUzNfUk9MRV9FTkQpOwo+ICsJCXJldHVybjsKPiArCX0KPiArCj4g KwlpZiAoY2Rucy0+cm9sZXNbcm9sZV0tPnN0YXRlID09IENETlMzX1JPTEVfU1RBVEVfSU5BQ1RJ VkUpCj4gKwkJcmV0dXJuOwo+ICsKPiArCW11dGV4X2xvY2soJmNkbnMtPm11dGV4KTsKPiArCWNk bnMtPnJvbGVzW3JvbGVdLT5zdG9wKGNkbnMpOwo+ICsJY2Rucy0+cm9sZXNbcm9sZV0tPnN0YXRl ID0gQ0ROUzNfUk9MRV9TVEFURV9JTkFDVElWRTsKPiArCW11dGV4X3VubG9jaygmY2Rucy0+bXV0 ZXgpOwo+ICt9Cj4gKwo+ICsvKgo+ICsgKiBjZG5zLT5yb2xlIGdldHMgZnJvbSBjZG5zM19nZXRf aW5pdGlhbF9yb2xlLCBhbmQgdGhpcyBBUEkgdGVsbHMgcm9sZSBhdCB0aGUKPiArICogcnVudGlt ZS4KPiArICogSWYgYm90aCByb2xlcyBhcmUgc3VwcG9ydGVkLCB0aGUgcm9sZSBpcyBzZWxlY3Rl ZCBiYXNlZCBvbiB2YnVzL2lkLgo+ICsgKiBJdCBjb3VsZCBiZSByZWFkIGZyb20gT1RHIHJlZ2lz dGVyIG9yIGV4dGVybmFsIGNvbm5lY3Rvci4KPiArICogSWYgb25seSBzaW5nbGUgcm9sZSBpcyBz dXBwb3J0ZWQsIG9ubHkgb25lIHJvbGUgc3RydWN0dXJlCj4gKyAqIGlzIGFsbG9jYXRlZCwgY2Ru cy0+cm9sZXNbQ0ROUzNfUk9MRV9IT1NUXSBvciBjZG5zLT5yb2xlc1tDRE5TM19ST0xFX0dBREdF VF0uCj4gKyAqLwo+ICtzdGF0aWMgZW51bSBjZG5zM19yb2xlcyBjZG5zM19nZXRfaW5pdGlhbF9y b2xlKHN0cnVjdCBjZG5zMyAqY2RucykKPiArewo+ICsJaWYgKGNkbnMtPnJvbGVzW0NETlMzX1JP TEVfSE9TVF0gJiYgY2Rucy0+cm9sZXNbQ0ROUzNfUk9MRV9HQURHRVRdKSB7Cj4gKwkJaWYgKGNk bnMzX2lzX2hvc3QoY2RucykpCj4gKwkJCXJldHVybiBDRE5TM19ST0xFX0hPU1Q7Cj4gKwkJaWYg KGNkbnMzX2lzX2RldmljZShjZG5zKSkKPiArCQkJcmV0dXJuIENETlMzX1JPTEVfR0FER0VUOwo+ ICsJfQo+ICsJcmV0dXJuIGNkbnMtPnJvbGVzW0NETlMzX1JPTEVfSE9TVF0KPiArCQk/IENETlMz X1JPTEVfSE9TVAo+ICsJCTogQ0ROUzNfUk9MRV9HQURHRVQ7Cj4gK30KPiArCj4gK3N0YXRpYyB2 b2lkIGNkbnMzX2V4aXRfcm9sZXMoc3RydWN0IGNkbnMzICpjZG5zKQo+ICt7Cj4gKwljZG5zM19y b2xlX3N0b3AoY2Rucyk7Cj4gKwljZG5zM19kcmRfZXhpdChjZG5zKTsKPiArfQo+ICsKPiArLyoq Cj4gKyAqIGNkbnMzX2NvcmVfaW5pdF9yb2xlIC0gaW5pdGlhbGl6ZSByb2xlIG9mIG9wZXJhdGlv bgo+ICsgKiBAY2RuczogUG9pbnRlciB0byBjZG5zMyBzdHJ1Y3R1cmUKPiArICoKPiArICogUmV0 dXJucyAwIG9uIHN1Y2Nlc3Mgb3RoZXJ3aXNlIG5lZ2F0aXZlIGVycm5vCj4gKyAqLwo+ICtzdGF0 aWMgaW50IGNkbnMzX2NvcmVfaW5pdF9yb2xlKHN0cnVjdCBjZG5zMyAqY2RucykKPiArewo+ICsJ c3RydWN0IGRldmljZSAqZGV2ID0gY2Rucy0+ZGV2Owo+ICsJZW51bSB1c2JfZHJfbW9kZSBiZXN0 X2RyX21vZGU7Cj4gKwllbnVtIHVzYl9kcl9tb2RlIGRyX21vZGU7Cj4gKwlpbnQgcmV0ID0gMDsK PiArCj4gKwlkcl9tb2RlID0gdXNiX2dldF9kcl9tb2RlKGRldik7Cj4gKwljZG5zLT5yb2xlID0g Q0ROUzNfUk9MRV9FTkQ7Cj4gKwo+ICsJLyoKPiArCSAqIElmIGRyaXZlciBjYW4ndCByZWFkIG1v ZGUgYnkgbWVhbnMgb2YgdXNiX2dldF9kcl9tZG9lIGZ1bmN0aW9uIHRoZW4KCnMvbWRvZS9tb2Rl Cgo+ICsJICogY2hvb3NlcyBtb2RlIGFjY29yZGluZyB3aXRoIEtlcm5lbCBjb25maWd1cmF0aW9u LiBUaGlzIHNldHRpbmcKPiArCSAqIGNhbiBiZSByZXN0cmljdGVkIGxhdGVyIGRlcGVuZGluZyBv biBzdHJhcCBwaW4gY29uZmlndXJhdGlvbi4KPiArCSAqLwo+ICsJaWYgKGRyX21vZGUgPT0gVVNC X0RSX01PREVfVU5LTk9XTikgewo+ICsJCWlmIChJU19FTkFCTEVEKENPTkZJR19VU0JfQ0ROUzNf SE9TVCkgJiYKPiArCQkgICAgSVNfRU5BQkxFRChDT05GSUdfVVNCX0NETlMzX0dBREdFVCkpCj4g KwkJCWRyX21vZGUgPSBVU0JfRFJfTU9ERV9PVEc7Cj4gKwkJZWxzZSBpZiAoSVNfRU5BQkxFRChD T05GSUdfVVNCX0NETlMzX0hPU1QpKQo+ICsJCQlkcl9tb2RlID0gVVNCX0RSX01PREVfSE9TVDsK PiArCQllbHNlIGlmIChJU19FTkFCTEVEKENPTkZJR19VU0JfQ0ROUzNfR0FER0VUKSkKPiArCQkJ ZHJfbW9kZSA9IFVTQl9EUl9NT0RFX1BFUklQSEVSQUw7Cj4gKwl9Cj4gKwo+ICsJYmVzdF9kcl9t b2RlID0gVVNCX0RSX01PREVfT1RHOwoKTWlnaHQgYmUgd29ydGggbWVudGlvbmluZyB0aGF0IGNk bnMtPmRyX21vZGUgaXMgc3RyYXAgY29uZmlndXJhdGlvbgphdCB0aGlzIHBvaW50LgoKV2hhdCBl eGFjdGx5IGFyZSB3ZSB0cnlpbmcgdG8gZG8gaGVyZT8KTXkgZ3Vlc3MgaXMgdGhhdCBjaG9vc2Vu IGRyX21vZGUgY2FuIGJlIGVxdWFsIHRvIG9yIHN1YnNldCBvZiBzdHJhcCBjb25maWd1cmF0aW9u PwoKRG9lcyB0aGlzIHdvcms/CgoJaWYgKGNkbnMtPmRyX21vZGUgIT0gVVNCX0RSX01PREVfT1RH KSB7CgkJaWYgKGNkbnMtPmRyX21vZGUgIT0gZHJfbW9kZSkgewoJCQlkZXZfZXJyKGRldiwgIklu Y29ycmVjdCBkcl9tb2RlIGNvbmZpZ3VyYXRpb246IHN0cmFwICVkOiByZXF1ZXN0ZWQgJWRcbiIs CgkJCQljZG5zLT5kcl9tb2RlLCBkcl9tb2RlKTsKCQl9Cgl9CgpBdCB0aGlzIHBvaW50LCBkcl9t b2RlIGNvbnRhaW5zIHRoZSBtb2RlIHdlIG5lZWQgdG8gdXNlLgoKPiArCj4gKwlpZiAoZHJfbW9k ZSA9PSBVU0JfRFJfTU9ERV9PVEcpIHsKPiArCQliZXN0X2RyX21vZGUgPSBjZG5zLT5kcl9tb2Rl Owo+ICsJfSBlbHNlIGlmIChjZG5zLT5kcl9tb2RlID09IFVTQl9EUl9NT0RFX09URykgewo+ICsJ CWJlc3RfZHJfbW9kZSA9IGRyX21vZGU7Cj4gKwl9IGVsc2UgaWYgKGNkbnMtPmRyX21vZGUgIT0g ZHJfbW9kZSkgewo+ICsJCWRldl9lcnIoZGV2LCAiSW5jb3JyZWN0IERSRCBjb25maWd1cmF0aW9u XG4iKTsKPiArCQlyZXR1cm4gLUVJTlZBTDsKPiArCX0KPiArCj4gKwlkcl9tb2RlID0gYmVzdF9k cl9tb2RlOwo+ICsKPiArCWlmIChkcl9tb2RlID09IFVTQl9EUl9NT0RFX09URyB8fCBkcl9tb2Rl ID09IFVTQl9EUl9NT0RFX0hPU1QpIHsKPiArCQlyZXQgPSBjZG5zM19ob3N0X2luaXQoY2Rucyk7 Cj4gKwkJaWYgKHJldCkgewo+ICsJCQlkZXZfZXJyKGRldiwgIkhvc3QgaW5pdGlhbGl6YXRpb24g ZmFpbGVkIHdpdGggJWRcbiIsCj4gKwkJCQlyZXQpOwo+ICsJCQlnb3RvIGVycjsKPiArCQl9Cj4g Kwl9Cj4gKwo+ICsJaWYgKGRyX21vZGUgPT0gVVNCX0RSX01PREVfT1RHIHx8IGRyX21vZGUgPT0g VVNCX0RSX01PREVfUEVSSVBIRVJBTCkgewo+ICsJCXJldCA9IGNkbnMzX2dhZGdldF9pbml0KGNk bnMpOwo+ICsJCWlmIChyZXQpIHsKPiArCQkJZGV2X2VycihkZXYsICJEZXZpY2UgaW5pdGlhbGl6 YXRpb24gZmFpbGVkIHdpdGggJWRcbiIsCj4gKwkJCQlyZXQpOwo+ICsJCQlnb3RvIGVycjsKPiAr CQl9Cj4gKwl9PiArCj4gKwljZG5zLT5kZXNpcmVkX2RyX21vZGUgPSBkcl9tb2RlOwo+ICsJY2Ru cy0+ZHJfbW9kZSA9IGRyX21vZGU7Cj4gKwkvKgo+ICsJICogZHJfbW9kZSBjb3VsZCBiZSBjaGFu Z2Ugc28gRFJEIG11c3QgdXBkYXRlIGNvbnRyb2xsZXIKCiJkZXNpcmVkX2RyX21vZGUgbWlnaHQg aGF2ZSBjaGFuZ2VkIHNvIHdlIG5lZWQgdG8gdXBkYXRlIHRoZSBjb250cm9sbGVyIGNvbmZpZ3Vy YXRpb24iPwoKPiArCSAqIGNvbmZpZ3VyYXRpb24KPiArCSAqLwo+ICsJcmV0ID0gY2RuczNfZHJk X3VwZGF0ZV9tb2RlKGNkbnMpOwo+ICsJaWYgKHJldCkKPiArCQlnb3RvIGVycjsKPiArCj4gKwlj ZG5zLT5yb2xlID0gY2RuczNfZ2V0X2luaXRpYWxfcm9sZShjZG5zKTsKPiArCj4gKwlyZXQgPSBj ZG5zM19yb2xlX3N0YXJ0KGNkbnMsIGNkbnMtPnJvbGUpOwo+ICsJaWYgKHJldCkgewo+ICsJCWRl dl9lcnIoZGV2LCAiY2FuJ3Qgc3RhcnQgJXMgcm9sZVxuIiwKPiArCQkJY2RuczNfZ2V0X2N1cnJl bnRfcm9sZV9kcml2ZXIoY2RucyktPm5hbWUpOwo+ICsJCWdvdG8gZXJyOwo+ICsJfQo+ICsKPiAr CXJldHVybiByZXQ7Cj4gK2VycjoKPiArCWNkbnMzX2V4aXRfcm9sZXMoY2Rucyk7Cj4gKwlyZXR1 cm4gcmV0Owo+ICt9Cj4gKwo+ICsvKioKPiArICogY2RzbjNfZ2V0X3JlYWxfcm9sZSAtIGdldCBy ZWFsIHJvbGUgb2YgY29udHJvbGxlciBiYXNlZCBvbiBoYXJkd2FyZSBzZXR0aW5ncy4KPiArICog QGNkbnM6IFBvaW50ZXIgdG8gY2RuczMgc3RydWN0dXJlCj4gKyAqCj4gKyAqIFJldHVybnMgcm9s ZQo+ICsgKi8KPiArZW51bSBjZG5zM19yb2xlcyBjZHNuM19nZXRfcmVhbF9yb2xlKHN0cnVjdCBj ZG5zMyAqY2RucykKPiArewo+ICsJZW51bSBjZG5zM19yb2xlcyByb2xlID0gQ0ROUzNfUk9MRV9F TkQ7Cj4gKwo+ICsJaWYgKGNkbnMtPmN1cnJlbnRfZHJfbW9kZSA9PSBVU0JfRFJfTU9ERV9PVEcp IHsKPiArCQlpZiAoY2RuczNfZ2V0X2lkKGNkbnMpKQo+ICsJCQlyb2xlID0gQ0ROUzNfUk9MRV9H QURHRVQ7Cj4gKwkJZWxzZQo+ICsJCQlyb2xlID0gQ0ROUzNfUk9MRV9IT1NUOwo+ICsJfSBlbHNl IHsKPiArCQlpZiAoY2RuczNfaXNfaG9zdChjZG5zKSkKPiArCQkJcm9sZSA9IENETlMzX1JPTEVf SE9TVDsKPiArCQlpZiAoY2RuczNfaXNfZGV2aWNlKGNkbnMpKQo+ICsJCQlyb2xlID0gQ0ROUzNf Uk9MRV9HQURHRVQ7Cj4gKwl9Cj4gKwo+ICsJcmV0dXJuIHJvbGU7Cj4gK30KPiArCj4gKy8qKgo+ ICsgKiBjZG5zM19yb2xlX3N3aXRjaCAtIHdvcmsgcXVldWUgaGFuZGxlciBmb3Igcm9sZSBzd2l0 Y2gKPiArICoKPiArICogQHdvcms6IHdvcmsgcXVldWUgaXRlbSBzdHJ1Y3R1cmUKPiArICoKPiAr ICogSGFuZGxlcyBiZWxvdyBldmVudHM6Cj4gKyAqIC0gUm9sZSBzd2l0Y2ggZm9yIGR1YWwtcm9s ZSBkZXZpY2VzCj4gKyAqIC0gQ0ROUzNfUk9MRV9HQURHRVQgPC0tPiBDRE5TM19ST0xFX0VORCBm b3IgcGVyaXBoZXJhbC1vbmx5IGRldmljZXMKPiArICovCj4gK3N0YXRpYyB2b2lkIGNkbnMzX3Jv bGVfc3dpdGNoKHN0cnVjdCB3b3JrX3N0cnVjdCAqd29yaykKPiArewo+ICsJZW51bSBjZG5zM19y b2xlcyByb2xlID0gQ0ROUzNfUk9MRV9FTkQ7Cj4gKwlzdHJ1Y3QgY2RuczNfcm9sZV9kcml2ZXIg KnJvbGVfZHJ2Owo+ICsJZW51bSBjZG5zM19yb2xlcyBjdXJyZW50X3JvbGU7Cj4gKwlzdHJ1Y3Qg Y2RuczMgKmNkbnM7Cj4gKwlpbnQgcmV0ID0gMDsKPiArCj4gKwljZG5zID0gY29udGFpbmVyX29m KHdvcmssIHN0cnVjdCBjZG5zMywgcm9sZV9zd2l0Y2hfd3EpOwo+ICsKPiArCS8qIER1cmluZyBz d2l0Y2hpbmcgY2Rucy0+cm9sZSBjYW4gYmUgZGlmZmVyZW50IHRoZW4gcm9sZSAqLwpzL3RoZW4v dGhhbgoKVGhlIGNvbW1lbnQgaXMgYSBiaXQgbWlzbGVhZGluZy4gVGhlIHB1cnBvc2Ugb2YgdGhp cyBzd2l0Y2ggZnVuY3Rpb24KaXMgdG8gZG8gYSBzd2l0Y2ggaWYgdGhlIHJvbGUgbmVlZHMgdG8g YmUgY2hhbmdlZC4KCj4gKwlyb2xlID0gY2RzbjNfZ2V0X3JlYWxfcm9sZShjZG5zKTsKPiArCj4g Kwlyb2xlX2RydiA9IGNkbnMzX2dldF9jdXJyZW50X3JvbGVfZHJpdmVyKGNkbnMpOwo+ICsKPiAr CXBtX3J1bnRpbWVfZ2V0X3N5bmMoY2Rucy0+ZGV2KTsKCnBtX3J1bnRpbWVfZ2V0X3N5bmMoKSBt dXN0IGJlIG1vdmVkIHRvIGJlZm9yZSBjZHNuM19nZXRfcmVhbF9yb2xlKCkgYXMgdGhhdCBmdW5j dGlvbgphY2Nlc3NlcyBhIGRldmljZSByZWdpc3Rlci4KCj4gKwo+ICsJLyogRGlzYWJsZSBjdXJy ZW50IHJvbGUuIFRoaXMgc3RhdGUgY2FuIGJlIGZvcmNlZCBmcm9tIHVzZXIgc3BhY2UuICovCi8q IERpc2FibGUgY3VycmVudCByb2xlIGlmIHJlcXVyZXN0ZWQgZnJvbSBkZWJ1Z2ZzICovPwoKPiAr CWlmIChjZG5zLT5kZWJ1Z19kaXNhYmxlICYmIHJvbGVfZHJ2LT5zdGF0ZSA9PSBDRE5TM19ST0xF X1NUQVRFX0FDVElWRSkgewo+ICsJCWNkbnMzX3JvbGVfc3RvcChjZG5zKTsKPiArCQlnb3RvIGV4 aXQ7Cj4gKwl9Cj4gKwo+ICsJLyogRG8gbm90aGluZyBpZiBub3RoaW5nIGNoYW5nZWQgKi8KPiAr CWlmIChjZG5zLT5yb2xlID09IHJvbGUgJiYgcm9sZV9kcnYtPnN0YXRlID09IENETlMzX1JPTEVf U1RBVEVfQUNUSVZFKQo+ICsJCWdvdG8gZXhpdDsKPiArCj4gKwljZG5zM19yb2xlX3N0b3AoY2Ru cyk7Cj4gKwo+ICsJcm9sZSA9IGNkc24zX2dldF9yZWFsX3JvbGUoY2Rucyk7CgpZb3UgYWxyZWFk eSBkaWQgY2RuczNfZ2V0X3JlYWxfcm9sZSBiZWZvcmUuIFRoaXMgaXMgcmVkdW5kYW50Lgo+ICsK PiArCWN1cnJlbnRfcm9sZSA9IGNkbnMtPnJvbGU7Cj4gKwlkZXZfZGJnKGNkbnMtPmRldiwgIlN3 aXRjaGluZyByb2xlIik7Cj4gKwo+ICsJcmV0ID0gY2RuczNfcm9sZV9zdGFydChjZG5zLCByb2xl KTsKPiArCWlmIChyZXQpIHsKPiArCQkvKiBCYWNrIHRvIGN1cnJlbnQgcm9sZSAqLwo+ICsJCWRl dl9lcnIoY2Rucy0+ZGV2LCAic2V0ICVkIGhhcyBmYWlsZWQsIGJhY2sgdG8gJWRcbiIsCj4gKwkJ CXJvbGUsIGN1cnJlbnRfcm9sZSk7Cj4gKwkJY2RuczNfcm9sZV9zdGFydChjZG5zLCBjdXJyZW50 X3JvbGUpOwoKTmVlZCB0byBjaGVjayByZXR1cm4gdmFsdWUgaGVyZSBhcyB3ZWxsPyBBbmQgY29t cGxhaW4gbG91ZCBpZiB0aGF0IGZhaWxzIHRvby4KCj4gKwl9Cj4gK2V4aXQ6Cj4gKwlwbV9ydW50 aW1lX3B1dF9zeW5jKGNkbnMtPmRldik7Cj4gK30KPiArCj4gKy8qKgo+ICsgKiBjZG5zM19wcm9i ZSAtIHByb2JlIGZvciBjZG5zMyBjb3JlIGRldmljZQo+ICsgKiBAcGRldjogUG9pbnRlciB0byBj ZG5zMyBjb3JlIHBsYXRmb3JtIGRldmljZQo+ICsgKgo+ICsgKiBSZXR1cm5zIDAgb24gc3VjY2Vz cyBvdGhlcndpc2UgbmVnYXRpdmUgZXJybm8KPiArICovCj4gK3N0YXRpYyBpbnQgY2RuczNfcHJv YmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldikKPiArewo+ICsJc3RydWN0IGRldmljZSAq ZGV2ID0gJnBkZXYtPmRldjsKPiArCXN0cnVjdCByZXNvdXJjZQkqcmVzOwo+ICsJc3RydWN0IGNk bnMzICpjZG5zOwo+ICsJdm9pZCBfX2lvbWVtICpyZWdzOwo+ICsJaW50IHJldDsKPiArCj4gKwlj ZG5zID0gZGV2bV9remFsbG9jKGRldiwgc2l6ZW9mKCpjZG5zKSwgR0ZQX0tFUk5FTCk7Cj4gKwlp ZiAoIWNkbnMpCj4gKwkJcmV0dXJuIC1FTk9NRU07Cj4gKwo+ICsJY2Rucy0+ZGV2ID0gZGV2Owo+ ICsKPiArCXBsYXRmb3JtX3NldF9kcnZkYXRhKHBkZXYsIGNkbnMpOwo+ICsKPiArCXJlcyA9IHBs YXRmb3JtX2dldF9yZXNvdXJjZShwZGV2LCBJT1JFU09VUkNFX0lSUSwgMCk7Cj4gKwlpZiAoIXJl cykgewo+ICsJCWRldl9lcnIoZGV2LCAibWlzc2luZyBJUlFcbiIpOwo+ICsJCXJldHVybiAtRU5P REVWOwo+ICsJfQo+ICsJY2Rucy0+aXJxID0gcmVzLT5zdGFydDsKPiArCj4gKwljZG5zLT54aGNp X3Jlc1swXSA9ICpyZXM7Cj4gKwo+ICsJLyoKPiArCSAqIFJlcXVlc3QgbWVtb3J5IHJlZ2lvbgo+ ICsJICogcmVnaW9uLTA6IHhIQ0kKPiArCSAqIHJlZ2lvbi0xOiBQZXJpcGhlcmFsCj4gKwkgKiBy ZWdpb24tMjogT1RHIHJlZ2lzdGVycwo+ICsJICovCj4gKwlyZXMgPSBwbGF0Zm9ybV9nZXRfcmVz b3VyY2VfYnluYW1lKHBkZXYsIElPUkVTT1VSQ0VfTUVNLCAieGhjaSIpOwo+ICsJaWYgKCFyZXMp Cj4gKwkJcmV0dXJuIC1FTlhJTzsKPiArCj4gKwljZG5zLT54aGNpX3Jlc1sxXSA9ICpyZXM7Cj4g Kwo+ICsJcmVzID0gcGxhdGZvcm1fZ2V0X3Jlc291cmNlX2J5bmFtZShwZGV2LCBJT1JFU09VUkNF X01FTSwgImRldiIpOwo+ICsJcmVncyA9IGRldm1faW9yZW1hcF9yZXNvdXJjZShkZXYsIHJlcyk7 Cj4gKwlpZiAoSVNfRVJSKHJlZ3MpKQo+ICsJCXJldHVybiBQVFJfRVJSKHJlZ3MpOwo+ICsJY2Ru cy0+ZGV2X3JlZ3MJPSByZWdzOwo+ICsKPiArCXJlcyA9IHBsYXRmb3JtX2dldF9yZXNvdXJjZV9i eW5hbWUocGRldiwgSU9SRVNPVVJDRV9NRU0sICJvdGciKTsKPiArCWlmICghcmVzKQo+ICsJCXJl dHVybiAtRU5YSU87Cj4gKwo+ICsJY2Rucy0+b3RnX3JlcyA9ICpyZXM7Cj4gKwo+ICsJbXV0ZXhf aW5pdCgmY2Rucy0+bXV0ZXgpOwo+ICsKPiArCWNkbnMtPnBoeSA9IGRldm1fcGh5X29wdGlvbmFs X2dldChkZXYsICJjZG5zMyx1c2JwaHkiKTsKPiArCWlmIChJU19FUlIoY2Rucy0+cGh5KSkKPiAr CQlyZXR1cm4gUFRSX0VSUihjZG5zLT5waHkpOwo+ICsKPiArCXBoeV9pbml0KGNkbnMtPnBoeSk7 Cj4gKwo+ICsJSU5JVF9XT1JLKCZjZG5zLT5yb2xlX3N3aXRjaF93cSwgY2RuczNfcm9sZV9zd2l0 Y2gpOwo+ICsKPiArCXJldCA9IGNkbnMzX2RyZF9pbml0KGNkbnMpOwo+ICsJaWYgKHJldCkKPiAr CQlnb3RvIGVycjsKPiArCj4gKwlyZXQgPSBjZG5zM19jb3JlX2luaXRfcm9sZShjZG5zKTsKPiAr CWlmIChyZXQpCj4gKwkJZ290byBlcnI7Cj4gKwo+ICsJY2RuczNfZGVidWdmc19pbml0KGNkbnMp Owo+ICsJZGV2aWNlX3NldF93YWtldXBfY2FwYWJsZShkZXYsIHRydWUpOwo+ICsJcG1fcnVudGlt ZV9zZXRfYWN0aXZlKGRldik7Cj4gKwlwbV9ydW50aW1lX2VuYWJsZShkZXYpOwo+ICsKPiArCS8q Cj4gKwkgKiBUaGUgY29udHJvbGxlciBuZWVkcyBsZXNzIHRpbWUgYmV0d2VlbiBidXMgYW5kIGNv bnRyb2xsZXIgc3VzcGVuZCwKPiArCSAqIGFuZCB3ZSBhbHNvIG5lZWRzIGEgc21hbGwgZGVsYXkg dG8gYXZvaWQgZnJlcXVlbnRseSBlbnRlcmluZyBsb3cKPiArCSAqIHBvd2VyIG1vZGUuCj4gKwkg Ki8KPiArCXBtX3J1bnRpbWVfc2V0X2F1dG9zdXNwZW5kX2RlbGF5KGRldiwgMjApOwo+ICsJcG1f cnVudGltZV9tYXJrX2xhc3RfYnVzeShkZXYpOwo+ICsJcG1fcnVudGltZV91c2VfYXV0b3N1c3Bl bmQoZGV2KTsKPiArCWRldl9kYmcoZGV2LCAiQ2FkZW5jZSBVU0IzIGNvcmU6IHByb2JlIHN1Y2Nl ZWRcbiIpOwo+ICsKPiArCXJldHVybiAwOwo+ICsKPiArZXJyOgo+ICsJcGh5X2V4aXQoY2Rucy0+ cGh5KTsKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gKy8qKgo+ICsgKiBjZG5zM19yZW1vdmUg LSB1bmJpbmQgZHJkIGRyaXZlciBhbmQgY2xlYW4gdXAKPiArICogQHBkZXY6IFBvaW50ZXIgdG8g TGludXggcGxhdGZvcm0gZGV2aWNlCj4gKyAqCj4gKyAqIFJldHVybnMgMCBvbiBzdWNjZXNzIG90 aGVyd2lzZSBuZWdhdGl2ZSBlcnJubwo+ICsgKi8KPiArc3RhdGljIGludCBjZG5zM19yZW1vdmUo c3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldikKPiArewo+ICsJc3RydWN0IGNkbnMzICpjZG5z ID0gcGxhdGZvcm1fZ2V0X2RydmRhdGEocGRldik7Cj4gKwo+ICsJcG1fcnVudGltZV9nZXRfc3lu YygmcGRldi0+ZGV2KTsKPiArCXBtX3J1bnRpbWVfZGlzYWJsZSgmcGRldi0+ZGV2KTsKPiArCXBt X3J1bnRpbWVfcHV0X25vaWRsZSgmcGRldi0+ZGV2KTsKCkknbSBub3Qgc3VyZSBpZiB0aGlzIGlz IGhhbmRsZWQgcmlnaHQuCllvdSBhcmUgc3RpbGwgYWNjZXNzaW5nIHRoZSBkZXZpY2UgaW4gYmVs b3cgY25kczNfKigpIGNhbGxzLgoKPiArCWNkbnMzX2RlYnVnZnNfZXhpdChjZG5zKTsKPiArCWNk bnMzX2V4aXRfcm9sZXMoY2Rucyk7PiArCXBoeV9leGl0KGNkbnMtPnBoeSk7CgpJcyB0aGUgZGV2 aWNlIGlzIGluIHJ1bnRpbWUgc3VzcGVuZGVkIHN0YXRlIGF0IHRoaXMgcG9pbnQ/Cgo+ICsJcmV0 dXJuIDA7Cj4gK30KPiArCj4gKyNpZmRlZiBDT05GSUdfT0YKPiArc3RhdGljIGNvbnN0IHN0cnVj dCBvZl9kZXZpY2VfaWQgb2ZfY2RuczNfbWF0Y2hbXSA9IHsKPiArCXsgLmNvbXBhdGlibGUgPSAi Y2Rucyx1c2IzLTEuMC4wIiB9LAo+ICsJeyAuY29tcGF0aWJsZSA9ICJjZG5zLHVzYjMtMS4wLjEi IH0sCj4gKwl7IH0sCj4gK307Cj4gK01PRFVMRV9ERVZJQ0VfVEFCTEUob2YsIG9mX2NkbnMzX21h dGNoKTsKPiArI2VuZGlmCj4gKwo+ICtzdGF0aWMgc3RydWN0IHBsYXRmb3JtX2RyaXZlciBjZG5z M19kcml2ZXIgPSB7Cj4gKwkucHJvYmUJCT0gY2RuczNfcHJvYmUsCj4gKwkucmVtb3ZlCQk9IGNk bnMzX3JlbW92ZSwKPiArCS5kcml2ZXIJCT0gewo+ICsJCS5uYW1lCT0gImNkbnMtdXNiMyIsCj4g KwkJLm9mX21hdGNoX3RhYmxlCT0gb2ZfbWF0Y2hfcHRyKG9mX2NkbnMzX21hdGNoKSwKPiArCX0s Cj4gK307Cj4gKwo+ICttb2R1bGVfcGxhdGZvcm1fZHJpdmVyKGNkbnMzX2RyaXZlcik7Cj4gKwo+ ICtNT0RVTEVfQUxJQVMoInBsYXRmb3JtOmNkbnMzIik7Cj4gK01PRFVMRV9BVVRIT1IoIlBhd2Vs IExhc3pjemFrIDxwYXdlbGxAY2FkZW5jZS5jb20+Iik7Cj4gK01PRFVMRV9MSUNFTlNFKCJHUEwg djIiKTsKPiArTU9EVUxFX0RFU0NSSVBUSU9OKCJDYWRlbmNlIFVTQjMgRFJEIENvbnRyb2xsZXIg RHJpdmVyIik7Cj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvdXNiL2NkbnMzL2NvcmUuaCBiL2RyaXZl cnMvdXNiL2NkbnMzL2NvcmUuaAo+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0Cj4gaW5kZXggMDAwMDAw MDAwMDAwLi5mYjRiMzkyMDYxNTgKPiAtLS0gL2Rldi9udWxsCj4gKysrIGIvZHJpdmVycy91c2Iv Y2RuczMvY29yZS5oCj4gQEAgLTAsMCArMSwxMTYgQEAKPiArLyogU1BEWC1MaWNlbnNlLUlkZW50 aWZpZXI6IEdQTC0yLjAgKi8KPiArLyoKPiArICogQ2FkZW5jZSBVU0JTUyBEUkQgSGVhZGVyIEZp bGUuCj4gKyAqCj4gKyAqIENvcHlyaWdodCAoQykgMjAxNy0yMDE4IE5YUAo+ICsgKiBDb3B5cmln aHQgKEMpIDIwMTggQ2FkZW5jZS4KPiArICoKPiArICogQXV0aG9yczogUGV0ZXIgQ2hlbiA8cGV0 ZXIuY2hlbkBueHAuY29tPgo+ICsgKiAgICAgICAgICBQYXdlbCBMYXN6Y3phayA8cGF3ZWxsQGNh ZGVuY2UuY29tPgo+ICsgKi8KPiArI2luY2x1ZGUgPGxpbnV4L3VzYi9vdGcuaD4KPiArCj4gKyNp Zm5kZWYgX19MSU5VWF9DRE5TM19DT1JFX0gKPiArI2RlZmluZSBfX0xJTlVYX0NETlMzX0NPUkVf SAo+ICsKPiArc3RydWN0IGNkbnMzOwo+ICtlbnVtIGNkbnMzX3JvbGVzIHsKPiArCUNETlMzX1JP TEVfSE9TVCA9IDAsCj4gKwlDRE5TM19ST0xFX0dBREdFVCwKPiArCUNETlMzX1JPTEVfRU5ELAo+ ICt9Owo+ICsKPiArLyoqCj4gKyAqIHN0cnVjdCBjZG5zM19yb2xlX2RyaXZlciAtIGhvc3QvZ2Fk Z2V0IHJvbGUgZHJpdmVyCj4gKyAqIEBzdGFydDogc3RhcnQgdGhpcyByb2xlCj4gKyAqIEBzdG9w OiBzdG9wIHRoaXMgcm9sZQo+ICsgKiBAc3VzcGVuZDogc3VzcGVuZCBjYWxsYmFjayBmb3IgdGhp cyByb2xlCj4gKyAqIEByZXN1bWU6IHJlc3VtZSBjYWxsYmFjayBmb3IgdGhpcyByb2xlCj4gKyAq IEBpcnE6IGlycSBoYW5kbGVyIGZvciB0aGlzIHJvbGUKPiArICogQG5hbWU6IHJvbGUgbmFtZSBz dHJpbmcgKGhvc3QvZ2FkZ2V0KQo+ICsgKiBAc3RhdGU6IGN1cnJlbnQgc3RhdGUKPiArICovCj4g K3N0cnVjdCBjZG5zM19yb2xlX2RyaXZlciB7Cj4gKwlpbnQgKCpzdGFydCkoc3RydWN0IGNkbnMz ICpjZG5zKTsKPiArCXZvaWQgKCpzdG9wKShzdHJ1Y3QgY2RuczMgKmNkbnMpOwo+ICsJaW50ICgq c3VzcGVuZCkoc3RydWN0IGNkbnMzICpjZG5zLCBib29sIGRvX3dha2V1cCk7Cj4gKwlpbnQgKCpy ZXN1bWUpKHN0cnVjdCBjZG5zMyAqY2RucywgYm9vbCBoaWJlcm5hdGVkKTsKPiArCWNvbnN0IGNo YXIgKm5hbWU7Cj4gKyNkZWZpbmUgQ0ROUzNfUk9MRV9TVEFURV9JTkFDVElWRQkwCj4gKyNkZWZp bmUgQ0ROUzNfUk9MRV9TVEFURV9BQ1RJVkUJCTEKPiArCWludCBzdGF0ZTsKPiArfTsKPiArCj4g KyNkZWZpbmUgQ0ROUzNfWEhDSV9SRVNPVVJDRVNfTlVNCTIKPiArLyoqCj4gKyAqIHN0cnVjdCBj ZG5zMyAtIFJlcHJlc2VudGF0aW9uIG9mIENhZGVuY2UgVVNCMyBEUkQgY29udHJvbGxlci4KPiAr ICogQGRldjogcG9pbnRlciB0byBDYWRlbmNlIGRldmljZSBzdHJ1Y3QKPiArICogQHhoY2lfcmVn czogcG9pbnRlciB0byBiYXNlIG9mIHhoY2kgcmVnaXN0ZXJzCj4gKyAqIEB4aGNpX3JlczogdGhl IHJlc291cmNlIGZvciB4aGNpCj4gKyAqIEBkZXZfcmVnczogcG9pbnRlciB0byBiYXNlIG9mIGRl diByZWdpc3RlcnMKPiArICogQG90Z19yZWdzOiBwb2ludGVyIHRvIGJhc2Ugb2Ygb3RnIHJlZ2lz dGVycwo+ICsgKiBAaXJxOiBpcnEgbnVtYmVyIGZvciBjb250cm9sbGVyCj4gKyAqIEByb2xlczog YXJyYXkgb2Ygc3VwcG9ydGVkIHJvbGVzIGZvciB0aGlzIGNvbnRyb2xsZXIKPiArICogQHJvbGU6 IGN1cnJlbnQgcm9sZQo+ICsgKiBAaG9zdF9kZXY6IHRoZSBjaGlsZCBob3N0IGRldmljZSBwb2lu dGVyIGZvciBjZG5zMyBjb3JlCj4gKyAqIEBnYWRnZXRfZGV2OiB0aGUgY2hpbGQgZ2FkZ2V0IGRl dmljZSBwb2ludGVyIGZvciBjZG5zMyBjb3JlCj4gKyAqIEB1c2I6IHBoeSBmb3IgdGhpcyBjb250 cm9sbGVyCj4gKyAqIEByb2xlX3N3aXRjaF93cTogd29yayBxdWV1ZSBpdGVtIGZvciByb2xlIHN3 aXRjaAo+ICsgKiBAaW5fbHBtOiB0aGUgY29udHJvbGxlciBpbiBsb3cgcG93ZXIgbW9kZQo+ICsg KiBAd2FrZXVwX2ludDogdGhlIHdha2V1cCBpbnRlcnJ1cHQKPiArICogQG11dGV4OiB0aGUgbXV0 ZXggZm9yIGNvbmN1cnJlbnQgY29kZSBhdCBkcml2ZXIKPiArICogQGRyX21vZGU6IHN1cHBvcnRl ZCBtb2RlIG9mIG9wZXJhdGlvbiBpdCBjYW4gYmUgb25seSBIb3N0LCBvbmx5IERldmljZQo+ICsg KiAgICAgICAgICAgb3IgT1RHIG1vZGUgdGhhdCBhbGxvdyB0byBzd2l0Y2ggYmV0d2VlbiBEZXZp Y2UgYW5kIEhvc3QgbW9kZS4KPiArICogICAgICAgICAgIFRoaXMgZmllbGQgYmFzZWQgb24gZmly bXdhcmUgc2V0dGluZywga2VybmVsIGNvbmZpZ3VyYXRpb24KPiArICogICAgICAgICAgIGFuZCBo YXJkd2FyZSBjb25maWd1cmF0aW9uLgo+ICsgKiBAY3VycmVudF9kcl9tb2RlOiBjdXJyZW50IG1v ZGUgb2Ygb3BlcmF0aW9uIHdoZW4gaW4gZHVhbC1yb2xlIG1vZGUKPiArICogQGRlc2lyZWRfZHJf bW9kZTogZGVzaXJlZCBtb2RlIG9mIG9wZXJhdGlvbiB3aGVuIGluIGR1YWwtcm9sZSBtb2RlLgo+ ICsgKiAgICAgICAgICAgVGhpcyB2YWx1ZSBjYW4gYmUgY2hhbmdlZCBkdXJpbmcgcnVudGltZS4K PiArICogICAgICAgICAgIEF2YWlsYWJsZSBvcHRpb25zIGRlcGVuZHMgb24gIGRyX21vZGU6Cj4g KyAqICAgICAgICAgICBkcl9tb2RlICAgICAgICAgICAgICAgICB8ICBkZXNpcmVkX2RyX21vZGUg YW5kIGN1cnJlbnRfZHJfbW9kZQo+ICsgKiAgICAgICAgICAgLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQo+ICsgKiAgICAgICAg ICAgVVNCX0RSX01PREVfSE9TVCAgICAgICAgfCBvbmx5IFVTQl9EUl9NT0RFX0hPU1QKPiArICog ICAgICAgICAgIFVTQl9EUl9NT0RFX1BFUklQSEVSQUwgIHwgb25seSBVU0JfRFJfTU9ERV9QRVJJ UEhFUkFMCj4gKyAqICAgICAgICAgICBVU0JfRFJfTU9ERV9PVEcgICAgICAgICB8IG9ubHkgVVNC X0RSX01PREVfSE9TVAo+ICsgKiAgICAgICAgICAgVVNCX0RSX01PREVfT1RHICAgICAgICAgfCBv bmx5IFVTQl9EUl9NT0RFX1BFUklQSEVSQUwKPiArICogICAgICAgICAgIFVTQl9EUl9NT0RFX09U RyAgICAgICAgIHwgVVNCX0RSX01PREVfT1RHCgpMYXN0IDMgbGluZXMgc2hvdWxkIGJlIHJlZHVj ZWQgdG8KCgkJVVNCX0RSX01PREVfT1RHICAgICAgICAgfCBVU0JfRFJfTU9ERV9PVEcsIFVTQl9E Ul9NT0RFX0hPU1Qgb3IKCQkJCQl8IFVTQl9EUl9NT0RFX1BFUklQSEVSQUwKCj4gKyAqCj4gKyAq ICAgICAgICAgICBEZXNpcmVkX2RyX3JvbGUgY2FuIGJlIGNoYW5nZWQgYnkgbWVhbnMgb2YgZGVi dWdmcy4KPiArICogQHJvb3Q6IGRlYnVnZnMgcm9vdCBmb2xkZXIgcG9pbnRlcgo+ICsgKiBAZGVi dWdfZGlzYWJsZToKPiArICovCj4gK3N0cnVjdCBjZG5zMyB7Cj4gKwlzdHJ1Y3QgZGV2aWNlCQkJ KmRldjsKPiArCXZvaWQgX19pb21lbQkJCSp4aGNpX3JlZ3M7Cj4gKwlzdHJ1Y3QgcmVzb3VyY2UJ CQl4aGNpX3Jlc1tDRE5TM19YSENJX1JFU09VUkNFU19OVU1dOwo+ICsJc3RydWN0IGNkbnMzX3Vz Yl9yZWdzIF9faW9tZW0JKmRldl9yZWdzOwo+ICsKPiArCXN0cnVjdCByZXNvdXJjZQkJCW90Z19y ZXM7Cj4gKwlzdHJ1Y3QgY2RuczNfb3RnX2xlZ2FjeV9yZWdzCSpvdGdfdjBfcmVnczsKPiArCXN0 cnVjdCBjZG5zM19vdGdfcmVncwkJKm90Z192MV9yZWdzOwo+ICsJc3RydWN0IGNkbnMzX290Z19j b21tb25fcmVncwkqb3RnX3JlZ3M7Cj4gKyNkZWZpbmUgQ0ROUzNfQ09OVFJPTExFUl9WMAkwCj4g KyNkZWZpbmUgQ0ROUzNfQ09OVFJPTExFUl9WMQkxCj4gKwl1MzIJCQkJdmVyc2lvbjsKPiArCj4g KwlpbnQJCQkJaXJxOwo+ICsJc3RydWN0IGNkbnMzX3JvbGVfZHJpdmVyCSpyb2xlc1tDRE5TM19S T0xFX0VORF07Cj4gKwllbnVtIGNkbnMzX3JvbGVzCQlyb2xlOwo+ICsJc3RydWN0IHBsYXRmb3Jt X2RldmljZQkJKmhvc3RfZGV2Owo+ICsJc3RydWN0IGNkbnMzX2RldmljZQkJKmdhZGdldF9kZXY7 Cj4gKwlzdHJ1Y3QgcGh5CQkJKnBoeTsKPiArCXN0cnVjdCB3b3JrX3N0cnVjdAkJcm9sZV9zd2l0 Y2hfd3E7Cj4gKwlpbnQJCQkJaW5fbHBtOjE7Cj4gKwlpbnQJCQkJd2FrZXVwX2ludDoxOwo+ICsJ LyogbXV0ZXh0IHVzZWQgaW4gd29ya3F1ZXVlKi8KPiArCXN0cnVjdCBtdXRleAkJCW11dGV4Owo+ ICsJZW51bSB1c2JfZHJfbW9kZQkJZHJfbW9kZTsKPiArCWVudW0gdXNiX2RyX21vZGUJCWN1cnJl bnRfZHJfbW9kZTsKPiArCWVudW0gdXNiX2RyX21vZGUJCWRlc2lyZWRfZHJfbW9kZTsKPiArCXN0 cnVjdCBkZW50cnkJCQkqcm9vdDsKPiArCWludAkJCQlkZWJ1Z19kaXNhYmxlOjE7Cj4gK307Cj4g Kwo+ICt2b2lkIGNkbnMzX3JvbGVfc3RvcChzdHJ1Y3QgY2RuczMgKmNkbnMpOwo+ICsKPiArI2Vu ZGlmIC8qIF9fTElOVVhfQ0ROUzNfQ09SRV9IICovCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvdXNi L2NkbnMzL2RlYnVnLmggYi9kcml2ZXJzL3VzYi9jZG5zMy9kZWJ1Zy5oCj4gbmV3IGZpbGUgbW9k ZSAxMDA2NDQKPiBpbmRleCAwMDAwMDAwMDAwMDAuLjE5MjllZGIzYTUyMQo+IC0tLSAvZGV2L251 bGwKPiArKysgYi9kcml2ZXJzL3VzYi9jZG5zMy9kZWJ1Zy5oCj4gQEAgLTAsMCArMSwxNjggQEAK PiArLyogU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjAgKi8KPiArLyoKPiArICogQ2Fk ZW5jZSBVU0JTUyBEUkQgRHJpdmVyLgo+ICsgKiBEZWJ1ZyBoZWFkZXIgZmlsZS4KPiArICoKPiAr ICogQ29weXJpZ2h0IChDKSAyMDE4IENhZGVuY2UuCj4gKyAqCj4gKyAqIEF1dGhvcjogUGF3ZWwg TGFzemN6YWsgPHBhd2VsbEBjYWRlbmNlLmNvbT4KPiArICovCj4gKyNpZm5kZWYgX19MSU5VWF9D RE5TM19ERUJVRwo+ICsjZGVmaW5lIF9fTElOVVhfQ0ROUzNfREVCVUcKPiArCj4gKyNpbmNsdWRl ICJjb3JlLmgiCj4gKwo+ICtzdGF0aWMgaW5saW5lIGNoYXIgKmNkbnMzX2RlY29kZV91c2JfaXJx KGNoYXIgKnN0ciwKPiArCQkJCQkgZW51bSB1c2JfZGV2aWNlX3NwZWVkIHNwZWVkLAo+ICsJCQkJ CSB1MzIgdXNiX2lzdHMpCj4gK3sKPiArCWludCByZXQ7Cj4gKwo+ICsJcmV0ID0gc3ByaW50Zihz dHIsICJJUlEgJTA4eCA9ICIsIHVzYl9pc3RzKTsKPiArCj4gKwlpZiAodXNiX2lzdHMgJiAoVVNC X0lTVFNfQ09OMkkgfCBVU0JfSVNUU19DT05JKSkgewo+ICsJCXJldCArPSBzcHJpbnRmKHN0ciAr IHJldCwgIkNvbm5lY3Rpb24gJXNcbiIsCj4gKwkJCSAgICAgICB1c2Jfc3BlZWRfc3RyaW5nKHNw ZWVkKSk7Cj4gKwl9Cj4gKwlpZiAodXNiX2lzdHMgJiBVU0JfSVNUU19DT04ySSB8fCB1c2JfaXN0 cyAmIFVTQl9JU1RTX0NPTkkpCj4gKwkJcmV0ICs9IHNwcmludGYoc3RyICsgcmV0LCAiRGlzY29u bmVjdGlvbiAiKTsKPiArCWlmICh1c2JfaXN0cyAmIFVTQl9JU1RTX0wyRU5USSkKPiArCQlyZXQg Kz0gc3ByaW50ZihzdHIgKyByZXQsICJzdXNwZW5kZWQgIik7Cj4gKwo+ICsJaWYgKHVzYl9pc3Rz ICYgVVNCX0lTVFNfTDJFWFRJKQo+ICsJCXJldCArPSBzcHJpbnRmKHN0ciArIHJldCwgIkwyIGV4 aXQgIik7Cj4gKwlpZiAodXNiX2lzdHMgJiBVU0JfSVNUU19VM0VYVEkpCj4gKwkJcmV0ICs9IHNw cmludGYoc3RyICsgcmV0LCAiVTMgZXhpdCAiKTsKPiArCWlmICh1c2JfaXN0cyAmIFVTQl9JU1RT X1VXUkVTSSkKPiArCQlyZXQgKz0gc3ByaW50ZihzdHIgKyByZXQsICJXYXJtIFJlc2V0ICIpOwo+ ICsJaWYgKHVzYl9pc3RzICYgVVNCX0lTVFNfVUhSRVNJKQo+ICsJCXJldCArPSBzcHJpbnRmKHN0 ciArIHJldCwgIkhvdCBSZXNldCAiKTsKPiArCWlmICh1c2JfaXN0cyAmIFVTQl9JU1RTX1UyUkVT SSkKPiArCQlyZXQgKz0gc3ByaW50ZihzdHIgKyByZXQsICJSZXNldCIpOwo+ICsKPiArCXJldHVy biBzdHI7Cj4gK30KPiArCj4gK3N0YXRpYyBpbmxpbmUgIGNoYXIgKmNkbnMzX2RlY29kZV9lcF9p cnEoY2hhciAqc3RyLAo+ICsJCQkJCSB1MzIgZXBfc3RzLAo+ICsJCQkJCSBjb25zdCBjaGFyICpl cF9uYW1lKQo+ICt7Cj4gKwlpbnQgcmV0Owo+ICsKPiArCXJldCA9IHNwcmludGYoc3RyLCAiSVJR IGZvciAlczogJTA4eCAiLCBlcF9uYW1lLCBlcF9zdHMpOwo+ICsKPiArCWlmIChlcF9zdHMgJiBF UF9TVFNfU0VUVVApCj4gKwkJcmV0ICs9IHNwcmludGYoc3RyICsgcmV0LCAiU0VUVVAgIik7Cj4g KwlpZiAoZXBfc3RzICYgRVBfU1RTX0lPQykKPiArCQlyZXQgKz0gc3ByaW50ZihzdHIgKyByZXQs ICJJT0MgIik7Cj4gKwlpZiAoZXBfc3RzICYgRVBfU1RTX0lTUCkKPiArCQlyZXQgKz0gc3ByaW50 ZihzdHIgKyByZXQsICJJU1AgIik7Cj4gKwlpZiAoZXBfc3RzICYgRVBfU1RTX0RFU0NNSVMpCj4g KwkJcmV0ICs9IHNwcmludGYoc3RyICsgcmV0LCAiREVTQ01JUyAiKTsKPiArCWlmIChlcF9zdHMg JiBFUF9TVFNfU1RSRUFNUikKPiArCQlyZXQgKz0gc3ByaW50ZihzdHIgKyByZXQsICJTVFJFQU1S ICIpOwo+ICsJaWYgKGVwX3N0cyAmIEVQX1NUU19NRF9FWElUKQo+ICsJCXJldCArPSBzcHJpbnRm KHN0ciArIHJldCwgIk1EX0VYSVQgIik7Cj4gKwlpZiAoZXBfc3RzICYgRVBfU1RTX1RSQkVSUikK PiArCQlyZXQgKz0gc3ByaW50ZihzdHIgKyByZXQsICJUUkJFUlIgIik7Cj4gKwlpZiAoZXBfc3Rz ICYgRVBfU1RTX05SRFkpCj4gKwkJcmV0ICs9IHNwcmludGYoc3RyICsgcmV0LCAiTlJEWSAiKTsK PiArCWlmIChlcF9zdHMgJiBFUF9TVFNfUFJJTUUpCj4gKwkJcmV0ICs9IHNwcmludGYoc3RyICsg cmV0LCAiUFJJTUUgIik7Cj4gKwlpZiAoZXBfc3RzICYgRVBfU1RTX1NJREVSUikKPiArCQlyZXQg Kz0gc3ByaW50ZihzdHIgKyByZXQsICJTSURFUlJUICIpOwo+ICsJaWYgKGVwX3N0cyAmIEVQX1NU U19PVVRTTU0pCj4gKwkJcmV0ICs9IHNwcmludGYoc3RyICsgcmV0LCAiT1VUU01NICIpOwo+ICsJ aWYgKGVwX3N0cyAmIEVQX1NUU19JU09FUlIpCj4gKwkJcmV0ICs9IHNwcmludGYoc3RyICsgcmV0 LCAiSVNPRVJSICIpOwo+ICsJaWYgKGVwX3N0cyAmIEVQX1NUU19JT1QpCj4gKwkJcmV0ICs9IHNw cmludGYoc3RyICsgcmV0LCAiSU9UICIpOwo+ICsKPiArCXJldHVybiBzdHI7Cj4gK30KPiArCj4g K3N0YXRpYyBpbmxpbmUgY2hhciAqY2RuczNfZGVjb2RlX2VweF9pcnEoY2hhciAqc3RyLAo+ICsJ CQkJCSBjaGFyICplcF9uYW1lLAo+ICsJCQkJCSB1MzIgZXBfc3RzKQo+ICt7Cj4gKwlyZXR1cm4g Y2RuczNfZGVjb2RlX2VwX2lycShzdHIsIGVwX3N0cywgZXBfbmFtZSk7Cj4gK30KPiArCj4gK3N0 YXRpYyBpbmxpbmUgY2hhciAqY2RuczNfZGVjb2RlX2VwMF9pcnEoY2hhciAqc3RyLAo+ICsJCQkJ CSBpbnQgZGlyLAo+ICsJCQkJCSB1MzIgZXBfc3RzKQo+ICt7Cj4gKwlyZXR1cm4gY2RuczNfZGVj b2RlX2VwX2lycShzdHIsIGVwX3N0cywKPiArCQkJCSAgIGRpciA/ICJlcDBJTiIgOiAiZXAwT1VU Iik7Cj4gK30KPiArCj4gKy8qKgo+ICsgKiBEZWJ1ZyBhIHRyYW5zZmVyIHJpbmcuCj4gKyAqCj4g KyAqIFByaW50cyBvdXQgYWxsIFRSQnMgaW4gdGhlIGVuZHBvaW50IHJpbmcsIGV2ZW4gdGhvc2Ug YWZ0ZXIgdGhlIExpbmsgVFJCLgo+ICsgKi4KPiArICovCj4gK3N0YXRpYyBpbmxpbmUgY2hhciAq Y2RuczNfZGJnX3Jpbmcoc3RydWN0IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwLAo+ICsJCQkJICAg c3RydWN0IGNkbnMzX3RyYiAqcmluZywgY2hhciAqc3RyKQo+ICt7Cj4gKwlkbWFfYWRkcl90IGFk ZHIgPSBwcml2X2VwLT50cmJfcG9vbF9kbWE7Cj4gKwlzdHJ1Y3QgY2RuczNfdHJiICp0cmI7Cj4g KwlpbnQgdHJiX3Blcl9zZWN0b3I7Cj4gKwlpbnQgcmV0ID0gMDsKPiArCWludCBpOwo+ICsKPiAr CXRyYl9wZXJfc2VjdG9yID0gR0VUX1RSQlNfUEVSX1NFR01FTlQocHJpdl9lcC0+dHlwZSk7Cj4g Kwo+ICsJdHJiID0gJnByaXZfZXAtPnRyYl9wb29sW3ByaXZfZXAtPmRlcXVldWVdOwo+ICsJcmV0 ICs9IHNwcmludGYoc3RyICsgcmV0LCAiXG5cdFx0UmluZyBjb250ZW50cyBmb3IgJXM6IiwgcHJp dl9lcC0+bmFtZSk7Cj4gKwo+ICsJcmV0ICs9IHNwcmludGYoc3RyICsgcmV0LAo+ICsJCSAgICAg ICAiXG5cdFx0UmluZyBkZXEgaW5kZXg6ICVkLCB0cmI6ICVwICh2aXJ0KSwgMHglbGx4IChkbWEp XG4iLAo+ICsJCSAgICAgICBwcml2X2VwLT5kZXF1ZXVlLCB0cmIsCj4gKwkJICAgICAgICh1bnNp Z25lZCBsb25nIGxvbmcpY2RuczNfdHJiX3ZpcnRfdG9fZG1hKHByaXZfZXAsIHRyYikpOwo+ICsK PiArCXRyYiA9ICZwcml2X2VwLT50cmJfcG9vbFtwcml2X2VwLT5lbnF1ZXVlXTsKPiArCXJldCAr PSBzcHJpbnRmKHN0ciArIHJldCwKPiArCQkgICAgICAgIlx0XHRSaW5nIGVucSBpbmRleDogJWQs IHRyYjogJXAgKHZpcnQpLCAweCVsbHggKGRtYSlcbiIsCj4gKwkJICAgICAgIHByaXZfZXAtPmVu cXVldWUsIHRyYiwKPiArCQkgICAgICAgKHVuc2lnbmVkIGxvbmcgbG9uZyljZG5zM190cmJfdmly dF90b19kbWEocHJpdl9lcCwgdHJiKSk7Cj4gKwo+ICsJcmV0ICs9IHNwcmludGYoc3RyICsgcmV0 LAo+ICsJCSAgICAgICAiXHRcdGZyZWUgdHJiczogJWQsIENDUz0lZCwgUENTPSVkXG4iLAo+ICsJ CSAgICAgICBwcml2X2VwLT5mcmVlX3RyYnMsIHByaXZfZXAtPmNjcywgcHJpdl9lcC0+cGNzKTsK PiArCj4gKwlpZiAodHJiX3Blcl9zZWN0b3IgPiBUUkJTX1BFUl9TRUdNRU5UKQo+ICsJCXRyYl9w ZXJfc2VjdG9yID0gVFJCU19QRVJfU0VHTUVOVDsKPiArCj4gKwlpZiAodHJiX3Blcl9zZWN0b3Ig PiBUUkJTX1BFUl9TRUdNRU5UKSB7Cj4gKwkJc3ByaW50ZihzdHIgKyByZXQsICJcdFx0VG8gYmln IHRyYW5zZmVyIHJpbmcgJWRcbiIsCj4gKwkJCXRyYl9wZXJfc2VjdG9yKTsKPiArCQlyZXR1cm4g c3RyOwo+ICsJfQo+ICsKPiArCWZvciAoaSA9IDA7IGkgPCB0cmJfcGVyX3NlY3RvcjsgKytpKSB7 Cj4gKwkJdHJiID0gJnJpbmdbaV07Cj4gKwkJcmV0ICs9IHNwcmludGYoc3RyICsgcmV0LAo+ICsJ CQkiXHRcdEAlcGFkICUwOHggJTA4eCAlMDh4XG4iLCAmYWRkciwKPiArCQkJbGUzMl90b19jcHUo dHJiLT5idWZmZXIpLAo+ICsJCQlsZTMyX3RvX2NwdSh0cmItPmxlbmd0aCksCj4gKwkJCWxlMzJf dG9fY3B1KHRyYi0+Y29udHJvbCkpOwo+ICsJCWFkZHIgKz0gc2l6ZW9mKCp0cmIpOwo+ICsJfQo+ ICsKPiArCXJldHVybiBzdHI7Cj4gK30KPiArCj4gK3ZvaWQgY2RuczNfZGJnKHN0cnVjdCBjZG5z M19kZXZpY2UgKnByaXZfZGV2LCBjb25zdCBjaGFyICpmbXQsIC4uLik7Cj4gKwo+ICsjaWZkZWYg Q09ORklHX0RFQlVHX0ZTCj4gK3ZvaWQgY2RuczNfZGVidWdmc19pbml0KHN0cnVjdCBjZG5zMyAq Y2Rucyk7Cj4gK3ZvaWQgY2RuczNfZGVidWdmc19leGl0KHN0cnVjdCBjZG5zMyAqY2Rucyk7Cj4g KyNlbHNlCj4gK3ZvaWQgY2RuczNfZGVidWdmc19pbml0KHN0cnVjdCBjZG5zMyAqY2Rucyk7Cj4g K3sgIH0KPiArdm9pZCBjZG5zM19kZWJ1Z2ZzX2V4aXQoc3RydWN0IGNkbnMzICpjZG5zKTsKPiAr eyAgfQo+ICsjZW5kaWYKPiArCj4gKyNlbmRpZiAvKl9fTElOVVhfQ0ROUzNfREVCVUcqLwo+IGRp ZmYgLS1naXQgYS9kcml2ZXJzL3VzYi9jZG5zMy9kZWJ1Z2ZzLmMgYi9kcml2ZXJzL3VzYi9jZG5z My9kZWJ1Z2ZzLmMKPiBuZXcgZmlsZSBtb2RlIDEwMDY0NAo+IGluZGV4IDAwMDAwMDAwMDAwMC4u ZDhmY2Q5MGQwNWIzCj4gLS0tIC9kZXYvbnVsbAo+ICsrKyBiL2RyaXZlcnMvdXNiL2NkbnMzL2Rl YnVnZnMuYwo+IEBAIC0wLDAgKzEsMTY0IEBACj4gKy8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVy OiBHUEwtMi4wCj4gKy8qCj4gKyAqIENhZGVuY2UgVVNCU1MgRFJEIENvbnRyb2xsZXIgRGVidWdG UyBmaWxlci4KPiArICoKPiArICogQ29weXJpZ2h0IChDKSAyMDE4IENhZGVuY2UuCj4gKyAqCj4g KyAqIEF1dGhvcjogUGF3ZWwgTGFzemN6YWsgPHBhd2VsbEBjYWRlbmNlLmNvbT4KPiArICovCj4g Kwo+ICsjaW5jbHVkZSA8bGludXgvdHlwZXMuaD4KPiArI2luY2x1ZGUgPGxpbnV4L2RlYnVnZnMu aD4KPiArI2luY2x1ZGUgPGxpbnV4L3NlcV9maWxlLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC91YWNj ZXNzLmg+Cj4gKwo+ICsjaW5jbHVkZSAiY29yZS5oIgo+ICsjaW5jbHVkZSAiZ2FkZ2V0LmgiCj4g KyNpbmNsdWRlICJkcmQuaCIKPiArCj4gK3N0YXRpYyBpbnQgY2RuczNfbW9kZV9zaG93KHN0cnVj dCBzZXFfZmlsZSAqcywgdm9pZCAqdW51c2VkKQo+ICt7Cj4gKwlzdHJ1Y3QgY2RuczMgKmNkbnMg PSBzLT5wcml2YXRlOwo+ICsKPiArCXN3aXRjaCAoY2Rucy0+Y3VycmVudF9kcl9tb2RlKSB7Cj4g KwljYXNlIFVTQl9EUl9NT0RFX0hPU1Q6Cj4gKwkJc2VxX3B1dHMocywgImhvc3RcbiIpOwo+ICsJ CWJyZWFrOwo+ICsJY2FzZSBVU0JfRFJfTU9ERV9QRVJJUEhFUkFMOgo+ICsJCXNlcV9wdXRzKHMs ICJkZXZpY2VcbiIpOwo+ICsJCWJyZWFrOwo+ICsJY2FzZSBVU0JfRFJfTU9ERV9PVEc6Cj4gKwkJ c2VxX3B1dHMocywgIm90Z1xuIik7Cj4gKwkJYnJlYWs7Cj4gKwlkZWZhdWx0Ogo+ICsJCXNlcV9w dXRzKHMsICJVTktOT1dOIG1vZGVcbiIpOwo+ICsJfQo+ICsKPiArCXJldHVybiAwOwo+ICt9Cj4g Kwo+ICtzdGF0aWMgaW50IGNkbnMzX21vZGVfb3BlbihzdHJ1Y3QgaW5vZGUgKmlub2RlLCBzdHJ1 Y3QgZmlsZSAqZmlsZSkKPiArewo+ICsJcmV0dXJuIHNpbmdsZV9vcGVuKGZpbGUsIGNkbnMzX21v ZGVfc2hvdywgaW5vZGUtPmlfcHJpdmF0ZSk7Cj4gK30KPiArCj4gK3N0YXRpYyBzc2l6ZV90IGNk bnMzX21vZGVfd3JpdGUoc3RydWN0IGZpbGUgKmZpbGUsCj4gKwkJCQljb25zdCBjaGFyIF9fdXNl ciAqdWJ1ZiwKPiArCQkJCXNpemVfdCBjb3VudCwgbG9mZl90ICpwcG9zKQo+ICt7Cj4gKwlzdHJ1 Y3Qgc2VxX2ZpbGUJICpzID0gZmlsZS0+cHJpdmF0ZV9kYXRhOwo+ICsJc3RydWN0IGNkbnMzICpj ZG5zID0gcy0+cHJpdmF0ZTsKPiArCXUzMiBtb2RlID0gVVNCX0RSX01PREVfVU5LTk9XTjsKPiAr CWNoYXIgYnVmWzMyXTsKPiArCj4gKwlpZiAoY29weV9mcm9tX3VzZXIoJmJ1ZiwgdWJ1ZiwgbWlu X3Qoc2l6ZV90LCBzaXplb2YoYnVmKSAtIDEsIGNvdW50KSkpCj4gKwkJcmV0dXJuIC1FRkFVTFQ7 Cj4gKwo+ICsJaWYgKCFzdHJuY21wKGJ1ZiwgImhvc3QiLCA0KSkgewo+ICsJCWlmIChjZG5zLT5k cl9tb2RlID09IFVTQl9EUl9NT0RFX0hPU1QgfHwKPiArCQkgICAgY2Rucy0+ZHJfbW9kZSA9PSBV U0JfRFJfTU9ERV9PVEcpIHsKPiArCQkJbW9kZSA9IFVTQl9EUl9NT0RFX0hPU1Q7Cj4gKwkJfQo+ ICsJfQo+ICsKPiArCWlmICghc3RybmNtcChidWYsICJkZXZpY2UiLCA2KSkKPiArCQlpZiAoY2Ru cy0+ZHJfbW9kZSA9PSBVU0JfRFJfTU9ERV9QRVJJUEhFUkFMIHx8Cj4gKwkJICAgIGNkbnMtPmRy X21vZGUgPT0gVVNCX0RSX01PREVfT1RHKQo+ICsJCQltb2RlID0gVVNCX0RSX01PREVfUEVSSVBI RVJBTDsKPiArCj4gKwlpZiAoIXN0cm5jbXAoYnVmLCAib3RnIiwgMykgJiYgY2Rucy0+ZHJfbW9k ZSA9PSBVU0JfRFJfTU9ERV9PVEcpCj4gKwkJbW9kZSA9IFVTQl9EUl9NT0RFX09URzsKPiArCj4g KwlpZiAobW9kZSA9PSBVU0JfRFJfTU9ERV9VTktOT1dOKSB7Cj4gKwkJZGV2X2VycihjZG5zLT5k ZXYsICJGYWlsZWQ6IGluY29ycmVjdCBtb2RlIHNldHRpbmdcbiIpOwo+ICsJCXJldHVybiAtRUZB VUxUOwo+ICsJfQo+ICsKPiArCWlmIChjZG5zLT5jdXJyZW50X2RyX21vZGUgIT0gbW9kZSkgewo+ ICsJCWNkbnMtPmRlc2lyZWRfZHJfbW9kZSA9IG1vZGU7Cj4gKwkJY2Rucy0+ZGVidWdfZGlzYWJs ZSA9IDA7Ckluc3RlYWQgb2YgZm9yY2luZyBkZWJ1Z19kaXNhYmxlIGhlcmUgbWF5YmUgeW91IGhv dWxkIGNoZWNrIGlmIGl0IGlzIHNldAphbmQgY29tcGxhaW4gdGhhdCBtb2RlIGNhbid0IGJlIGNo YW5nZWQgd2hlbiBkZWJ1Z19kaXNhYmxlIGlzIHNldD8KCj4gKwkJY2RuczNfcm9sZV9zdG9wKGNk bnMpOwo+ICsJCWNkbnMzX2RyZF91cGRhdGVfbW9kZShjZG5zKTsKCk5lZWQgdG8gY2hlY2sgcmV0 dXJuIHZhbHVlLgoKPiArCQlxdWV1ZV93b3JrKHN5c3RlbV9mcmVlemFibGVfd3EsICZjZG5zLT5y b2xlX3N3aXRjaF93cSk7Cj4gKwl9Cj4gKwo+ICsJcmV0dXJuIGNvdW50Owo+ICt9Cj4gKwo+ICtz dGF0aWMgY29uc3Qgc3RydWN0IGZpbGVfb3BlcmF0aW9ucyBjZG5zM19tb2RlX2ZvcHMgPSB7Cj4g Kwkub3BlbgkJCT0gY2RuczNfbW9kZV9vcGVuLAo+ICsJLndyaXRlCQkJPSBjZG5zM19tb2RlX3dy aXRlLAo+ICsJLnJlYWQJCQk9IHNlcV9yZWFkLAo+ICsJLmxsc2VlawkJCT0gc2VxX2xzZWVrLAo+ ICsJLnJlbGVhc2UJCT0gc2luZ2xlX3JlbGVhc2UsCj4gK307Cj4gKwo+ICtzdGF0aWMgaW50IGNk bnMzX2Rpc2FibGVfc2hvdyhzdHJ1Y3Qgc2VxX2ZpbGUgKnMsIHZvaWQgKnVudXNlZCkKPiArewo+ ICsJc3RydWN0IGNkbnMzICpjZG5zID0gcy0+cHJpdmF0ZTsKPiArCj4gKwlpZiAoIWNkbnMtPmRl YnVnX2Rpc2FibGUpCj4gKwkJc2VxX3B1dHMocywgIjBcbiIpOwo+ICsJZWxzZQo+ICsJCXNlcV9w dXRzKHMsICIxXG4iKTsKPiArCj4gKwlyZXR1cm4gMDsKPiArfQo+ICsKPiArc3RhdGljIHNzaXpl X3QgY2RuczNfZGlzYWJsZV93cml0ZShzdHJ1Y3QgZmlsZSAqZmlsZSwKPiArCQkJCSAgIGNvbnN0 IGNoYXIgX191c2VyICp1YnVmLAo+ICsJCQkJICAgc2l6ZV90IGNvdW50LCBsb2ZmX3QgKnBwb3Mp Cj4gK3sKPiArCXN0cnVjdCBzZXFfZmlsZQkgKnMgPSBmaWxlLT5wcml2YXRlX2RhdGE7Cj4gKwlz dHJ1Y3QgY2RuczMgKmNkbnMgPSBzLT5wcml2YXRlOwo+ICsJYm9vbCBkaXNhYmxlOwo+ICsJY2hh ciBidWZbMTZdOwo+ICsKPiArCWlmIChjb3B5X2Zyb21fdXNlcigmYnVmLCB1YnVmLCBtaW5fdChz aXplX3QsIHNpemVvZihidWYpIC0gMSwgY291bnQpKSkKPiArCQlyZXR1cm4gLUVGQVVMVDsKPiAr Cj4gKwlpZiAoa3N0cnRvYm9vbChidWYsICZkaXNhYmxlKSkgewo+ICsJCWRldl9lcnIoY2Rucy0+ ZGV2LCAid3Jvbmcgc2V0dGluZ1xuIik7Cj4gKwkJcmV0dXJuIC1FSU5WQUw7Cj4gKwl9Cj4gKwo+ ICsJaWYgKGRpc2FibGUgIT0gY2Rucy0+ZGVidWdfZGlzYWJsZSkgewo+ICsJCWNkbnMtPmRlYnVn X2Rpc2FibGUgPSBkaXNhYmxlOwo+ICsJCXF1ZXVlX3dvcmsoc3lzdGVtX2ZyZWV6YWJsZV93cSwg JmNkbnMtPnJvbGVfc3dpdGNoX3dxKTsKCldoYXQgaXMgdGhlIHB1cnBvc2Ugb2YgdGhpcyBkaXNh YmxlIGRlYnVnZnMgZmlsZT8KVG8gc3RvcCB0aGUgY3VycmVudGx5IGFjdGl2ZSByb2xlPwoKPiAr CX0KPiArCj4gKwlyZXR1cm4gY291bnQ7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgY2RuczNfZGlz YWJsZV9vcGVuKHN0cnVjdCBpbm9kZSAqaW5vZGUsIHN0cnVjdCBmaWxlICpmaWxlKQo+ICt7Cj4g KwlyZXR1cm4gc2luZ2xlX29wZW4oZmlsZSwgY2RuczNfZGlzYWJsZV9zaG93LCBpbm9kZS0+aV9w cml2YXRlKTsKPiArfQo+ICsKPiArc3RhdGljIGNvbnN0IHN0cnVjdCBmaWxlX29wZXJhdGlvbnMg Y2RuczNfZGlzYWJsZV9mb3BzID0gewo+ICsJLm9wZW4JCQk9IGNkbnMzX2Rpc2FibGVfb3BlbiwK PiArCS53cml0ZQkJCT0gY2RuczNfZGlzYWJsZV93cml0ZSwKPiArCS5yZWFkCQkJPSBzZXFfcmVh ZCwKPiArCS5sbHNlZWsJCQk9IHNlcV9sc2VlaywKPiArCS5yZWxlYXNlCQk9IHNpbmdsZV9yZWxl YXNlLAo+ICt9Owo+ICsKPiArdm9pZCBjZG5zM19kZWJ1Z2ZzX2luaXQoc3RydWN0IGNkbnMzICpj ZG5zKQo+ICt7Cj4gKwlzdHJ1Y3QgZGVudHJ5ICpyb290Owo+ICsKPiArCXJvb3QgPSBkZWJ1Z2Zz X2NyZWF0ZV9kaXIoZGV2X25hbWUoY2Rucy0+ZGV2KSwgTlVMTCk7Cj4gKwljZG5zLT5yb290ID0g cm9vdDsKPiArCWlmIChJU19FTkFCTEVEKENPTkZJR19VU0JfQ0ROUzNfR0FER0VUKSAmJgo+ICsJ ICAgIElTX0VOQUJMRUQoQ09ORklHX1VTQl9DRE5TM19IT1NUKSkKPiArCQlkZWJ1Z2ZzX2NyZWF0 ZV9maWxlKCJtb2RlIiwgMDY0NCwgcm9vdCwgY2RucywKPiArCQkJCSAgICAmY2RuczNfbW9kZV9m b3BzKTsKPiArCj4gKwlkZWJ1Z2ZzX2NyZWF0ZV9maWxlKCJkaXNhYmxlIiwgMDY0NCwgcm9vdCwg Y2RucywKPiArCQkJICAgICZjZG5zM19kaXNhYmxlX2ZvcHMpOwo+ICt9Cj4gKwo+ICt2b2lkIGNk bnMzX2RlYnVnZnNfZXhpdChzdHJ1Y3QgY2RuczMgKmNkbnMpCj4gK3sKPiArCWRlYnVnZnNfcmVt b3ZlX3JlY3Vyc2l2ZShjZG5zLT5yb290KTsKPiArfQo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL3Vz Yi9jZG5zMy9kcmQuYyBiL2RyaXZlcnMvdXNiL2NkbnMzL2RyZC5jCj4gbmV3IGZpbGUgbW9kZSAx MDA2NDQKPiBpbmRleCAwMDAwMDAwMDAwMDAuLjNlNTYzMzhjZDdiOQo+IC0tLSAvZGV2L251bGwK PiArKysgYi9kcml2ZXJzL3VzYi9jZG5zMy9kcmQuYwo+IEBAIC0wLDAgKzEsMzY1IEBACj4gKy8v IFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBHUEwtMi4wCj4gKy8qCj4gKyAqIENhZGVuY2UgVVNC U1MgRFJEIERyaXZlci4KPiArICoKPiArICogQ29weXJpZ2h0IChDKSAyMDE4IENhZGVuY2UuCj4g KyAqCj4gKyAqIEF1dGhvcjogUGF3ZWwgTGFzemN6YWsgPHBhd2VsbEBjYWRlbmNlLmNvbQo+ICsg Kgo+ICsgKi8KPiArI2luY2x1ZGUgPGxpbnV4L2tlcm5lbC5oPgo+ICsjaW5jbHVkZSA8bGludXgv aW50ZXJydXB0Lmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9kZWxheS5oPgo+ICsjaW5jbHVkZSA8bGlu dXgvdXNiL290Zy5oPgo+ICsKPiArI2luY2x1ZGUgImdhZGdldC5oIgo+ICsjaW5jbHVkZSAiZHJk LmgiCj4gKyNpbmNsdWRlICJjb3JlLmgiCj4gKwo+ICtzdGF0aWMgaW50IGNkbnMzX2RyZF9zd2l0 Y2hfZ2FkZ2V0KHN0cnVjdCBjZG5zMyAqY2RucywgaW50IG9uKTsKPiArc3RhdGljIGludCBjZG5z M19kcmRfc3dpdGNoX2hvc3Qoc3RydWN0IGNkbnMzICpjZG5zLCBpbnQgb24pOwo+ICsKPiArLyoq Cj4gKyAqIGNkbnMzX3NldF9tb2RlIC0gY2hhbmdlIG1vZGUgb2YgT1RHIENvcmUKPiArICogQGNk bnM6IHBvaW50ZXIgdG8gY29udGV4dCBzdHJ1Y3R1cmUKPiArICogQG1vZGU6IHNlbGVjdGVkIG1v ZGUgZnJvbSBjZG5zX3JvbGUKPiArICoKPiArICogUmV0dXJucyAwIG9uIHN1Y2Nlc3Mgb3RoZXJ3 aXNlIG5lZ2F0aXZlIGVycm5vCj4gKyAqLwo+ICtpbnQgY2RuczNfc2V0X21vZGUoc3RydWN0IGNk bnMzICpjZG5zLCBlbnVtIHVzYl9kcl9tb2RlIG1vZGUpCj4gK3sKPiArCWludCByZXQgPSAwOwo+ ICsJdTMyIHJlZzsKPiArCj4gKwljZG5zLT5jdXJyZW50X2RyX21vZGUgPSBtb2RlOwo+ICsKPiAr CXN3aXRjaCAobW9kZSkgewo+ICsJY2FzZSBVU0JfRFJfTU9ERV9QRVJJUEhFUkFMOgo+ICsJCWRl dl9pbmZvKGNkbnMtPmRldiwgIlNldCBjb250cm9sbGVyIHRvIEdhZGdldCBtb2RlXG4iKTsKCmRl dl9kYmcoKT8KCj4gKwkJcmV0ID0gY2RuczNfZHJkX3N3aXRjaF9nYWRnZXQoY2RucywgMSk7Cj4g KwkJYnJlYWs7Cj4gKwljYXNlIFVTQl9EUl9NT0RFX0hPU1Q6Cj4gKwkJZGV2X2luZm8oY2Rucy0+ ZGV2LCAiU2V0IGNvbnRyb2xsZXIgdG8gSG9zdCBtb2RlXG4iKTsKCmRldl9kYmcoKQoKPiArCQly ZXQgPSBjZG5zM19kcmRfc3dpdGNoX2hvc3QoY2RucywgMSk7Cj4gKwkJYnJlYWs7Cj4gKwljYXNl IFVTQl9EUl9NT0RFX09URzoKPiArCQlkZXZfaW5mbyhjZG5zLT5kZXYsICJTZXQgY29udHJvbGxl ciB0byBPVEcgbW9kZVxuIik7CgpkZXZfZGJnKCkKCj4gKwkJaWYgKGNkbnMtPnZlcnNpb24gPT0g Q0ROUzNfQ09OVFJPTExFUl9WMSkgewo+ICsJCQlyZWcgPSByZWFkbCgmY2Rucy0+b3RnX3YxX3Jl Z3MtPm92ZXJyaWRlKTsKPiArCQkJcmVnIHw9IE9WRVJSSURFX0lEUFVMTFVQOwo+ICsJCQl3cml0 ZWwocmVnLCAmY2Rucy0+b3RnX3YxX3JlZ3MtPm92ZXJyaWRlKTsKPiArCQl9IGVsc2Ugewo+ICsJ CQlyZWcgPSByZWFkbCgmY2Rucy0+b3RnX3YwX3JlZ3MtPmN0cmwxKTsKPiArCQkJcmVnIHw9IE9W RVJSSURFX0lEUFVMTFVQX1YwOwo+ICsJCQl3cml0ZWwocmVnLCAmY2Rucy0+b3RnX3YwX3JlZ3Mt PmN0cmwxKTsKPiArCQl9Cj4gKwoKRG9uJ3QgeW91IGhhdmUgdG8gY2xlYXIgSURQVUxMVVAgd2hl biB5b3Ugc3dpdGNoIHRvIFBFUklQSEVSQUwgb3IgSE9TVCBtb2RlPwoKPiArCQkvKgo+ICsJCSAq IEhhcmR3YXJlIHNwZWNpZmljYXRpb24gc2F5czogIklEX1ZBTFVFIG11c3QgYmUgdmFsaWQgd2l0 aGluCj4gKwkJICogNTBtcyBhZnRlciBpZHB1bGx1cCBpcyBzZXQgdG8gJzEiIHNvIGRyaXZlciBt dXN0IHdhaXQKPiArCQkgKiA1MG1zIGJlZm9yZSByZWFkaW5nIHRoaXMgcGluLgo+ICsJCSAqLwo+ ICsJCXVzbGVlcF9yYW5nZSg1MDAwMCwgNjAwMDApOwo+ICsJCWJyZWFrOwo+ICsJZGVmYXVsdDoK PiArCQljZG5zLT5jdXJyZW50X2RyX21vZGUgPSBVU0JfRFJfTU9ERV9VTktOT1dOOwo+ICsJCWRl dl9lcnIoY2Rucy0+ZGV2LCAiVW5zdXBwb3J0ZWQgbW9kZSBvZiBvcGVyYXRpb24gJWRcbiIsIG1v ZGUpOwo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsJfQo+ICsKPiArCXJldHVybiByZXQ7Cj4gK30K PiArCj4gK2ludCBjZG5zM19nZXRfaWQoc3RydWN0IGNkbnMzICpjZG5zKQo+ICt7Cj4gKwlpbnQg aWQ7Cj4gKwo+ICsJaWQgPSByZWFkbCgmY2Rucy0+b3RnX3JlZ3MtPnN0cykgJiBPVEdTVFNfSURf VkFMVUU7Cj4gKwlkZXZfZGJnKGNkbnMtPmRldiwgIk9URyBJRDogJWQiLCBpZCk7Cj4gKwlyZXR1 cm4gaWQ7Cj4gK30KPiArCj4gK2ludCBjZG5zM19pc19ob3N0KHN0cnVjdCBjZG5zMyAqY2RucykK PiArewo+ICsJaWYgKGNkbnMtPmN1cnJlbnRfZHJfbW9kZSA9PSBVU0JfRFJfTU9ERV9IT1NUKQo+ ICsJCXJldHVybiAxOwoKZG9uJ3QgeW91IGhhdmUgdG8gcmV0dXJuIDAgaWYgY3VycmVudF9kcl9t b2RlID09IFVTQl9EUl9NT0RFX1BFUklQSEVSQUw/Cgo+ICsJZWxzZSBpZiAoIWNkbnMzX2dldF9p ZChjZG5zKSkKPiArCQlyZXR1cm4gMTsKPiArCj4gKwlyZXR1cm4gMDsKPiArfQo+ICsKPiAraW50 IGNkbnMzX2lzX2RldmljZShzdHJ1Y3QgY2RuczMgKmNkbnMpCj4gK3sKPiArCWlmIChjZG5zLT5j dXJyZW50X2RyX21vZGUgPT0gVVNCX0RSX01PREVfUEVSSVBIRVJBTCkKPiArCQlyZXR1cm4gMTsK CmRvbid0IHlvdSBoYXZlIHRvIHJldHVybiAwIGlmIGN1cnJlbnRfZHJfbW9kZSA9PSBVU0JfRFJf TU9ERV9IT1NUPwoKPiArCWVsc2UgaWYgKGNkbnMtPmN1cnJlbnRfZHJfbW9kZSA9PSBVU0JfRFJf TU9ERV9PVEcpCj4gKwkJaWYgKGNkbnMzX2dldF9pZChjZG5zKSkKPiArCQkJcmV0dXJuIDE7Cj4g Kwo+ICsJcmV0dXJuIDA7Cj4gK30KPiArCj4gKy8qKgo+ICsgKiBjZG5zM19vdGdfZGlzYWJsZV9p cnEgLSBEaXNhYmxlIGFsbCBPVEcgaW50ZXJydXB0cwo+ICsgKiBAY2RuczogUG9pbnRlciB0byBj b250cm9sbGVyIGNvbnRleHQgc3RydWN0dXJlCj4gKyAqLwo+ICtzdGF0aWMgdm9pZCBjZG5zM19v dGdfZGlzYWJsZV9pcnEoc3RydWN0IGNkbnMzICpjZG5zKQo+ICt7Cj4gKwl3cml0ZWwoMCwgJmNk bnMtPm90Z19yZWdzLT5pZW4pOwo+ICt9Cj4gKwo+ICsvKioKPiArICogY2RuczNfb3RnX2VuYWJs ZV9pcnEgLSBlbmFibGUgaWQgYW5kIHNlc3NfdmFsaWQgaW50ZXJydXB0cwo+ICsgKiBAY2Ruczog UG9pbnRlciB0byBjb250cm9sbGVyIGNvbnRleHQgc3RydWN0dXJlCj4gKyAqLwo+ICtzdGF0aWMg dm9pZCBjZG5zM19vdGdfZW5hYmxlX2lycShzdHJ1Y3QgY2RuczMgKmNkbnMpCj4gK3sKPiArCXdy aXRlbChPVEdJRU5fSURfQ0hBTkdFX0lOVCB8IE9UR0lFTl9WQlVTVkFMSURfUklTRV9JTlQgfAo+ ICsJICAgICAgIE9UR0lFTl9WQlVTVkFMSURfRkFMTF9JTlQsICZjZG5zLT5vdGdfcmVncy0+aWVu KTsKPiArfQo+ICsKPiArLyoqCj4gKyAqIGNkbnMzX2RyZF9zd2l0Y2hfaG9zdCAtIHN0YXJ0L3N0 b3AgaG9zdAo+ICsgKiBAY2RuczogUG9pbnRlciB0byBjb250cm9sbGVyIGNvbnRleHQgc3RydWN0 dXJlCj4gKyAqIEBvbjogMSBmb3Igc3RhcnQsIDAgZm9yIHN0b3AKPiArICoKPiArICogUmV0dXJu cyAwIG9uIHN1Y2Nlc3Mgb3RoZXJ3aXNlIG5lZ2F0aXZlIGVycm5vCj4gKyAqLwo+ICtzdGF0aWMg aW50IGNkbnMzX2RyZF9zd2l0Y2hfaG9zdChzdHJ1Y3QgY2RuczMgKmNkbnMsIGludCBvbikKPiAr ewo+ICsJaW50IHJldDsKPiArCXUzMiByZWcgPSBPVEdDTURfT1RHX0RJUzsKPiArCj4gKwkvKiBz d2l0Y2ggT1RHIGNvcmUgKi8KPiArCWlmIChvbikgewo+ICsJCXdyaXRlbChPVEdDTURfSE9TVF9C VVNfUkVRIHwgcmVnLCAmY2Rucy0+b3RnX3JlZ3MtPmNtZCk7Cj4gKwo+ICsJCWRldl9kYmcoY2Ru cy0+ZGV2LCAiV2FpdGluZyBmb3IgSG9zdCBtb2RlIGlzIHR1cm5lZCBvblxuIik7CnMvZm9yL3Rp bGwKCj4gKwkJcmV0ID0gY2RuczNfaGFuZHNoYWtlKCZjZG5zLT5vdGdfcmVncy0+c3RzLCBPVEdT VFNfWEhDSV9SRUFEWSwKPiArCQkJCSAgICAgIE9UR1NUU19YSENJX1JFQURZLCAxMDAwMDApOwo+ ICsKPiArCQlpZiAocmV0KQo+ICsJCQlyZXR1cm4gcmV0Owo+ICsJfSBlbHNlIHsKPiArCQl1c2xl ZXBfcmFuZ2UoMzAsIDQwKTsKPiArCQl3cml0ZWwoT1RHQ01EX0hPU1RfQlVTX0RST1AgfCBPVEdD TURfREVWX0JVU19EUk9QIHwKPiArCQkgICAgICAgT1RHQ01EX0RFVl9QT1dFUl9PRkYgfCBPVEdD TURfSE9TVF9QT1dFUl9PRkYsCj4gKwkJICAgICAgICZjZG5zLT5vdGdfcmVncy0+Y21kKTsKPiAr CQl1c2xlZXBfcmFuZ2UoMzAwMCwgNDAwMCk7Cgp3aHkgZG8geW91IG5lZWQgZGVsYXlzIGJlZm9y ZSBhbmQgYWZ0ZXIgdGhlIHdyaXRlPwo+ICsJfQo+ICsKPiArCXJldHVybiAwOwo+ICt9Cj4gKwo+ ICsvKioKPiArICogY2RuczNfZHJkX3N3aXRjaF9nYWRnZXQgLSBzdGFydC9zdG9wIGdhZGdldAo+ ICsgKiBAY2RuczogUG9pbnRlciB0byBjb250cm9sbGVyIGNvbnRleHQgc3RydWN0dXJlCj4gKyAq IEBvbjogMSBmb3Igc3RhcnQsIDAgZm9yIHN0b3AKPiArICoKPiArICogUmV0dXJucyAwIG9uIHN1 Y2Nlc3Mgb3RoZXJ3aXNlIG5lZ2F0aXZlIGVycm5vCj4gKyAqLwo+ICtzdGF0aWMgaW50IGNkbnMz X2RyZF9zd2l0Y2hfZ2FkZ2V0KHN0cnVjdCBjZG5zMyAqY2RucywgaW50IG9uKQo+ICt7Cj4gKwlp bnQgcmV0Owo+ICsJdTMyIHJlZyA9IE9UR0NNRF9PVEdfRElTOwo+ICsKPiArCS8qIHN3aXRjaCBP VEcgY29yZSAqLwo+ICsJaWYgKG9uKSB7Cj4gKwkJd3JpdGVsKE9UR0NNRF9ERVZfQlVTX1JFUSB8 IHJlZywgJmNkbnMtPm90Z19yZWdzLT5jbWQpOwo+ICsKPiArCQlkZXZfZGJnKGNkbnMtPmRldiwg IldhaXRpbmcgZm9yIERldmljZSBtb2RlIGlzIHR1cm5lZCBvblxuIik7CgpzL2Zvci90aWxsCgo+ ICsKPiArCQlyZXQgPSBjZG5zM19oYW5kc2hha2UoJmNkbnMtPm90Z19yZWdzLT5zdHMsIE9UR1NU U19ERVZfUkVBRFksCj4gKwkJCQkgICAgICBPVEdTVFNfREVWX1JFQURZLCAxMDAwMDApOwo+ICsK PiArCQlpZiAocmV0KQo+ICsJCQlyZXR1cm4gcmV0Owo+ICsJfSBlbHNlIHsKPiArCQkvKgo+ICsJ CSAqIGRyaXZlciBzaG91bGQgd2FpdCBhdCBsZWFzdCAxMHVzIGFmdGVyIGRpc2FibGluZyBEZXZp Y2UKPiArCQkgKiBiZWZvcmUgdHVybmluZy1vZmYgRGV2aWNlIChERVZfQlVTX0RST1ApCj4gKwkJ ICovCj4gKwkJdXNsZWVwX3JhbmdlKDIwLCAzMCk7Cj4gKwkJd3JpdGVsKE9UR0NNRF9IT1NUX0JV U19EUk9QIHwgT1RHQ01EX0RFVl9CVVNfRFJPUCB8Cj4gKwkJICAgICAgIE9UR0NNRF9ERVZfUE9X RVJfT0ZGIHwgT1RHQ01EX0hPU1RfUE9XRVJfT0ZGLAo+ICsJCSAgICAgICAmY2Rucy0+b3RnX3Jl Z3MtPmNtZCk7Cj4gKwkJdXNsZWVwX3JhbmdlKDMwMDAsIDQwMDApOwoKd2h5IGRvIHlvdSBuZWVk IGEgZGVsYXkgYWZ0ZXIgdGhlIHdyaXRlPwoKPiArCX0KPiArCj4gKwlyZXR1cm4gMDsKPiArfQo+ ICsKPiArLyoqCj4gKyAqIGNkbnMzX2luaXRfb3RnX21vZGUgLSBpbml0aWFsaXplIGRyZCBjb250 cm9sbGVyCj4gKyAqIEBjZG5zOiBQb2ludGVyIHRvIGNvbnRyb2xsZXIgY29udGV4dCBzdHJ1Y3R1 cmUKPiArICoKPiArICogUmV0dXJucyAwIG9uIHN1Y2Nlc3Mgb3RoZXJ3aXNlIG5lZ2F0aXZlIGVy cm5vCj4gKyAqLwo+ICtzdGF0aWMgaW50IGNkbnMzX2luaXRfb3RnX21vZGUoc3RydWN0IGNkbnMz ICpjZG5zKQo+ICt7Cj4gKwlpbnQgcmV0ID0gMDsKPiArCj4gKwljZG5zM19vdGdfZGlzYWJsZV9p cnEoY2Rucyk7Cj4gKwkvKiBjbGVhciBhbGwgaW50ZXJydXB0cyAqLwo+ICsJd3JpdGVsKH4wLCAm Y2Rucy0+b3RnX3JlZ3MtPml2ZWN0KTsKPiArCj4gKwlyZXQgPSBjZG5zM19zZXRfbW9kZShjZG5z LCBVU0JfRFJfTU9ERV9PVEcpOwo+ICsJaWYgKHJldCkKPiArCQlyZXR1cm4gcmV0Owo+ICsKPiAr CWlmIChjZG5zM19pc19ob3N0KGNkbnMpKQo+ICsJCXJldCA9IGNkbnMzX2RyZF9zd2l0Y2hfaG9z dChjZG5zLCAxKTsKPiArCWVsc2UKPiArCQlyZXQgPSBjZG5zM19kcmRfc3dpdGNoX2dhZGdldChj ZG5zLCAxKTsKPiArCj4gKwlpZiAocmV0KQo+ICsJCXJldHVybiByZXQ7Cj4gKwo+ICsJY2RuczNf b3RnX2VuYWJsZV9pcnEoY2Rucyk7CgpTY2hlZHVsZSBzd2l0Y2ggd29ya3F1ZXVlIHRvIGRlYWwg d2l0aCB1cGRhdGVkIElEIHN0YXRlPwoKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gKy8qKgo+ ICsgKiBjZG5zM19kcmRfdXBkYXRlX21vZGUgLSBpbml0aWFsaXplIG1vZGUgb2Ygb3BlcmF0aW9u Cj4gKyAqIEBjZG5zOiBQb2ludGVyIHRvIGNvbnRyb2xsZXIgY29udGV4dCBzdHJ1Y3R1cmUKPiAr ICoKPiArICogUmV0dXJucyAwIG9uIHN1Y2Nlc3Mgb3RoZXJ3aXNlIG5lZ2F0aXZlIGVycm5vCj4g KyAqLwo+ICtpbnQgY2RuczNfZHJkX3VwZGF0ZV9tb2RlKHN0cnVjdCBjZG5zMyAqY2RucykKPiAr ewo+ICsJaW50IHJldCA9IDA7Cj4gKwo+ICsJaWYgKGNkbnMtPmRlc2lyZWRfZHJfbW9kZSA9PSBj ZG5zLT5jdXJyZW50X2RyX21vZGUpCj4gKwkJcmV0dXJuIHJldDsKPiArCj4gKwljZG5zM19kcmRf c3dpdGNoX2dhZGdldChjZG5zLCAwKTsKPiArCWNkbnMzX2RyZF9zd2l0Y2hfaG9zdChjZG5zLCAw KTsKCldoeSBhcmUgeW91IHN0b3BwaW5nIGdhZGdldC9ob3N0IGhlcmU/Ck9uZSBvciBib3RoIG9m IG1pZ2h0IG5vdCBoYXZlIGJlZW4gc3RhcnRlZC4KCj4gKwo+ICsJc3dpdGNoIChjZG5zLT5kZXNp cmVkX2RyX21vZGUpIHsKPiArCWNhc2UgVVNCX0RSX01PREVfUEVSSVBIRVJBTDoKPiArCQlyZXQg PSBjZG5zM19zZXRfbW9kZShjZG5zLCBVU0JfRFJfTU9ERV9QRVJJUEhFUkFMKTsKPiArCQlicmVh azsKPiArCWNhc2UgVVNCX0RSX01PREVfSE9TVDoKPiArCQlyZXQgPSBjZG5zM19zZXRfbW9kZShj ZG5zLCBVU0JfRFJfTU9ERV9IT1NUKTsKPiArCQlicmVhazsKPiArCWNhc2UgVVNCX0RSX01PREVf T1RHOgo+ICsJCXJldCA9IGNkbnMzX2luaXRfb3RnX21vZGUoY2Rucyk7Cj4gKwkJYnJlYWs7Cj4g KwlkZWZhdWx0Ogo+ICsJCWRldl9lcnIoY2Rucy0+ZGV2LCAiVW5zdXBwb3J0ZWQgbW9kZSBvZiBv cGVyYXRpb24gJWRcbiIsCj4gKwkJCWNkbnMtPmRyX21vZGUpOwo+ICsJCXJldHVybiAtRUlOVkFM Owo+ICsJfQo+ICsKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gKy8qKgo+ICsgKiBjZG5zM19k cmRfaXJxIC0gaW50ZXJydXB0IGhhbmRsZXIgZm9yIE9URyBldmVudHMKPiArICoKPiArICogQGly cTogaXJxIG51bWJlciBmb3IgY2RuczMgY29yZSBkZXZpY2UKPiArICogQGRhdGE6IHN0cnVjdHVy ZSBvZiBjZG5zMwo+ICsgKgo+ICsgKiBSZXR1cm5zIElSUV9IQU5ETEVEIG9yIElSUV9OT05FCj4g KyAqLwo+ICtzdGF0aWMgaXJxcmV0dXJuX3QgY2RuczNfZHJkX2lycShpbnQgaXJxLCB2b2lkICpk YXRhKQo+ICt7Cj4gKwlpcnFyZXR1cm5fdCByZXQgPSBJUlFfTk9ORTsKPiArCXN0cnVjdCBjZG5z MyAqY2RucyA9IGRhdGE7Cj4gKwl1MzIgcmVnOwo+ICsKPiArCWlmIChjZG5zLT5kcl9tb2RlICE9 IFVTQl9EUl9NT0RFX09URykKPiArCQlyZXR1cm4gcmV0Owo+ICsKPiArCXJlZyA9IHJlYWRsKCZj ZG5zLT5vdGdfcmVncy0+aXZlY3QpOwo+ICsKPiArCWlmICghcmVnKQo+ICsJCXJldHVybiByZXQ7 Cj4gKwo+ICsJaWYgKHJlZyAmIE9UR0lFTl9JRF9DSEFOR0VfSU5UKSB7Cj4gKwkJZGV2X2RiZyhj ZG5zLT5kZXYsICJPVEcgSVJROiBuZXcgSUQ6ICVkXG4iLAo+ICsJCQljZG5zM19nZXRfaWQoY2Ru cykpOwo+ICsKPiArCQlxdWV1ZV93b3JrKHN5c3RlbV9mcmVlemFibGVfd3EsICZjZG5zLT5yb2xl X3N3aXRjaF93cSk7Cj4gKwo+ICsJCXJldCA9IElSUV9IQU5ETEVEOwo+ICsJfQo+ICsKPiArCXdy aXRlbCh+MCwgJmNkbnMtPm90Z19yZWdzLT5pdmVjdCk7Cj4gKwlyZXR1cm4gcmV0Owo+ICt9Cj4g Kwo+ICtpbnQgY2RuczNfZHJkX2luaXQoc3RydWN0IGNkbnMzICpjZG5zKQo+ICt7Cj4gKwl2b2lk IF9faW9tZW0gKnJlZ3M7Cj4gKwlpbnQgcmV0ID0gMDsKPiArCXUzMiBzdGF0ZTsKPiArCj4gKwly ZWdzID0gZGV2bV9pb3JlbWFwX3Jlc291cmNlKGNkbnMtPmRldiwgJmNkbnMtPm90Z19yZXMpOwo+ ICsJaWYgKElTX0VSUihyZWdzKSkKPiArCQlyZXR1cm4gUFRSX0VSUihyZWdzKTsKPiArCj4gKwkv KiBEZXRlY3Rpb24gb2YgRFJEIHZlcnNpb24uIENvbnRyb2xsZXIgaGFzIGJlZW4gcmVsZWFzZWQK PiArCSAqIGluIHR3byB2ZXJzaW9ucy4gQm90aCBhcmUgc2ltaWxhciwgYnV0IHRoZXkgaGF2ZSBz YW1lIGNoYW5nZXMKPiArCSAqIGluIHJlZ2lzdGVyIG1hcHMuCj4gKwkgKiBUaGUgZmlyc3QgcmVn aXN0ZXIgaW4gb2xkIHZlcnNpb24gaXMgY29tbWFuZCByZWdpc3RlciBhbmQgaXQncyByZWFkCj4g KwkgKiBvbmx5LCBzbyBkcml2ZXIgc2hvdWxkIHJlYWQgMCBmcm9tIGl0LiBPbiB0aGUgb3RoZXIg aGFuZCwgaW4gdjEKPiArCSAqIHRoZSBmaXJzdCByZWdpc3RlciBjb250YWlucyBkZXZpY2UgSUQg bnVtYmVyIHdoaWNoIGlzIG5vdCBzZXQgdG8gMC4KPiArCSAqIERyaXZlciB1c2VzIHRoaXMgZmFj dCB0byBkZXRlY3QgdGhlIHByb3BlciB2ZXJzaW9uIG9mCj4gKwkgKiBjb250cm9sbGVyLgo+ICsJ ICovCj4gKwljZG5zLT5vdGdfdjBfcmVncyA9IHJlZ3M7Cj4gKwlpZiAoIXJlYWRsKCZjZG5zLT5v dGdfdjBfcmVncy0+Y21kKSkgewo+ICsJCWNkbnMtPnZlcnNpb24gID0gQ0ROUzNfQ09OVFJPTExF Ul9WMDsKPiArCQljZG5zLT5vdGdfdjFfcmVncyA9IE5VTEw7Cj4gKwkJY2Rucy0+b3RnX3JlZ3Mg PSByZWdzOwo+ICsJCWRldl9pbmZvKGNkbnMtPmRldiwgIkRSRCB2ZXJzaW9uIHYwICglMDh4KVxu IiwKPiArCQkJIHJlYWRsKCZjZG5zLT5vdGdfdjBfcmVncy0+dmVyc2lvbikpOwo+ICsJfSBlbHNl IHsKPiArCQljZG5zLT5vdGdfdjBfcmVncyA9IE5VTEw7Cj4gKwkJY2Rucy0+b3RnX3YxX3JlZ3Mg PSByZWdzOwo+ICsJCWNkbnMtPm90Z19yZWdzID0gKHZvaWQgKikmY2Rucy0+b3RnX3YxX3JlZ3Mt PmNtZDsKPiArCQljZG5zLT52ZXJzaW9uICA9IENETlMzX0NPTlRST0xMRVJfVjE7Cj4gKwkJZGV2 X2luZm8oY2Rucy0+ZGV2LCAiRFJEIHZlcnNpb24gdjEgKElEOiAlMDh4LCByZXY6ICUwOHgpXG4i LAo+ICsJCQkgcmVhZGwoJmNkbnMtPm90Z192MV9yZWdzLT5kaWQpLAo+ICsJCQkgcmVhZGwoJmNk bnMtPm90Z192MV9yZWdzLT5yaWQpKTsKPiArCX0KPiArCj4gKwlzdGF0ZSA9IE9UR1NUU19TVFJB UChyZWFkbCgmY2Rucy0+b3RnX3JlZ3MtPnN0cykpOwo+ICsKPiArCS8qIFVwZGF0ZSBkcl9tb2Rl IGFjY29yZGluZyB0byBTVFJBUCBjb25maWd1cmF0aW9uLiAqLwo+ICsJY2Rucy0+ZHJfbW9kZSA9 IFVTQl9EUl9NT0RFX09URzsKPiArCWlmIChzdGF0ZSA9PSBPVEdTVFNfU1RSQVBfSE9TVCkgewo+ ICsJCWRldl9pbmZvKGNkbnMtPmRldiwgIkNvbnRyb2xsZXIgc3RyYXBwZWQgdG8gSE9TVFxuIik7 Cj4gKwkJY2Rucy0+ZHJfbW9kZSA9IFVTQl9EUl9NT0RFX0hPU1Q7Cj4gKwl9IGVsc2UgaWYgKHN0 YXRlID09IE9UR1NUU19TVFJBUF9HQURHRVQpIHsKPiArCQlkZXZfaW5mbyhjZG5zLT5kZXYsICJD b250cm9sbGVyIHN0cmFwcGVkIHRvIFBFUklQSEVSQUxcbiIpOwo+ICsJCWNkbnMtPmRyX21vZGUg PSBVU0JfRFJfTU9ERV9QRVJJUEhFUkFMOwo+ICsJfQo+ICsKPiArCWNkbnMtPmRlc2lyZWRfZHJf bW9kZSA9IGNkbnMtPmRyX21vZGU7Cj4gKwljZG5zLT5jdXJyZW50X2RyX21vZGUgPSBVU0JfRFJf TU9ERV9VTktOT1dOOwo+ICsKPiArCXJldCA9IGRldm1fcmVxdWVzdF90aHJlYWRlZF9pcnEoY2Ru cy0+ZGV2LCBjZG5zLT5pcnEsIGNkbnMzX2RyZF9pcnEsCj4gKwkJCQkJTlVMTCwgSVJRRl9TSEFS RUQsCj4gKwkJCQkJZGV2X25hbWUoY2Rucy0+ZGV2KSwgY2Rucyk7Cj4gKwo+ICsJaWYgKHJldCkK PiArCQlyZXR1cm4gcmV0Owo+ICsKPiArCXN0YXRlID0gcmVhZGwoJmNkbnMtPm90Z19yZWdzLT5z dHMpOwo+ICsJaWYgKE9UR1NUU19PVEdfTlJEWShzdGF0ZSkgIT0gMCkgewo+ICsJCWRldl9lcnIo Y2Rucy0+ZGV2LCAiQ2FkZW5jZSBVU0IzIE9URyBkZXZpY2Ugbm90IHJlYWR5XG4iKTsKPiArCQly ZXR1cm4gLUVOT0RFVjsKPiArCX0KPiArCj4gKwlyZXQgPSBjZG5zM19kcmRfdXBkYXRlX21vZGUo Y2Rucyk7Cj4gKwo+ICsJcmV0dXJuIHJldDsKPiArfQo+ICsKPiAraW50IGNkbnMzX2RyZF9leGl0 KHN0cnVjdCBjZG5zMyAqY2RucykKPiArewo+ICsJcmV0dXJuIGNkbnMzX2RyZF9zd2l0Y2hfaG9z dChjZG5zLCAwKTsKCldoeSBvbmx5IHN0b3BwaW5nIGhvc3Q/CgpJIHRoaW5rIHdlIG5lZWQgdG8g c3RvcCBhY3RpdmUgcm9sZSwgZGlzYWJsZSBJUlEgZ2VuZXJhdGlvbiBhbmQgZnJlZSBpcnE/Cgo+ ICt9Cgo8c25pcD4KCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvdXNiL2NkbnMzL2dhZGdldC5jIGIv ZHJpdmVycy91c2IvY2RuczMvZ2FkZ2V0LmMKPiBuZXcgZmlsZSBtb2RlIDEwMDY0NAo+IGluZGV4 IDAwMDAwMDAwMDAwMC4uN2Y3ZjI0ZWUzYzRiCj4gLS0tIC9kZXYvbnVsbAo+ICsrKyBiL2RyaXZl cnMvdXNiL2NkbnMzL2dhZGdldC5jCj4gQEAgLTAsMCArMSwyMDAzIEBACj4gKy8vIFNQRFgtTGlj ZW5zZS1JZGVudGlmaWVyOiBHUEwtMi4wCj4gKy8qCj4gKyAqIENhZGVuY2UgVVNCU1MgRFJEIERy aXZlciAtIGdhZGdldCBzaWRlLgo+ICsgKgo+ICsgKiBDb3B5cmlnaHQgKEMpIDIwMTggQ2FkZW5j ZSBEZXNpZ24gU3lzdGVtcy4KPiArICogQ29weXJpZ2h0IChDKSAyMDE3LTIwMTggTlhQCj4gKyAq Cj4gKyAqIEF1dGhvcnM6IFBhd2VsIEpleiA8cGplekBjYWRlbmNlLmNvbT4sCj4gKyAqICAgICAg ICAgIFBhd2VsIExhc3pjemFrIDxwYXdlbGxAY2FkZW5jZS5jb20+Cj4gKyAqCSAgICBQZXRlciBD aGVuIDxwZXRlci5jaGVuQG54cC5jb20+Cj4gKyAqLwo+ICsKCjxzbmlwPgoKPiArCj4gK3N0YXRp YyB2b2lkIGNkbnMzX2dhZGdldF9kaXNhYmxlKHN0cnVjdCBjZG5zMyAqY2RucykKPiArewo+ICsJ c3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXY7Cj4gKwo+ICsJcHJpdl9kZXYgPSBjZG5zLT5n YWRnZXRfZGV2Owo+ICsKPiArCWlmIChwcml2X2Rldi0+Z2FkZ2V0X2RyaXZlcikKPiArCQlwcml2 X2Rldi0+Z2FkZ2V0X2RyaXZlci0+ZGlzY29ubmVjdCgmcHJpdl9kZXYtPmdhZGdldCk7PiArCj4g Kwl1c2JfZ2FkZ2V0X2Rpc2Nvbm5lY3QoJnByaXZfZGV2LT5nYWRnZXQpOwo+ICsJcHJpdl9kZXYt PmdhZGdldC5zcGVlZCA9IFVTQl9TUEVFRF9VTktOT1dOOwo+ICt9Cj4gKwo+ICt2b2lkIGNkbnMz X2dhZGdldF9leGl0KHN0cnVjdCBjZG5zMyAqY2RucykKPiArewo+ICsJc3RydWN0IGNkbnMzX2Rl dmljZSAqcHJpdl9kZXY7Cj4gKwo+ICsJcHJpdl9kZXYgPSBjZG5zLT5nYWRnZXRfZGV2Owo+ICsK PiArCWNkbnMzX2dhZGdldF9kaXNhYmxlKGNkbnMpOwo+ICsKPiArCWRldm1fZnJlZV9pcnEoY2Ru cy0+ZGV2LCBjZG5zLT5pcnEsIGNkbnMpOwo+ICsKPiArCXBtX3J1bnRpbWVfbWFya19sYXN0X2J1 c3koY2Rucy0+ZGV2KTsKPiArCXBtX3J1bnRpbWVfcHV0X2F1dG9zdXNwZW5kKGNkbnMtPmRldik7 Cj4gKwo+ICsJdXNiX2RlbF9nYWRnZXRfdWRjKCZwcml2X2Rldi0+Z2FkZ2V0KTsKPiArCj4gKwlj ZG5zM19mcmVlX2FsbF9lcHMocHJpdl9kZXYpOwo+ICsKPiArCWRtYV9mcmVlX2NvaGVyZW50KHBy aXZfZGV2LT5zeXNkZXYsIDgsIHByaXZfZGV2LT5zZXR1cF9idWYsCj4gKwkJCSAgcHJpdl9kZXYt PnNldHVwX2RtYSk7Cj4gKwo+ICsJa2ZyZWUocHJpdl9kZXYtPnpscF9idWYpOwo+ICsJa2ZyZWUo cHJpdl9kZXYpOwo+ICsJY2Rucy0+Z2FkZ2V0X2RldiA9IE5VTEw7Cj4gK30KPiArCj4gK3N0YXRp YyBpbnQgY2RuczNfZ2FkZ2V0X3N0YXJ0KHN0cnVjdCBjZG5zMyAqY2RucykKPiArewo+ICsJc3Ry dWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXY7Cj4gKwl1MzIgbWF4X3NwZWVkOwo+ICsJaW50IHJl dDsKPiArCj4gKwlwcml2X2RldiA9IGt6YWxsb2Moc2l6ZW9mKCpwcml2X2RldiksIEdGUF9LRVJO RUwpOwo+ICsJaWYgKCFwcml2X2RldikKPiArCQlyZXR1cm4gLUVOT01FTTsKPiArCj4gKwljZG5z LT5nYWRnZXRfZGV2ID0gcHJpdl9kZXY7Cj4gKwlwcml2X2Rldi0+c3lzZGV2ID0gY2Rucy0+ZGV2 Owo+ICsJcHJpdl9kZXYtPmRldiA9IGNkbnMtPmRldjsKPiArCXByaXZfZGV2LT5yZWdzID0gY2Ru cy0+ZGV2X3JlZ3M7Cj4gKwo+ICsJbWF4X3NwZWVkID0gdXNiX2dldF9tYXhpbXVtX3NwZWVkKGNk bnMtPmRldik7Cj4gKwo+ICsJLyogQ2hlY2sgdGhlIG1heGltdW1fc3BlZWQgcGFyYW1ldGVyICov Cj4gKwlzd2l0Y2ggKG1heF9zcGVlZCkgewo+ICsJY2FzZSBVU0JfU1BFRURfRlVMTDoKPiArCWNh c2UgVVNCX1NQRUVEX0hJR0g6Cj4gKwljYXNlIFVTQl9TUEVFRF9TVVBFUjoKPiArCQlicmVhazsK PiArCWRlZmF1bHQ6Cj4gKwkJZGV2X2VycihjZG5zLT5kZXYsICJpbnZhbGlkIG1heGltdW1fc3Bl ZWQgcGFyYW1ldGVyICVkXG4iLAo+ICsJCQltYXhfc3BlZWQpOwo+ICsJCS8qIGZhbGwgdGhyb3Vn aCAqLwo+ICsJY2FzZSBVU0JfU1BFRURfVU5LTk9XTjoKPiArCQkvKiBkZWZhdWx0IHRvIHN1cGVy c3BlZWQgKi8KPiArCQltYXhfc3BlZWQgPSBVU0JfU1BFRURfU1VQRVI7Cj4gKwkJYnJlYWs7Cj4g Kwl9Cj4gKwo+ICsJLyogZmlsbCBnYWRnZXQgZmllbGRzICovCj4gKwlwcml2X2Rldi0+Z2FkZ2V0 Lm1heF9zcGVlZCA9IG1heF9zcGVlZDsKPiArCXByaXZfZGV2LT5nYWRnZXQuc3BlZWQgPSBVU0Jf U1BFRURfVU5LTk9XTjsKPiArCXByaXZfZGV2LT5nYWRnZXQub3BzID0gJmNkbnMzX2dhZGdldF9v cHM7Cj4gKwlwcml2X2Rldi0+Z2FkZ2V0Lm5hbWUgPSAidXNiLXNzLWdhZGdldCI7Cj4gKwlwcml2 X2Rldi0+Z2FkZ2V0LnNnX3N1cHBvcnRlZCA9IDE7Cj4gKwo+ICsJc3Bpbl9sb2NrX2luaXQoJnBy aXZfZGV2LT5sb2NrKTsKPiArCUlOSVRfV09SSygmcHJpdl9kZXYtPnBlbmRpbmdfc3RhdHVzX3dx LAo+ICsJCSAgY2RuczNfcGVuZGluZ19zZXR1cF9zdGF0dXNfaGFuZGxlcik7Cj4gKwo+ICsJLyog aW5pdGlhbGl6ZSBlbmRwb2ludCBjb250YWluZXIgKi8KPiArCUlOSVRfTElTVF9IRUFEKCZwcml2 X2Rldi0+Z2FkZ2V0LmVwX2xpc3QpOwo+ICsKPiArCXJldCA9IGNkbnMzX2luaXRfZXBzKHByaXZf ZGV2KTsKPiArCWlmIChyZXQpIHsKPiArCQlkZXZfZXJyKHByaXZfZGV2LT5kZXYsICJGYWlsZWQg dG8gY3JlYXRlIGVuZHBvaW50c1xuIik7Cj4gKwkJZ290byBlcnIxOwo+ICsJfQo+ICsKPiArCS8q IGFsbG9jYXRlIG1lbW9yeSBmb3Igc2V0dXAgcGFja2V0IGJ1ZmZlciAqLwo+ICsJcHJpdl9kZXYt PnNldHVwX2J1ZiA9IGRtYV9hbGxvY19jb2hlcmVudChwcml2X2Rldi0+c3lzZGV2LCA4LAo+ICsJ CQkJCQkgJnByaXZfZGV2LT5zZXR1cF9kbWEsIEdGUF9ETUEpOwo+ICsJaWYgKCFwcml2X2Rldi0+ c2V0dXBfYnVmKSB7Cj4gKwkJZGV2X2Vycihwcml2X2Rldi0+ZGV2LCAiRmFpbGVkIHRvIGFsbG9j YXRlIG1lbW9yeSBmb3IgU0VUVVAgYnVmZmVyXG4iKTsKPiArCQlyZXQgPSAtRU5PTUVNOwo+ICsJ CWdvdG8gZXJyMjsKPiArCX0KPiArCj4gKwlwcml2X2Rldi0+ZGV2X3ZlciA9IHJlYWRsKCZwcml2 X2Rldi0+cmVncy0+dXNiX2NhcDYpOwo+ICsJZGV2X2RiZyhwcml2X2Rldi0+ZGV2LCAiRGV2aWNl IENvbnRyb2xsZXIgdmVyc2lvbjogJTA4eFxuIiwKPiArCQlyZWFkbCgmcHJpdl9kZXYtPnJlZ3Mt PnVzYl9jYXA2KSk7Cj4gKwlkZXZfZGJnKHByaXZfZGV2LT5kZXYsICJVU0IgQ2FwYWJpbGl0aWVz OjogJTA4eFxuIiwKPiArCQlyZWFkbCgmcHJpdl9kZXYtPnJlZ3MtPnVzYl9jYXAxKSk7Cj4gKwlk ZXZfZGJnKHByaXZfZGV2LT5kZXYsICJPbi1DaGlwIG1lbW9yeSBjbmZpZ3VyYXRpb246ICUwOHhc biIsCj4gKwkJcmVhZGwoJnByaXZfZGV2LT5yZWdzLT51c2JfY2FwMikpOwo+ICsKPiArCXByaXZf ZGV2LT56bHBfYnVmID0ga3phbGxvYyhDRE5TM19FUF9aTFBfQlVGX1NJWkUsIEdGUF9LRVJORUwp Owo+ICsJaWYgKCFwcml2X2Rldi0+emxwX2J1Zikgewo+ICsJCXJldCA9IC1FTk9NRU07Cj4gKwkJ Z290byBlcnIzOwo+ICsJfQo+ICsKPiArCS8qIGFkZCBVU0IgZ2FkZ2V0IGRldmljZSAqLwo+ICsJ cmV0ID0gdXNiX2FkZF9nYWRnZXRfdWRjKHByaXZfZGV2LT5kZXYsICZwcml2X2Rldi0+Z2FkZ2V0 KTsKPiArCWlmIChyZXQgPCAwKSB7Cj4gKwkJZGV2X2Vycihwcml2X2Rldi0+ZGV2LAo+ICsJCQki RmFpbGVkIHRvIHJlZ2lzdGVyIFVTQiBkZXZpY2UgY29udHJvbGxlclxuIik7Cj4gKwkJZ290byBl cnI0Owo+ICsJfQo+ICsKPiArCXJldHVybiAwOwo+ICtlcnI0Ogo+ICsJa2ZyZWUocHJpdl9kZXYt PnpscF9idWYpOwo+ICtlcnIzOgo+ICsJZG1hX2ZyZWVfY29oZXJlbnQocHJpdl9kZXYtPnN5c2Rl diwgOCwgcHJpdl9kZXYtPnNldHVwX2J1ZiwKPiArCQkJICBwcml2X2Rldi0+c2V0dXBfZG1hKTsK PiArZXJyMjoKPiArCWNkbnMzX2ZyZWVfYWxsX2Vwcyhwcml2X2Rldik7Cj4gK2VycjE6Cj4gKwlj ZG5zLT5nYWRnZXRfZGV2ID0gTlVMTDsKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gK3N0YXRp YyBpbnQgX19jZG5zM19nYWRnZXRfaW5pdChzdHJ1Y3QgY2RuczMgKmNkbnMpCj4gK3sKPiArCXN0 cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2Owo+ICsJdW5zaWduZWQgbG9uZyBmbGFnczsKPiAr CWludCByZXQgPSAwOwo+ICsKPiArCXJldCA9IGNkbnMzX2dhZGdldF9zdGFydChjZG5zKTsKPiAr CWlmIChyZXQpCj4gKwkJcmV0dXJuIHJldDsKPiArCj4gKwlwcml2X2RldiA9IGNkbnMtPmdhZGdl dF9kZXY7Cj4gKwlyZXQgPSBkZXZtX3JlcXVlc3RfdGhyZWFkZWRfaXJxKGNkbnMtPmRldiwgY2Ru cy0+aXJxLAo+ICsJCQkJCWNkbnMzX2RldmljZV9pcnFfaGFuZGxlciwKPiArCQkJCQljZG5zM19k ZXZpY2VfdGhyZWFkX2lycV9oYW5kbGVyLAo+ICsJCQkJCUlSUUZfU0hBUkVELCBkZXZfbmFtZShj ZG5zLT5kZXYpLCBjZG5zKTsKPiArCWlmIChyZXQpCj4gKwkJZ290byBlcnIwOwo+ICsKPiArCXBt X3J1bnRpbWVfZ2V0X3N5bmMoY2Rucy0+ZGV2KTsKcG1fcnVudGltZV9nZXRfc3luYygpIHNob3Vs ZCBiZSBkb25lIGJlZm9yZSBjZG5zM19nYWRnZXRfc3RhcnQoKQoKPiArCXNwaW5fbG9ja19pcnFz YXZlKCZwcml2X2Rldi0+bG9jaywgZmxhZ3MpOwo+ICsJc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgm cHJpdl9kZXYtPmxvY2ssIGZsYWdzKTsKClJlZHVuZGFudCBzcGlubG9jayB1c2FnZT8KCj4gKwly ZXR1cm4gMDsKPiArZXJyMDoKPiArCWNkbnMzX2dhZGdldF9leGl0KGNkbnMpOwo+ICsJcmV0dXJu IHJldDsKPiArfQo+ICsKPiArc3RhdGljIGludCBjZG5zM19nYWRnZXRfc3VzcGVuZChzdHJ1Y3Qg Y2RuczMgKmNkbnMsIGJvb2wgZG9fd2FrZXVwKQo+ICt7Cj4gKwljZG5zM19nYWRnZXRfZGlzYWJs ZShjZG5zKTsKCkRvZXMgdGhpcyBlbnN1cmUgZ2FkZ2V0IGNvbnRyb2xsZXIgaXMgc3RvcHBlZD8K Cj4gKwlyZXR1cm4gMDsKPiArfQo+ICsKPiArc3RhdGljIGludCBjZG5zM19nYWRnZXRfcmVzdW1l KHN0cnVjdCBjZG5zMyAqY2RucywgYm9vbCBoaWJlcm5hdGVkKQo+ICt7Cj4gKwlzdHJ1Y3QgY2Ru czNfZGV2aWNlICpwcml2X2RldjsKPiArCXVuc2lnbmVkIGxvbmcgZmxhZ3M7Cj4gKwo+ICsJcHJp dl9kZXYgPSBjZG5zLT5nYWRnZXRfZGV2Owo+ICsJc3Bpbl9sb2NrX2lycXNhdmUoJnByaXZfZGV2 LT5sb2NrLCBmbGFncyk7Cj4gKwo+ICsJaWYgKCFwcml2X2Rldi0+Z2FkZ2V0X2RyaXZlcikgewo+ ICsJCXNwaW5fdW5sb2NrX2lycXJlc3RvcmUoJnByaXZfZGV2LT5sb2NrLCBmbGFncyk7Cj4gKwkJ cmV0dXJuIDA7Cj4gKwl9Cj4gKwo+ICsJY2RuczNfZ2FkZ2V0X2NvbmZpZyhwcml2X2Rldik7Cj4g KwlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZwcml2X2Rldi0+bG9jaywgZmxhZ3MpOwo+ICsJcmV0 dXJuIDA7Cj4gK30KPiArCj4gKy8qKgo+ICsgKiBjZG5zM19nYWRnZXRfaW5pdCAtIGluaXRpYWxp emUgZGV2aWNlIHN0cnVjdHVyZQo+ICsgKgo+ICsgKiBjZG5zOiBjZG5zMyBpbnN0YW5jZQo+ICsg Kgo+ICsgKiBUaGlzIGZ1bmN0aW9uIGluaXRpYWxpemVzIHRoZSBnYWRnZXQuCj4gKyAqLwo+ICtp bnQgY2RuczNfZ2FkZ2V0X2luaXQoc3RydWN0IGNkbnMzICpjZG5zKQo+ICt7Cj4gKwlzdHJ1Y3Qg Y2RuczNfcm9sZV9kcml2ZXIgKnJkcnY7Cj4gKwo+ICsJcmRydiA9IGRldm1fa3phbGxvYyhjZG5z LT5kZXYsIHNpemVvZigqcmRydiksIEdGUF9LRVJORUwpOwo+ICsJaWYgKCFyZHJ2KQo+ICsJCXJl dHVybiAtRU5PTUVNOwo+ICsKPiArCXJkcnYtPnN0YXJ0CT0gX19jZG5zM19nYWRnZXRfaW5pdDsK PiArCXJkcnYtPnN0b3AJPSBjZG5zM19nYWRnZXRfZXhpdDsKPiArCXJkcnYtPnN1c3BlbmQJPSBj ZG5zM19nYWRnZXRfc3VzcGVuZDsKPiArCXJkcnYtPnJlc3VtZQk9IGNkbnMzX2dhZGdldF9yZXN1 bWU7Cj4gKwlyZHJ2LT5zdGF0ZQk9IENETlMzX1JPTEVfU1RBVEVfSU5BQ1RJVkU7Cj4gKwlyZHJ2 LT5uYW1lCT0gImdhZGdldCI7Cj4gKwljZG5zLT5yb2xlc1tDRE5TM19ST0xFX0dBREdFVF0gPSBy ZHJ2Owo+ICsKPiArCXJldHVybiAwOwo+ICt9Cgo8c25pcD4K