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.0 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_PASS,UNPARSEABLE_RELAY, 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 822D7C43381 for ; Tue, 5 Mar 2019 01:42:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2F38A206B6 for ; Tue, 5 Mar 2019 01:42:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726917AbfCEBmn (ORCPT ); Mon, 4 Mar 2019 20:42:43 -0500 Received: from mailgw02.mediatek.com ([1.203.163.81]:50861 "EHLO mailgw02.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1726783AbfCEBmn (ORCPT ); Mon, 4 Mar 2019 20:42:43 -0500 X-UUID: 422404d3da5841b088ad13359443f0d2-20190305 X-UUID: 422404d3da5841b088ad13359443f0d2-20190305 Received: from mtkcas35.mediatek.inc [(172.27.4.253)] by mailgw02.mediatek.com (envelope-from ) (mailgw01.mediatek.com ESMTP with TLS) with ESMTP id 285228643; Tue, 05 Mar 2019 09:42:30 +0800 Received: from MTKCAS36.mediatek.inc (172.27.4.186) by MTKMBS32N1.mediatek.inc (172.27.4.71) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Tue, 5 Mar 2019 09:42:28 +0800 Received: from [10.17.3.153] (172.27.4.253) by MTKCAS36.mediatek.inc (172.27.4.170) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Tue, 5 Mar 2019 09:42:26 +0800 Message-ID: <1551750146.2210.78.camel@mhfsdcap03> Subject: RE: [PATCH v4 5/6] usb:cdns3 Add Cadence USB3 DRD Driver From: Chunfeng Yun To: Pawel Laszczak CC: "devicetree@vger.kernel.org" , "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" , "rogerq@ti.com" , "linux-kernel@vger.kernel.org" , "jbergsagel@ti.com" , "nsekhar@ti.com" , "nm@ti.com" , "Suresh Punnoose" , "peter.chen@nxp.com" , Rahul Kumar Date: Tue, 5 Mar 2019 09:42:26 +0800 In-Reply-To: References: <1550173514-23573-1-git-send-email-pawell@cadence.com> <1550173514-23573-6-git-send-email-pawell@cadence.com> <1550224667.2210.22.camel@mhfsdcap03> Content-Type: text/plain; charset="UTF-8" X-Mailer: Evolution 3.2.3-0ubuntu6 Content-Transfer-Encoding: 7bit MIME-Version: 1.0 X-MTK: N Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi, On Mon, 2019-03-04 at 11:01 +0000, Pawel Laszczak wrote: > Hi, > > > >hi, > >On Thu, 2019-02-14 at 19:45 +0000, 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 > >> --- [...] > >> 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. > >> + > >> + 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 > >when build as module: > >CONFIG_USB_CDNS3=m > >CONFIG_USB_CDNS3_GADGET=m > >CONFIG_USB_CDNS3_HOST=m > > How you set such configuration ? From make menuconfig it's impossible. I checked again, I changed it directly for easy test, sorry > > >there is an error: > >ERROR: "cdns3_handshake" [drivers/usb/cdns3/cdns3.ko] undefined! > > > >when only set: > >CONFIG_USB_CDNS3=y > >also encounter errors: > >drivers/usb/cdns3/drd.o: In function `cdns3_drd_switch_gadget': > >/drivers/usb/cdns3/drd.c:173: undefined reference to `cdns3_handshake' > >drivers/usb/cdns3/drd.o: In function `cdns3_drd_switch_host': > >drivers/usb/cdns3/drd.c:139: undefined reference to `cdns3_handshake' > > I will check this. > Thanks. > > > > > > > > >> 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. > >> + * > >> + * 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; > >not used in fact? > > Yes, I forgot to remove it. > > > >> + > >> +#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)); > >Mabye not necessary, devm_kzalloc() already set them as 0; > > Yes, it's not necessary. > > > >> + 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); > >> +} > >> + > >> +/* [...] > >> +/** > >> + * 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 */ > >> + role = cdsn3_get_real_role(cdns); > >> + > >> + role_drv = cdns3_get_current_role_driver(cdns); > >> + > >> + pm_runtime_get_sync(cdns->dev); > >> + > >> + /* Disable current role. This state can be forced from user space. */ > >> + 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); > >> + > >> + 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); > >> + } > >> +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 > >> + */ > >the comment should be modified or removed if not necessary when codes > >changed. > > Yes, now it's not necessary. > > >> + 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); > >check the return value? and > >It's better to call phy_power_on() here even if the phy driver doesn't > >provide power_on() > > Driver doesn't need to check return value in this case. It was discussed some time ago. Ok, I missed out something > > > > >> + > >> + 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); > >> + cdns3_debugfs_exit(cdns); > >> + cdns3_exit_roles(cdns); > >> + phy_exit(cdns->phy); > >> + 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 > >no irq member, > >> + * @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 > >not pointer > > Why ? > struct cdns3_otg_common_regs *otg_regs; Sorry, I may see otg_res as otg_regs > > But I forgot: > * @otg_res: the resource for otg > * @otg_v0_regs: pointer to base of v0 otg registers > * @otg_v1_regs: pointer to base of v1 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 > >> + * > >> + * 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; > >Does the single phy support both HS and SS? > >> + 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; > >> +}; > >> + > [...] > > > Thanks, > Pawel From mboxrd@z Thu Jan 1 00:00:00 1970 From: Chunfeng Yun Subject: RE: [PATCH v4 5/6] usb:cdns3 Add Cadence USB3 DRD Driver Date: Tue, 5 Mar 2019 09:42:26 +0800 Message-ID: <1551750146.2210.78.camel@mhfsdcap03> References: <1550173514-23573-1-git-send-email-pawell@cadence.com> <1550173514-23573-6-git-send-email-pawell@cadence.com> <1550224667.2210.22.camel@mhfsdcap03> Mime-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: Sender: linux-kernel-owner@vger.kernel.org To: Pawel Laszczak Cc: "devicetree@vger.kernel.org" , "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" , "rogerq@ti.com" , "linux-kernel@vger.kernel.org" , "jbergsagel@ti.com" , "nsekhar@ti.com" , "nm@ti.com" , Suresh Punnoose , "peter.chen@nxp.com" List-Id: devicetree@vger.kernel.org Hi, On Mon, 2019-03-04 at 11:01 +0000, Pawel Laszczak wrote: > Hi, > > > >hi, > >On Thu, 2019-02-14 at 19:45 +0000, 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 > >> --- [...] > >> 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. > >> + > >> + 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 > >when build as module: > >CONFIG_USB_CDNS3=m > >CONFIG_USB_CDNS3_GADGET=m > >CONFIG_USB_CDNS3_HOST=m > > How you set such configuration ? From make menuconfig it's impossible. I checked again, I changed it directly for easy test, sorry > > >there is an error: > >ERROR: "cdns3_handshake" [drivers/usb/cdns3/cdns3.ko] undefined! > > > >when only set: > >CONFIG_USB_CDNS3=y > >also encounter errors: > >drivers/usb/cdns3/drd.o: In function `cdns3_drd_switch_gadget': > >/drivers/usb/cdns3/drd.c:173: undefined reference to `cdns3_handshake' > >drivers/usb/cdns3/drd.o: In function `cdns3_drd_switch_host': > >drivers/usb/cdns3/drd.c:139: undefined reference to `cdns3_handshake' > > I will check this. > Thanks. > > > > > > > > >> 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. > >> + * > >> + * 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; > >not used in fact? > > Yes, I forgot to remove it. > > > >> + > >> +#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)); > >Mabye not necessary, devm_kzalloc() already set them as 0; > > Yes, it's not necessary. > > > >> + 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); > >> +} > >> + > >> +/* [...] > >> +/** > >> + * 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 */ > >> + role = cdsn3_get_real_role(cdns); > >> + > >> + role_drv = cdns3_get_current_role_driver(cdns); > >> + > >> + pm_runtime_get_sync(cdns->dev); > >> + > >> + /* Disable current role. This state can be forced from user space. */ > >> + 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); > >> + > >> + 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); > >> + } > >> +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 > >> + */ > >the comment should be modified or removed if not necessary when codes > >changed. > > Yes, now it's not necessary. > > >> + 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); > >check the return value? and > >It's better to call phy_power_on() here even if the phy driver doesn't > >provide power_on() > > Driver doesn't need to check return value in this case. It was discussed some time ago. Ok, I missed out something > > > > >> + > >> + 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); > >> + cdns3_debugfs_exit(cdns); > >> + cdns3_exit_roles(cdns); > >> + phy_exit(cdns->phy); > >> + 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 > >no irq member, > >> + * @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 > >not pointer > > Why ? > struct cdns3_otg_common_regs *otg_regs; Sorry, I may see otg_res as otg_regs > > But I forgot: > * @otg_res: the resource for otg > * @otg_v0_regs: pointer to base of v0 otg registers > * @otg_v1_regs: pointer to base of v1 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 > >> + * > >> + * 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; > >Does the single phy support both HS and SS? > >> + 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; > >> +}; > >> + > [...] > > > Thanks, > Pawel 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: Chunfeng Yun Message-Id: <1551750146.2210.78.camel@mhfsdcap03> Date: Tue, 5 Mar 2019 09:42:26 +0800 To: Pawel Laszczak Cc: "devicetree@vger.kernel.org" , "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" , "rogerq@ti.com" , "linux-kernel@vger.kernel.org" , "jbergsagel@ti.com" , "nsekhar@ti.com" , "nm@ti.com" , Suresh Punnoose , "peter.chen@nxp.com" , Rahul Kumar List-ID: SGksCk9uIE1vbiwgMjAxOS0wMy0wNCBhdCAxMTowMSArMDAwMCwgUGF3ZWwgTGFzemN6YWsgd3Jv dGU6Cj4gSGksIAo+ID4KPiA+aGksCj4gPk9uIFRodSwgMjAxOS0wMi0xNCBhdCAxOTo0NSArMDAw MCwgUGF3ZWwgTGFzemN6YWsgd3JvdGU6Cj4gPj4gVGhpcyBwYXRjaCBpbnRyb2R1Y2UgbmV3IENh ZGVuY2UgVVNCU1MgRFJEIGRyaXZlciB0byBsaW51eCBrZXJuZWwuCj4gPj4KPiA+PiBUaGUgQ2Fk ZW5jZSBVU0JTUyBEUkQgRHJpdmVyIGlzIGEgaGlnaGx5IGNvbmZpZ3VyYWJsZSBJUCBDb3JlIHdo aWNoaQo+ID4+IGNhbiBiZSBpbnN0YW50aWF0ZWQgYXMgRHVhbC1Sb2xlIERldmljZSAoRFJEKSwg UGVyaXBoZXJhbCBPbmx5IGFuZAo+ID4+IEhvc3QgT25seSAoWEhDSSljb25maWd1cmF0aW9ucy4K PiA+Pgo+ID4+IFRoZSBjdXJyZW50IGRyaXZlciBoYXMgYmVlbiB2YWxpZGF0ZWQgd2l0aCBGUEdB IGJ1cm5lZC4gV2UgaGF2ZSBzdXBwb3J0Cj4gPj4gZm9yIFBDSWUgYnVzLCB3aGljaCBpcyB1c2Vk IG9uIEZQR0EgcHJvdG90eXBpbmcuCj4gPj4KPiA+PiBUaGUgaG9zdCBzaWRlIG9mIFVTQlNTLURS RCBjb250cm9sbGVyIGlzIGNvbXBsaWFuY2Ugd2l0aCBYSENJCj4gPj4gc3BlY2lmaWNhdGlvbiwg c28gaXQgd29ya3Mgd2l0aCBzdGFuZGFyZCBYSENJIGxpbnV4IGRyaXZlci4KPiA+Pgo+ID4+IFNp Z25lZC1vZmYtYnk6IFBhd2VsIExhc3pjemFrIDxwYXdlbGxAY2FkZW5jZS5jb20+Cj4gPj4gLS0t ClsuLi5dCj4gPj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvdXNiL2NkbnMzL0tjb25maWcgYi9kcml2 ZXJzL3VzYi9jZG5zMy9LY29uZmlnCj4gPj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQKPiA+PiBpbmRl eCAwMDAwMDAwMDAwMDAuLjI3Y2IzZDhkYmUzZAo+ID4+IC0tLSAvZGV2L251bGwKPiA+PiArKysg Yi9kcml2ZXJzL3VzYi9jZG5zMy9LY29uZmlnCj4gPj4gQEAgLTAsMCArMSw0NCBAQAo+ID4+ICtj b25maWcgVVNCX0NETlMzCj4gPj4gKwl0cmlzdGF0ZSAiQ2FkZW5jZSBVU0IzIER1YWwtUm9sZSBD b250cm9sbGVyIgo+ID4+ICsJZGVwZW5kcyBvbiBVU0JfU1VQUE9SVCAmJiAoVVNCIHx8IFVTQl9H QURHRVQpICYmIEhBU19ETUEKPiA+PiArCWhlbHAKPiA+PiArCSAgU2F5IFkgaGVyZSBpZiB5b3Vy IHN5c3RlbSBoYXMgYSBjYWRlbmNlIFVTQjMgZHVhbC1yb2xlIGNvbnRyb2xsZXIuCj4gPj4gKwkg IEl0IHN1cHBvcnRzOiBkdWFsLXJvbGUgc3dpdGNoLCBIb3N0LW9ubHksIGFuZCBQZXJpcGhlcmFs LW9ubHkuCj4gPj4gKwo+ID4+ICsJICBJZiB5b3UgY2hvb3NlIHRvIGJ1aWxkIHRoaXMgZHJpdmVy IGlzIGEgZHluYW1pY2FsbHkgbGlua2VkCj4gPj4gKwkgIGFzIG1vZHVsZSwgdGhlIG1vZHVsZSB3 aWxsIGJlIGNhbGxlZCBjZG5zMy5rby4KPiA+PiArCj4gPj4gK2lmIFVTQl9DRE5TMwo+ID4+ICsK PiA+PiArY29uZmlnIFVTQl9DRE5TM19HQURHRVQKPiA+PiArICAgICAgICBib29sICJDYWRlbmNl IFVTQjMgZGV2aWNlIGNvbnRyb2xsZXIiCj4gPj4gKyAgICAgICAgZGVwZW5kcyBvbiBVU0JfR0FE R0VUCj4gPj4gKyAgICAgICAgaGVscAo+ID4+ICsgICAgICAgICAgU2F5IFkgaGVyZSB0byBlbmFi bGUgZGV2aWNlIGNvbnRyb2xsZXIgZnVuY3Rpb25hbGl0eSBvZiB0aGUKPiA+PiArICAgICAgICAg IGNhZGVuY2UgVVNCU1MtREVWIGRyaXZlci4KPiA+PiArCj4gPj4gKyAgICAgICAgICBUaGlzIGNv bnRyb2xsZXIgc3VwcG9ydHMgRkYsIEhTIGFuZCBTUyBtb2RlLiBJdCBkb2Vzbid0IHN1cHBvcnQK PiA+PiArICAgICAgICAgIExTIGFuZCBTU1AgbW9kZS4KPiA+PiArCj4gPj4gK2NvbmZpZyBVU0Jf Q0ROUzNfSE9TVAo+ID4+ICsgICAgICAgIGJvb2wgIkNhZGVuY2UgVVNCMyBob3N0IGNvbnRyb2xs ZXIiCj4gPj4gKyAgICAgICAgZGVwZW5kcyBvbiBVU0JfWEhDSV9IQ0QKPiA+PiArICAgICAgICBo ZWxwCj4gPj4gKyAgICAgICAgICBTYXkgWSBoZXJlIHRvIGVuYWJsZSBob3N0IGNvbnRyb2xsZXIg ZnVuY3Rpb25hbGl0eSBvZiB0aGUKPiA+PiArICAgICAgICAgIGNhZGVuY2UgZHJpdmVyLgo+ID4+ ICsKPiA+PiArICAgICAgICAgIEhvc3QgY29udHJvbGxlciBpcyBjb21wbGlhbnQgd2l0aCBYSENJ IHNvIGl0IHdpbGwgdXNlCj4gPj4gKyAgICAgICAgICBzdGFuZGFyZCBYSENJIGRyaXZlci4KPiA+ PiArCj4gPj4gK2NvbmZpZyBVU0JfQ0ROUzNfUENJX1dSQVAKPiA+PiArCXRyaXN0YXRlICJDYWRl bmNlIFVTQjMgc3VwcG9ydCBvbiBQQ0llLWJhc2VkIHBsYXRmb3JtcyIKPiA+PiArCWRlcGVuZHMg b24gVVNCX1BDSSAmJiBBQ1BJCj4gPj4gKwlkZWZhdWx0IFVTQl9DRE5TMwo+ID4+ICsJaGVscAo+ ID4+ICsJICBJZiB5b3UncmUgdXNpbmcgdGhlIFVTQlNTIENvcmUgSVAgd2l0aCBhIFBDSWUsIHBs ZWFzZSBzYXkKPiA+PiArCSAgJ1knIG9yICdNJyBoZXJlLgo+ID4+ICsKPiA+PiArCSAgSWYgeW91 IGNob29zZSB0byBidWlsZCB0aGlzIGRyaXZlciBhcyBtb2R1bGUgaXQgd2lsbAo+ID4+ICsJICBi ZSBkeW5hbWljYWxseSBsaW5rZWQgYW5kIG1vZHVsZSB3aWxsIGJlIGNhbGxlZCBjZG5zMy1wY2ku a28KPiA+PiArCj4gPj4gK2VuZGlmCj4gPj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvdXNiL2NkbnMz L01ha2VmaWxlIGIvZHJpdmVycy91c2IvY2RuczMvTWFrZWZpbGUKPiA+PiBuZXcgZmlsZSBtb2Rl IDEwMDY0NAo+ID4+IGluZGV4IDAwMDAwMDAwMDAwMC4uOGY5NDM4NTkzMzc1Cj4gPj4gLS0tIC9k ZXYvbnVsbAo+ID4+ICsrKyBiL2RyaXZlcnMvdXNiL2NkbnMzL01ha2VmaWxlCj4gPj4gQEAgLTAs MCArMSwxNCBAQAo+ID4+ICsjIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBHUEwtMi4wCj4gPj4g KyMgZGVmaW5lX3RyYWNlLmggbmVlZHMgdG8ga25vdyBob3cgdG8gZmluZCBvdXIgaGVhZGVyCj4g Pj4gK0NGTEFHU190cmFjZS5vCQkJCTo9IC1JJChzcmMpCj4gPj4gKwo+ID4+ICtjZG5zMy15CQkJ CQk6PSBjb3JlLm8gZHJkLm8gdHJhY2Uubwo+ID4+ICsKPiA+PiArb2JqLSQoQ09ORklHX1VTQl9D RE5TMykJCQkrPSBjZG5zMy5vCj4gPj4gK2lmbmVxICgkKENPTkZJR19ERUJVR19GUyksKQo+ID4+ ICsJY2RuczMteQkJCQkrPSBkZWJ1Z2ZzLm8KPiA+PiArZW5kaWYKPiA+PiArCj4gPj4gK2NkbnMz LSQoQ09ORklHX1VTQl9DRE5TM19HQURHRVQpCSs9IGdhZGdldC5vIGVwMC5vCj4gPj4gK2NkbnMz LSQoQ09ORklHX1VTQl9DRE5TM19IT1NUKQkJKz0gaG9zdC5vCj4gPj4gK29iai0kKENPTkZJR19V U0JfQ0ROUzNfUENJX1dSQVApCSs9IGNkbnMzLXBjaS13cmFwLm8KPiA+d2hlbiBidWlsZCBhcyBt b2R1bGU6Cj4gPkNPTkZJR19VU0JfQ0ROUzM9bQo+ID5DT05GSUdfVVNCX0NETlMzX0dBREdFVD1t Cj4gPkNPTkZJR19VU0JfQ0ROUzNfSE9TVD1tCj4gCj4gSG93IHlvdSBzZXQgc3VjaCBjb25maWd1 cmF0aW9uID8gRnJvbSBtYWtlIG1lbnVjb25maWcgaXQncyBpbXBvc3NpYmxlLiAKSSBjaGVja2Vk IGFnYWluLCBJIGNoYW5nZWQgaXQgZGlyZWN0bHkgZm9yIGVhc3kgdGVzdCwgc29ycnkKCj4gCj4g PnRoZXJlIGlzIGFuIGVycm9yOgo+ID5FUlJPUjogImNkbnMzX2hhbmRzaGFrZSIgW2RyaXZlcnMv dXNiL2NkbnMzL2NkbnMzLmtvXSB1bmRlZmluZWQhCj4gPgo+ID53aGVuIG9ubHkgc2V0Ogo+ID5D T05GSUdfVVNCX0NETlMzPXkKPiA+YWxzbyBlbmNvdW50ZXIgZXJyb3JzOgo+ID5kcml2ZXJzL3Vz Yi9jZG5zMy9kcmQubzogSW4gZnVuY3Rpb24gYGNkbnMzX2RyZF9zd2l0Y2hfZ2FkZ2V0JzoKPiA+ L2RyaXZlcnMvdXNiL2NkbnMzL2RyZC5jOjE3MzogdW5kZWZpbmVkIHJlZmVyZW5jZSB0byBgY2Ru czNfaGFuZHNoYWtlJwo+ID5kcml2ZXJzL3VzYi9jZG5zMy9kcmQubzogSW4gZnVuY3Rpb24gYGNk bnMzX2RyZF9zd2l0Y2hfaG9zdCc6Cj4gPmRyaXZlcnMvdXNiL2NkbnMzL2RyZC5jOjEzOTogdW5k ZWZpbmVkIHJlZmVyZW5jZSB0byBgY2RuczNfaGFuZHNoYWtlJwo+IAo+IEkgd2lsbCBjaGVjayB0 aGlzLiAKPiBUaGFua3MuIAo+IAo+ID4KPiA+Cj4gPgo+ID4+IGRpZmYgLS1naXQgYS9kcml2ZXJz L3VzYi9jZG5zMy9jZG5zMy1wY2ktd3JhcC5jIGIvZHJpdmVycy91c2IvY2RuczMvY2RuczMtcGNp LXdyYXAuYwo+ID4+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0Cj4gPj4gaW5kZXggMDAwMDAwMDAwMDAw Li5kMGIyZDNkOWI5ODMKPiA+PiAtLS0gL2Rldi9udWxsCj4gPj4gKysrIGIvZHJpdmVycy91c2Iv Y2RuczMvY2RuczMtcGNpLXdyYXAuYwo+ID4+IEBAIC0wLDAgKzEsMTU1IEBACj4gPj4gKy8vIFNQ RFgtTGljZW5zZS1JZGVudGlmaWVyOiBHUEwtMi4wCj4gPj4gKy8qCj4gPj4gKyAqIENhZGVuY2Ug VVNCU1MgUENJIEdsdWUgZHJpdmVyCj4gPj4gKyAqCj4gPj4gKyAqIENvcHlyaWdodCAoQykgMjAx OCBDYWRlbmNlLgo+ID4+ICsgKgo+ID4+ICsgKiBBdXRob3I6IFBhd2VsIExhc3pjemFrIDxwYXdl bGxAY2FkZW5jZS5jb20+Cj4gPj4gKyAqLwo+ID4+ICsKPiA+PiArI2luY2x1ZGUgPGxpbnV4L2tl cm5lbC5oPgo+ID4+ICsjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+Cj4gPj4gKyNpbmNsdWRlIDxs aW51eC9wY2kuaD4KPiA+PiArI2luY2x1ZGUgPGxpbnV4L3BsYXRmb3JtX2RldmljZS5oPgo+ID4+ ICsjaW5jbHVkZSA8bGludXgvZG1hLW1hcHBpbmcuaD4KPiA+PiArI2luY2x1ZGUgPGxpbnV4L3Ns YWIuaD4KPiA+PiArCj4gPj4gK3N0cnVjdCBjZG5zM193cmFwIHsKPiA+PiArCXN0cnVjdCBwbGF0 Zm9ybV9kZXZpY2UgKnBsYXRfZGV2Owo+ID4+ICsJc3RydWN0IHBjaV9kZXYgKmhnX2RldjsKPiA+ PiArCXN0cnVjdCByZXNvdXJjZSBkZXZfcmVzWzRdOwo+ID4+ICt9Owo+ID4+ICsKPiA+PiArc3Ry dWN0IGNkbnMzX3dyYXAgd3JhcDsKPiA+bm90IHVzZWQgaW4gZmFjdD8KPiAKPiBZZXMsIEkgZm9y Z290IHRvIHJlbW92ZSBpdC4gIAo+ID4KPiA+PiArCj4gPj4gKyNkZWZpbmUgUkVTX0lSUV9JRAkJ MAo+ID4+ICsjZGVmaW5lIFJFU19IT1NUX0lECQkxCj4gPj4gKyNkZWZpbmUgUkVTX0RFVl9JRAkJ Mgo+ID4+ICsjZGVmaW5lIFJFU19EUkRfSUQJCTMKPiA+PiArCj4gPj4gKyNkZWZpbmUgUENJX0JB Ul9IT1NUCQkwCj4gPj4gKyNkZWZpbmUgUENJX0JBUl9ERVYJCTIKPiA+PiArI2RlZmluZSBQQ0lf QkFSX09URwkJNAo+ID4+ICsKPiA+PiArI2RlZmluZSBQQ0lfREVWX0ZOX0hPU1RfREVWSUNFCTAK PiA+PiArI2RlZmluZSBQQ0lfREVWX0ZOX09URwkJMQo+ID4+ICsKPiA+PiArI2RlZmluZSBQQ0lf RFJJVkVSX05BTUUJCSJjZG5zMy1wY2ktdXNic3MiCj4gPj4gKyNkZWZpbmUgUExBVF9EUklWRVJf TkFNRQkiY2Rucy11c2IzIgo+ID4+ICsKPiA+PiArI2RlZmluZSBDRE5TX1ZFTkRPUl9JRCAweDE3 Y2QKPiA+PiArI2RlZmluZSBDRE5TX0RFVklDRV9JRCAweDAxMDAKPiA+PiArCj4gPj4gKy8qKgo+ ID4+ICsgKiBjZG5zM19wY2lfcHJvYmUgLSBQcm9iZSBmdW5jdGlvbiBmb3IgQ2FkZW5jZSBVU0Ig d3JhcHBlciBkcml2ZXIKPiA+PiArICogQHBkZXY6IHBsYXRmb3JtIGRldmljZSBvYmplY3QKPiA+ PiArICogQGlkOiBwY2kgZGV2aWNlIGlkCj4gPj4gKyAqCj4gPj4gKyAqIFJldHVybnMgMCBvbiBz dWNjZXNzIG90aGVyd2lzZSBuZWdhdGl2ZSBlcnJubwo+ID4+ICsgKi8KPiA+PiArc3RhdGljIGlu dCBjZG5zM19wY2lfcHJvYmUoc3RydWN0IHBjaV9kZXYgKnBkZXYsCj4gPj4gKwkJCSAgIGNvbnN0 IHN0cnVjdCBwY2lfZGV2aWNlX2lkICppZCkKPiA+PiArewo+ID4+ICsJc3RydWN0IHBsYXRmb3Jt X2RldmljZV9pbmZvIHBsYXRfaW5mbzsKPiA+PiArCXN0cnVjdCBjZG5zM193cmFwICp3cmFwOwo+ ID4+ICsJc3RydWN0IHJlc291cmNlICpyZXM7Cj4gPj4gKwlpbnQgZXJyOwo+ID4+ICsKPiA+PiAr CS8qCj4gPj4gKwkgKiBmb3IgR0FER0VUL0hPU1QgUENJIChkZXZmbikgZnVuY3Rpb24gbnVtYmVy IGlzIDAsCj4gPj4gKwkgKiBmb3IgT1RHIFBDSSAoZGV2Zm4pIGZ1bmN0aW9uIG51bWJlciBpcyAx Cj4gPj4gKwkgKi8KPiA+PiArCWlmICghaWQgfHwgcGRldi0+ZGV2Zm4gIT0gUENJX0RFVl9GTl9I T1NUX0RFVklDRSkKPiA+PiArCQlyZXR1cm4gLUVJTlZBTDsKPiA+PiArCj4gPj4gKwllcnIgPSBw Y2ltX2VuYWJsZV9kZXZpY2UocGRldik7Cj4gPj4gKwlpZiAoZXJyKSB7Cj4gPj4gKwkJZGV2X2Vy cigmcGRldi0+ZGV2LCAiRW5hYmxpbmcgUENJIGRldmljZSBoYXMgZmFpbGVkICVkXG4iLCBlcnIp Owo+ID4+ICsJCXJldHVybiBlcnI7Cj4gPj4gKwl9Cj4gPj4gKwo+ID4+ICsJcGNpX3NldF9tYXN0 ZXIocGRldik7Cj4gPj4gKwl3cmFwID0gZGV2bV9remFsbG9jKCZwZGV2LT5kZXYsIHNpemVvZigq d3JhcCksIEdGUF9LRVJORUwpOwo+ID4+ICsJaWYgKCF3cmFwKSB7Cj4gPj4gKwkJZGV2X2Vycigm cGRldi0+ZGV2LCAiRmFpbGVkIHRvIGFsbG9jYXRlIG1lbW9yeVxuIik7Cj4gPj4gKwkJcmV0dXJu IC1FTk9NRU07Cj4gPj4gKwl9Cj4gPj4gKwo+ID4+ICsJLyogZnVuY3Rpb24gMDogaG9zdChCQVJf MCkgKyBkZXZpY2UoQkFSXzEpICsgb3RnKEJBUl8yKSkuICovCj4gPj4gKwltZW1zZXQod3JhcC0+ ZGV2X3JlcywgMHgwMCwKPiA+PiArCSAgICAgICBzaXplb2Yoc3RydWN0IHJlc291cmNlKSAqIEFS UkFZX1NJWkUod3JhcC0+ZGV2X3JlcykpOwo+ID5NYWJ5ZSBub3QgbmVjZXNzYXJ5LCBkZXZtX2t6 YWxsb2MoKSBhbHJlYWR5IHNldCB0aGVtIGFzIDA7Cj4gCj4gWWVzLCBpdCdzIG5vdCBuZWNlc3Nh cnkuIAo+ID4KPiA+PiArCWRldl9kYmcoJnBkZXYtPmRldiwgIkluaXRpYWxpemUgRGV2aWNlIHJl c291cmNlc1xuIik7Cj4gPj4gKwlyZXMgPSB3cmFwLT5kZXZfcmVzOwo+ID4+ICsKPiA+PiArCXJl c1tSRVNfREVWX0lEXS5zdGFydCA9IHBjaV9yZXNvdXJjZV9zdGFydChwZGV2LCBQQ0lfQkFSX0RF Vik7Cj4gPj4gKwlyZXNbUkVTX0RFVl9JRF0uZW5kID0gICBwY2lfcmVzb3VyY2VfZW5kKHBkZXYs IFBDSV9CQVJfREVWKTsKPiA+PiArCXJlc1tSRVNfREVWX0lEXS5uYW1lID0gImRldiI7Cj4gPj4g KwlyZXNbUkVTX0RFVl9JRF0uZmxhZ3MgPSBJT1JFU09VUkNFX01FTTsKPiA+PiArCWRldl9kYmco JnBkZXYtPmRldiwgIlVTQlNTLURFViBwaHlzaWNhbCBiYXNlIGFkZHI6ICVwYVxuIiwKPiA+PiAr CQkmcmVzW1JFU19ERVZfSURdLnN0YXJ0KTsKPiA+PiArCj4gPj4gKwlyZXNbUkVTX0hPU1RfSURd LnN0YXJ0ID0gcGNpX3Jlc291cmNlX3N0YXJ0KHBkZXYsIFBDSV9CQVJfSE9TVCk7Cj4gPj4gKwly ZXNbUkVTX0hPU1RfSURdLmVuZCA9IHBjaV9yZXNvdXJjZV9lbmQocGRldiwgUENJX0JBUl9IT1NU KTsKPiA+PiArCXJlc1tSRVNfSE9TVF9JRF0ubmFtZSA9ICJ4aGNpIjsKPiA+PiArCXJlc1tSRVNf SE9TVF9JRF0uZmxhZ3MgPSBJT1JFU09VUkNFX01FTTsKPiA+PiArCWRldl9kYmcoJnBkZXYtPmRl diwgIlVTQlNTLVhIQ0kgcGh5c2ljYWwgYmFzZSBhZGRyOiAlcGFcbiIsCj4gPj4gKwkJJnJlc1tS RVNfSE9TVF9JRF0uc3RhcnQpOwo+ID4+ICsKPiA+PiArCXJlc1tSRVNfRFJEX0lEXS5zdGFydCA9 IHBjaV9yZXNvdXJjZV9zdGFydChwZGV2LCBQQ0lfQkFSX09URyk7Cj4gPj4gKwlyZXNbUkVTX0RS RF9JRF0uZW5kID0gICBwY2lfcmVzb3VyY2VfZW5kKHBkZXYsIFBDSV9CQVJfT1RHKTsKPiA+PiAr CXJlc1tSRVNfRFJEX0lEXS5uYW1lID0gIm90ZyI7Cj4gPj4gKwlyZXNbUkVTX0RSRF9JRF0uZmxh Z3MgPSBJT1JFU09VUkNFX01FTTsKPiA+PiArCWRldl9kYmcoJnBkZXYtPmRldiwgIlVTQlNTLURS RCBwaHlzaWNhbCBiYXNlIGFkZHI6ICVwYVxuIiwKPiA+PiArCQkmcmVzW1JFU19EUkRfSURdLnN0 YXJ0KTsKPiA+PiArCj4gPj4gKwkvKiBJbnRlcnJ1cHQgY29tbW9uIGZvciBib3RoIGRldmljZSBh bmQgWEhDSSAqLwo+ID4+ICsJd3JhcC0+ZGV2X3Jlc1tSRVNfSVJRX0lEXS5zdGFydCA9IHBkZXYt PmlycTsKPiA+PiArCXdyYXAtPmRldl9yZXNbUkVTX0lSUV9JRF0ubmFtZSA9ICJjZG5zMy1pcnEi Owo+ID4+ICsJd3JhcC0+ZGV2X3Jlc1tSRVNfSVJRX0lEXS5mbGFncyA9IElPUkVTT1VSQ0VfSVJR Owo+ID4+ICsKPiA+PiArCS8qIHNldCB1cCBwbGF0Zm9ybSBkZXZpY2UgaW5mbyAqLwo+ID4+ICsJ bWVtc2V0KCZwbGF0X2luZm8sIDAsIHNpemVvZihwbGF0X2luZm8pKTsKPiA+PiArCXBsYXRfaW5m by5wYXJlbnQgPSAmcGRldi0+ZGV2Owo+ID4+ICsJcGxhdF9pbmZvLmZ3bm9kZSA9IHBkZXYtPmRl di5md25vZGU7Cj4gPj4gKwlwbGF0X2luZm8ubmFtZSA9IFBMQVRfRFJJVkVSX05BTUU7Cj4gPj4g KwlwbGF0X2luZm8uaWQgPSBwZGV2LT5kZXZmbjsKPiA+PiArCXBsYXRfaW5mby5yZXMgPSB3cmFw LT5kZXZfcmVzOwo+ID4+ICsJcGxhdF9pbmZvLm51bV9yZXMgPSBBUlJBWV9TSVpFKHdyYXAtPmRl dl9yZXMpOwo+ID4+ICsJcGxhdF9pbmZvLmRtYV9tYXNrID0gcGRldi0+ZG1hX21hc2s7Cj4gPj4g Kwo+ID4+ICsJLyogcmVnaXN0ZXIgcGxhdGZvcm0gZGV2aWNlICovCj4gPj4gKwl3cmFwLT5wbGF0 X2RldiA9IHBsYXRmb3JtX2RldmljZV9yZWdpc3Rlcl9mdWxsKCZwbGF0X2luZm8pOwo+ID4+ICsJ aWYgKElTX0VSUih3cmFwLT5wbGF0X2RldikpCj4gPj4gKwkJcmV0dXJuIFBUUl9FUlIod3JhcC0+ cGxhdF9kZXYpOwo+ID4+ICsKPiA+PiArCXBjaV9zZXRfZHJ2ZGF0YShwZGV2LCB3cmFwKTsKPiA+ PiArCj4gPj4gKwlyZXR1cm4gZXJyOwo+ID4+ICt9Cj4gPj4gKwo+ID4+ICt2b2lkIGNkbnMzX3Bj aV9yZW1vdmUoc3RydWN0IHBjaV9kZXYgKnBkZXYpCj4gPj4gK3sKPiA+PiArCXN0cnVjdCBjZG5z M193cmFwICp3cmFwID0gKHN0cnVjdCBjZG5zM193cmFwICopcGNpX2dldF9kcnZkYXRhKHBkZXYp Owo+ID4+ICsKPiA+PiArCXBsYXRmb3JtX2RldmljZV91bnJlZ2lzdGVyKHdyYXAtPnBsYXRfZGV2 KTsKPiA+PiArfQo+ID4+ICsKPiA+PiArc3RhdGljIGNvbnN0IHN0cnVjdCBwY2lfZGV2aWNlX2lk IGNkbnMzX3BjaV9pZHNbXSA9IHsKPiA+PiArCXsgUENJX0RFVklDRShDRE5TX1ZFTkRPUl9JRCwg Q0ROU19ERVZJQ0VfSUQpLCB9LAo+ID4+ICsJeyAwLCB9Cj4gPj4gK307Cj4gPj4gKwo+ID4+ICtz dGF0aWMgc3RydWN0IHBjaV9kcml2ZXIgY2RuczNfcGNpX2RyaXZlciA9IHsKPiA+PiArCS5uYW1l ID0gUENJX0RSSVZFUl9OQU1FLAo+ID4+ICsJLmlkX3RhYmxlID0gY2RuczNfcGNpX2lkcywKPiA+ PiArCS5wcm9iZSA9IGNkbnMzX3BjaV9wcm9iZSwKPiA+PiArCS5yZW1vdmUgPSBjZG5zM19wY2lf cmVtb3ZlLAo+ID4+ICt9Owo+ID4+ICsKPiA+PiArbW9kdWxlX3BjaV9kcml2ZXIoY2RuczNfcGNp X2RyaXZlcik7Cj4gPj4gK01PRFVMRV9ERVZJQ0VfVEFCTEUocGNpLCBjZG5zM19wY2lfaWRzKTsK PiA+PiArCj4gPj4gK01PRFVMRV9BVVRIT1IoIlBhd2VsIExhc3pjemFrIDxwYXdlbGxAY2FkZW5j ZS5jb20+Iik7Cj4gPj4gK01PRFVMRV9MSUNFTlNFKCJHUEwgdjIiKTsKPiA+PiArTU9EVUxFX0RF U0NSSVBUSU9OKCJDYWRlbmNlIFVTQlNTIFBDSSB3cmFwcGVyciIpOwo+ID4+ICsKPiA+PiBkaWZm IC0tZ2l0IGEvZHJpdmVycy91c2IvY2RuczMvY29yZS5jIGIvZHJpdmVycy91c2IvY2RuczMvY29y ZS5jCj4gPj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQKPiA+PiBpbmRleCAwMDAwMDAwMDAwMDAuLmFh MmY2MzI0MWRhYgo+ID4+IC0tLSAvZGV2L251bGwKPiA+PiArKysgYi9kcml2ZXJzL3VzYi9jZG5z My9jb3JlLmMKPiA+PiBAQCAtMCwwICsxLDQwMyBAQAo+ID4+ICsvLyBTUERYLUxpY2Vuc2UtSWRl bnRpZmllcjogR1BMLTIuMAo+ID4+ICsvKgo+ID4+ICsgKiBDYWRlbmNlIFVTQlNTIERSRCBEcml2 ZXIuCj4gPj4gKyAqCj4gPj4gKyAqIENvcHlyaWdodCAoQykgMjAxOCBDYWRlbmNlLgo+ID4+ICsg KiBDb3B5cmlnaHQgKEMpIDIwMTctMjAxOCBOWFAKPiA+PiArICoKPiA+PiArICogQXV0aG9yOiBQ ZXRlciBDaGVuIDxwZXRlci5jaGVuQG54cC5jb20+Cj4gPj4gKyAqICAgICAgICAgUGF3ZWwgTGFz emN6YWsgPHBhd2VsbEBjYWRlbmNlLmNvbT4KPiA+PiArICovCj4gPj4gKwo+ID4+ICsjaW5jbHVk ZSA8bGludXgvbW9kdWxlLmg+Cj4gPj4gKyNpbmNsdWRlIDxsaW51eC9rZXJuZWwuaD4KPiA+PiAr I2luY2x1ZGUgPGxpbnV4L3BsYXRmb3JtX2RldmljZS5oPgo+ID4+ICsjaW5jbHVkZSA8bGludXgv aW50ZXJydXB0Lmg+Cj4gPj4gKyNpbmNsdWRlIDxsaW51eC9pby5oPgo+ID4+ICsjaW5jbHVkZSA8 bGludXgvcG1fcnVudGltZS5oPgo+ID4+ICsKPiA+PiArI2luY2x1ZGUgImdhZGdldC5oIgo+ID4+ ICsjaW5jbHVkZSAiY29yZS5oIgo+ID4+ICsjaW5jbHVkZSAiaG9zdC1leHBvcnQuaCIKPiA+PiAr I2luY2x1ZGUgImdhZGdldC1leHBvcnQuaCIKPiA+PiArI2luY2x1ZGUgImRyZC5oIgo+ID4+ICsj aW5jbHVkZSAiZGVidWcuaCIKPiA+PiArCj4gPj4gK3N0YXRpYyBpbmxpbmUKPiA+PiArc3RydWN0 IGNkbnMzX3JvbGVfZHJpdmVyICpjZG5zM19nZXRfY3VycmVudF9yb2xlX2RyaXZlcihzdHJ1Y3Qg Y2RuczMgKmNkbnMpCj4gPj4gK3sKPiA+PiArCVdBUk5fT04oY2Rucy0+cm9sZSA+PSBDRE5TM19S T0xFX0VORCB8fCAhY2Rucy0+cm9sZXNbY2Rucy0+cm9sZV0pOwo+ID4+ICsJcmV0dXJuIGNkbnMt PnJvbGVzW2NkbnMtPnJvbGVdOwo+ID4+ICt9Cj4gPj4gKwo+ID4+ICtzdGF0aWMgaW50IGNkbnMz X3JvbGVfc3RhcnQoc3RydWN0IGNkbnMzICpjZG5zLCBlbnVtIGNkbnMzX3JvbGVzIHJvbGUpCj4g Pj4gK3sKPiA+PiArCWludCByZXQ7Cj4gPj4gKwo+ID4+ICsJaWYgKFdBUk5fT04ocm9sZSA+PSBD RE5TM19ST0xFX0VORCkpCj4gPj4gKwkJcmV0dXJuIDA7Cj4gPj4gKwo+ID4+ICsJaWYgKCFjZG5z LT5yb2xlc1tyb2xlXSkKPiA+PiArCQlyZXR1cm4gLUVOWElPOwo+ID4+ICsKPiA+PiArCWlmIChj ZG5zLT5yb2xlc1tyb2xlXS0+c3RhdGUgPT0gQ0ROUzNfUk9MRV9TVEFURV9BQ1RJVkUpCj4gPj4g KwkJcmV0dXJuIDA7Cj4gPj4gKwo+ID4+ICsJbXV0ZXhfbG9jaygmY2Rucy0+bXV0ZXgpOwo+ID4+ ICsJY2Rucy0+cm9sZSA9IHJvbGU7Cj4gPj4gKwlyZXQgPSBjZG5zLT5yb2xlc1tyb2xlXS0+c3Rh cnQoY2Rucyk7Cj4gPj4gKwlpZiAoIXJldCkKPiA+PiArCQljZG5zLT5yb2xlc1tyb2xlXS0+c3Rh dGUgPSBDRE5TM19ST0xFX1NUQVRFX0FDVElWRTsKPiA+PiArCW11dGV4X3VubG9jaygmY2Rucy0+ bXV0ZXgpOwo+ID4+ICsJcmV0dXJuIHJldDsKPiA+PiArfQo+ID4+ICsKPiA+PiArdm9pZCBjZG5z M19yb2xlX3N0b3Aoc3RydWN0IGNkbnMzICpjZG5zKQo+ID4+ICt7Cj4gPj4gKwllbnVtIGNkbnMz X3JvbGVzIHJvbGUgPSBjZG5zLT5yb2xlOwo+ID4+ICsKPiA+PiArCWlmIChyb2xlID49IENETlMz X1JPTEVfRU5EKSB7Cj4gPj4gKwkJV0FSTl9PTihyb2xlID4gQ0ROUzNfUk9MRV9FTkQpOwo+ID4+ ICsJCXJldHVybjsKPiA+PiArCX0KPiA+PiArCj4gPj4gKwlpZiAoY2Rucy0+cm9sZXNbcm9sZV0t PnN0YXRlID09IENETlMzX1JPTEVfU1RBVEVfSU5BQ1RJVkUpCj4gPj4gKwkJcmV0dXJuOwo+ID4+ ICsKPiA+PiArCW11dGV4X2xvY2soJmNkbnMtPm11dGV4KTsKPiA+PiArCWNkbnMtPnJvbGVzW3Jv bGVdLT5zdG9wKGNkbnMpOwo+ID4+ICsJY2Rucy0+cm9sZXNbcm9sZV0tPnN0YXRlID0gQ0ROUzNf Uk9MRV9TVEFURV9JTkFDVElWRTsKPiA+PiArCW11dGV4X3VubG9jaygmY2Rucy0+bXV0ZXgpOwo+ ID4+ICt9Cj4gPj4gKwo+ID4+ICsvKgpbLi4uXQo+ID4+ICsvKioKPiA+PiArICogY2RzbjNfZ2V0 X3JlYWxfcm9sZSAtIGdldCByZWFsIHJvbGUgb2YgY29udHJvbGxlciBiYXNlZCBvbiBoYXJkd2Fy ZSBzZXR0aW5ncy4KPiA+PiArICogQGNkbnM6IFBvaW50ZXIgdG8gY2RuczMgc3RydWN0dXJlCj4g Pj4gKyAqCj4gPj4gKyAqIFJldHVybnMgcm9sZQo+ID4+ICsgKi8KPiA+PiArZW51bSBjZG5zM19y b2xlcyBjZHNuM19nZXRfcmVhbF9yb2xlKHN0cnVjdCBjZG5zMyAqY2RucykKPiA+PiArewo+ID4+ ICsJZW51bSBjZG5zM19yb2xlcyByb2xlID0gQ0ROUzNfUk9MRV9FTkQ7Cj4gPj4gKwo+ID4+ICsJ aWYgKGNkbnMtPmN1cnJlbnRfZHJfbW9kZSA9PSBVU0JfRFJfTU9ERV9PVEcpIHsKPiA+PiArCQlp ZiAoY2RuczNfZ2V0X2lkKGNkbnMpKQo+ID4+ICsJCQlyb2xlID0gQ0ROUzNfUk9MRV9HQURHRVQ7 Cj4gPj4gKwkJZWxzZQo+ID4+ICsJCQlyb2xlID0gQ0ROUzNfUk9MRV9IT1NUOwo+ID4+ICsJfSBl bHNlIHsKPiA+PiArCQlpZiAoY2RuczNfaXNfaG9zdChjZG5zKSkKPiA+PiArCQkJcm9sZSA9IENE TlMzX1JPTEVfSE9TVDsKPiA+PiArCQlpZiAoY2RuczNfaXNfZGV2aWNlKGNkbnMpKQo+ID4+ICsJ CQlyb2xlID0gQ0ROUzNfUk9MRV9HQURHRVQ7Cj4gPj4gKwl9Cj4gPj4gKwo+ID4+ICsJcmV0dXJu IHJvbGU7Cj4gPj4gK30KPiA+PiArCj4gPj4gKy8qKgo+ID4+ICsgKiBjZG5zM19yb2xlX3N3aXRj aCAtIHdvcmsgcXVldWUgaGFuZGxlciBmb3Igcm9sZSBzd2l0Y2gKPiA+PiArICoKPiA+PiArICog QHdvcms6IHdvcmsgcXVldWUgaXRlbSBzdHJ1Y3R1cmUKPiA+PiArICoKPiA+PiArICogSGFuZGxl cyBiZWxvdyBldmVudHM6Cj4gPj4gKyAqIC0gUm9sZSBzd2l0Y2ggZm9yIGR1YWwtcm9sZSBkZXZp Y2VzCj4gPj4gKyAqIC0gQ0ROUzNfUk9MRV9HQURHRVQgPC0tPiBDRE5TM19ST0xFX0VORCBmb3Ig cGVyaXBoZXJhbC1vbmx5IGRldmljZXMKPiA+PiArICovCj4gPj4gK3N0YXRpYyB2b2lkIGNkbnMz X3JvbGVfc3dpdGNoKHN0cnVjdCB3b3JrX3N0cnVjdCAqd29yaykKPiA+PiArewo+ID4+ICsJZW51 bSBjZG5zM19yb2xlcyByb2xlID0gQ0ROUzNfUk9MRV9FTkQ7Cj4gPj4gKwlzdHJ1Y3QgY2RuczNf cm9sZV9kcml2ZXIgKnJvbGVfZHJ2Owo+ID4+ICsJZW51bSBjZG5zM19yb2xlcyBjdXJyZW50X3Jv bGU7Cj4gPj4gKwlzdHJ1Y3QgY2RuczMgKmNkbnM7Cj4gPj4gKwlpbnQgcmV0ID0gMDsKPiA+PiAr Cj4gPj4gKwljZG5zID0gY29udGFpbmVyX29mKHdvcmssIHN0cnVjdCBjZG5zMywgcm9sZV9zd2l0 Y2hfd3EpOwo+ID4+ICsKPiA+PiArCS8qIER1cmluZyBzd2l0Y2hpbmcgY2Rucy0+cm9sZSBjYW4g YmUgZGlmZmVyZW50IHRoZW4gcm9sZSAqLwo+ID4+ICsJcm9sZSA9IGNkc24zX2dldF9yZWFsX3Jv bGUoY2Rucyk7Cj4gPj4gKwo+ID4+ICsJcm9sZV9kcnYgPSBjZG5zM19nZXRfY3VycmVudF9yb2xl X2RyaXZlcihjZG5zKTsKPiA+PiArCj4gPj4gKwlwbV9ydW50aW1lX2dldF9zeW5jKGNkbnMtPmRl dik7Cj4gPj4gKwo+ID4+ICsJLyogRGlzYWJsZSBjdXJyZW50IHJvbGUuIFRoaXMgc3RhdGUgY2Fu IGJlIGZvcmNlZCBmcm9tIHVzZXIgc3BhY2UuICovCj4gPj4gKwlpZiAoY2Rucy0+ZGVidWdfZGlz YWJsZSAmJiByb2xlX2Rydi0+c3RhdGUgPT0gQ0ROUzNfUk9MRV9TVEFURV9BQ1RJVkUpIHsKPiA+ PiArCQljZG5zM19yb2xlX3N0b3AoY2Rucyk7Cj4gPj4gKwkJZ290byBleGl0Owo+ID4+ICsJfQo+ ID4+ICsKPiA+PiArCS8qIERvIG5vdGhpbmcgaWYgbm90aGluZyBjaGFuZ2VkICovCj4gPj4gKwlp ZiAoY2Rucy0+cm9sZSA9PSByb2xlICYmIHJvbGVfZHJ2LT5zdGF0ZSA9PSBDRE5TM19ST0xFX1NU QVRFX0FDVElWRSkKPiA+PiArCQlnb3RvIGV4aXQ7Cj4gPj4gKwo+ID4+ICsJY2RuczNfcm9sZV9z dG9wKGNkbnMpOwo+ID4+ICsKPiA+PiArCXJvbGUgPSBjZHNuM19nZXRfcmVhbF9yb2xlKGNkbnMp Owo+ID4+ICsKPiA+PiArCWN1cnJlbnRfcm9sZSA9IGNkbnMtPnJvbGU7Cj4gPj4gKwlkZXZfZGJn KGNkbnMtPmRldiwgIlN3aXRjaGluZyByb2xlIik7Cj4gPj4gKwo+ID4+ICsJcmV0ID0gY2RuczNf cm9sZV9zdGFydChjZG5zLCByb2xlKTsKPiA+PiArCWlmIChyZXQpIHsKPiA+PiArCQkvKiBCYWNr IHRvIGN1cnJlbnQgcm9sZSAqLwo+ID4+ICsJCWRldl9lcnIoY2Rucy0+ZGV2LCAic2V0ICVkIGhh cyBmYWlsZWQsIGJhY2sgdG8gJWRcbiIsCj4gPj4gKwkJCXJvbGUsIGN1cnJlbnRfcm9sZSk7Cj4g Pj4gKwkJY2RuczNfcm9sZV9zdGFydChjZG5zLCBjdXJyZW50X3JvbGUpOwo+ID4+ICsJfQo+ID4+ ICtleGl0Ogo+ID4+ICsJcG1fcnVudGltZV9wdXRfc3luYyhjZG5zLT5kZXYpOwo+ID4+ICt9Cj4g Pj4gKwo+ID4+ICsvKioKPiA+PiArICogY2RuczNfcHJvYmUgLSBwcm9iZSBmb3IgY2RuczMgY29y ZSBkZXZpY2UKPiA+PiArICogQHBkZXY6IFBvaW50ZXIgdG8gY2RuczMgY29yZSBwbGF0Zm9ybSBk ZXZpY2UKPiA+PiArICoKPiA+PiArICogUmV0dXJucyAwIG9uIHN1Y2Nlc3Mgb3RoZXJ3aXNlIG5l Z2F0aXZlIGVycm5vCj4gPj4gKyAqLwo+ID4+ICtzdGF0aWMgaW50IGNkbnMzX3Byb2JlKHN0cnVj dCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYpCj4gPj4gK3sKPiA+PiArCXN0cnVjdCBkZXZpY2UgKmRl diA9ICZwZGV2LT5kZXY7Cj4gPj4gKwlzdHJ1Y3QgcmVzb3VyY2UJKnJlczsKPiA+PiArCXN0cnVj dCBjZG5zMyAqY2RuczsKPiA+PiArCXZvaWQgX19pb21lbSAqcmVnczsKPiA+PiArCWludCByZXQ7 Cj4gPj4gKwo+ID4+ICsJY2RucyA9IGRldm1fa3phbGxvYyhkZXYsIHNpemVvZigqY2RucyksIEdG UF9LRVJORUwpOwo+ID4+ICsJaWYgKCFjZG5zKQo+ID4+ICsJCXJldHVybiAtRU5PTUVNOwo+ID4+ ICsKPiA+PiArCWNkbnMtPmRldiA9IGRldjsKPiA+PiArCj4gPj4gKwlwbGF0Zm9ybV9zZXRfZHJ2 ZGF0YShwZGV2LCBjZG5zKTsKPiA+PiArCj4gPj4gKwlyZXMgPSBwbGF0Zm9ybV9nZXRfcmVzb3Vy Y2UocGRldiwgSU9SRVNPVVJDRV9JUlEsIDApOwo+ID4+ICsJaWYgKCFyZXMpIHsKPiA+PiArCQlk ZXZfZXJyKGRldiwgIm1pc3NpbmcgSVJRXG4iKTsKPiA+PiArCQlyZXR1cm4gLUVOT0RFVjsKPiA+ PiArCX0KPiA+PiArCWNkbnMtPmlycSA9IHJlcy0+c3RhcnQ7Cj4gPj4gKwo+ID4+ICsJY2Rucy0+ eGhjaV9yZXNbMF0gPSAqcmVzOwo+ID4+ICsKPiA+PiArCS8qCj4gPj4gKwkgKiBSZXF1ZXN0IG1l bW9yeSByZWdpb24KPiA+PiArCSAqIHJlZ2lvbi0wOiB4SENJCj4gPj4gKwkgKiByZWdpb24tMTog UGVyaXBoZXJhbAo+ID4+ICsJICogcmVnaW9uLTI6IE9URyByZWdpc3RlcnMKPiA+PiArCSAqLwo+ ID50aGUgY29tbWVudCBzaG91bGQgYmUgbW9kaWZpZWQgb3IgcmVtb3ZlZCBpZiBub3QgbmVjZXNz YXJ5IHdoZW4gY29kZXMKPiA+Y2hhbmdlZC4KPiAKPiBZZXMsIG5vdyBpdCdzIG5vdCBuZWNlc3Nh cnkuIAo+IAo+ID4+ICsJcmVzID0gcGxhdGZvcm1fZ2V0X3Jlc291cmNlX2J5bmFtZShwZGV2LCBJ T1JFU09VUkNFX01FTSwgInhoY2kiKTsKPiA+PiArCWlmICghcmVzKQo+ID4+ICsJCXJldHVybiAt RU5YSU87Cj4gPj4gKwo+ID4+ICsJY2Rucy0+eGhjaV9yZXNbMV0gPSAqcmVzOwo+ID4+ICsKPiA+ PiArCXJlcyA9IHBsYXRmb3JtX2dldF9yZXNvdXJjZV9ieW5hbWUocGRldiwgSU9SRVNPVVJDRV9N RU0sICJkZXYiKTsKPiA+PiArCXJlZ3MgPSBkZXZtX2lvcmVtYXBfcmVzb3VyY2UoZGV2LCByZXMp Owo+ID4+ICsJaWYgKElTX0VSUihyZWdzKSkKPiA+PiArCQlyZXR1cm4gUFRSX0VSUihyZWdzKTsK PiA+PiArCWNkbnMtPmRldl9yZWdzCT0gcmVnczsKPiA+PiArCj4gPj4gKwlyZXMgPSBwbGF0Zm9y bV9nZXRfcmVzb3VyY2VfYnluYW1lKHBkZXYsIElPUkVTT1VSQ0VfTUVNLCAib3RnIik7Cj4gPj4g KwlpZiAoIXJlcykKPiA+PiArCQlyZXR1cm4gLUVOWElPOwo+ID4+ICsKPiA+PiArCWNkbnMtPm90 Z19yZXMgPSAqcmVzOwo+ID4+ICsKPiA+PiArCW11dGV4X2luaXQoJmNkbnMtPm11dGV4KTsKPiA+ PiArCj4gPj4gKwljZG5zLT5waHkgPSBkZXZtX3BoeV9vcHRpb25hbF9nZXQoZGV2LCAiY2RuczMs dXNicGh5Iik7Cj4gPj4gKwlpZiAoSVNfRVJSKGNkbnMtPnBoeSkpCj4gPj4gKwkJcmV0dXJuIFBU Ul9FUlIoY2Rucy0+cGh5KTsKPiA+PiArCj4gPj4gKwlwaHlfaW5pdChjZG5zLT5waHkpOwo+ID5j aGVjayB0aGUgcmV0dXJuIHZhbHVlPyBhbmQKPiA+SXQncyBiZXR0ZXIgdG8gY2FsbCBwaHlfcG93 ZXJfb24oKSBoZXJlIGV2ZW4gaWYgdGhlIHBoeSBkcml2ZXIgZG9lc24ndAo+ID5wcm92aWRlIHBv d2VyX29uKCkKPiAKPiBEcml2ZXIgZG9lc24ndCBuZWVkIHRvIGNoZWNrIHJldHVybiB2YWx1ZSBp biB0aGlzIGNhc2UuIEl0IHdhcyBkaXNjdXNzZWQgc29tZSB0aW1lIGFnby4gCk9rLCBJIG1pc3Nl ZCBvdXQgc29tZXRoaW5nCgo+IAo+ID4KPiA+PiArCj4gPj4gKwlJTklUX1dPUksoJmNkbnMtPnJv bGVfc3dpdGNoX3dxLCBjZG5zM19yb2xlX3N3aXRjaCk7Cj4gPj4gKwo+ID4+ICsJcmV0ID0gY2Ru czNfZHJkX2luaXQoY2Rucyk7Cj4gPj4gKwlpZiAocmV0KQo+ID4+ICsJCWdvdG8gZXJyOwo+ID4+ ICsKPiA+PiArCXJldCA9IGNkbnMzX2NvcmVfaW5pdF9yb2xlKGNkbnMpOwo+ID4+ICsJaWYgKHJl dCkKPiA+PiArCQlnb3RvIGVycjsKPiA+PiArCj4gPj4gKwljZG5zM19kZWJ1Z2ZzX2luaXQoY2Ru cyk7Cj4gPj4gKwlkZXZpY2Vfc2V0X3dha2V1cF9jYXBhYmxlKGRldiwgdHJ1ZSk7Cj4gPj4gKwlw bV9ydW50aW1lX3NldF9hY3RpdmUoZGV2KTsKPiA+PiArCXBtX3J1bnRpbWVfZW5hYmxlKGRldik7 Cj4gPj4gKwo+ID4+ICsJLyoKPiA+PiArCSAqIFRoZSBjb250cm9sbGVyIG5lZWRzIGxlc3MgdGlt ZSBiZXR3ZWVuIGJ1cyBhbmQgY29udHJvbGxlciBzdXNwZW5kLAo+ID4+ICsJICogYW5kIHdlIGFs c28gbmVlZHMgYSBzbWFsbCBkZWxheSB0byBhdm9pZCBmcmVxdWVudGx5IGVudGVyaW5nIGxvdwo+ ID4+ICsJICogcG93ZXIgbW9kZS4KPiA+PiArCSAqLwo+ID4+ICsJcG1fcnVudGltZV9zZXRfYXV0 b3N1c3BlbmRfZGVsYXkoZGV2LCAyMCk7Cj4gPj4gKwlwbV9ydW50aW1lX21hcmtfbGFzdF9idXN5 KGRldik7Cj4gPj4gKwlwbV9ydW50aW1lX3VzZV9hdXRvc3VzcGVuZChkZXYpOwo+ID4+ICsJZGV2 X2RiZyhkZXYsICJDYWRlbmNlIFVTQjMgY29yZTogcHJvYmUgc3VjY2VlZFxuIik7Cj4gPj4gKwo+ ID4+ICsJcmV0dXJuIDA7Cj4gPj4gKwo+ID4+ICtlcnI6Cj4gPj4gKwlwaHlfZXhpdChjZG5zLT5w aHkpOwo+ID4+ICsJcmV0dXJuIHJldDsKPiA+PiArfQo+ID4+ICsKPiA+PiArLyoqCj4gPj4gKyAq IGNkbnMzX3JlbW92ZSAtIHVuYmluZCBkcmQgZHJpdmVyIGFuZCBjbGVhbiB1cAo+ID4+ICsgKiBA cGRldjogUG9pbnRlciB0byBMaW51eCBwbGF0Zm9ybSBkZXZpY2UKPiA+PiArICoKPiA+PiArICog UmV0dXJucyAwIG9uIHN1Y2Nlc3Mgb3RoZXJ3aXNlIG5lZ2F0aXZlIGVycm5vCj4gPj4gKyAqLwo+ ID4+ICtzdGF0aWMgaW50IGNkbnMzX3JlbW92ZShzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2 KQo+ID4+ICt7Cj4gPj4gKwlzdHJ1Y3QgY2RuczMgKmNkbnMgPSBwbGF0Zm9ybV9nZXRfZHJ2ZGF0 YShwZGV2KTsKPiA+PiArCj4gPj4gKwlwbV9ydW50aW1lX2dldF9zeW5jKCZwZGV2LT5kZXYpOwo+ ID4+ICsJcG1fcnVudGltZV9kaXNhYmxlKCZwZGV2LT5kZXYpOwo+ID4+ICsJcG1fcnVudGltZV9w dXRfbm9pZGxlKCZwZGV2LT5kZXYpOwo+ID4+ICsJY2RuczNfZGVidWdmc19leGl0KGNkbnMpOwo+ ID4+ICsJY2RuczNfZXhpdF9yb2xlcyhjZG5zKTsKPiA+PiArCXBoeV9leGl0KGNkbnMtPnBoeSk7 Cj4gPj4gKwlyZXR1cm4gMDsKPiA+PiArfQo+ID4+ICsKPiA+PiArI2lmZGVmIENPTkZJR19PRgo+ ID4+ICtzdGF0aWMgY29uc3Qgc3RydWN0IG9mX2RldmljZV9pZCBvZl9jZG5zM19tYXRjaFtdID0g ewo+ID4+ICsJeyAuY29tcGF0aWJsZSA9ICJjZG5zLHVzYjMtMS4wLjAiIH0sCj4gPj4gKwl7IC5j b21wYXRpYmxlID0gImNkbnMsdXNiMy0xLjAuMSIgfSwKPiA+PiArCXsgfSwKPiA+PiArfTsKPiA+ PiArTU9EVUxFX0RFVklDRV9UQUJMRShvZiwgb2ZfY2RuczNfbWF0Y2gpOwo+ID4+ICsjZW5kaWYK PiA+PiArCj4gPj4gK3N0YXRpYyBzdHJ1Y3QgcGxhdGZvcm1fZHJpdmVyIGNkbnMzX2RyaXZlciA9 IHsKPiA+PiArCS5wcm9iZQkJPSBjZG5zM19wcm9iZSwKPiA+PiArCS5yZW1vdmUJCT0gY2RuczNf cmVtb3ZlLAo+ID4+ICsJLmRyaXZlcgkJPSB7Cj4gPj4gKwkJLm5hbWUJPSAiY2Rucy11c2IzIiwK PiA+PiArCQkub2ZfbWF0Y2hfdGFibGUJPSBvZl9tYXRjaF9wdHIob2ZfY2RuczNfbWF0Y2gpLAo+ ID4+ICsJfSwKPiA+PiArfTsKPiA+PiArCj4gPj4gK21vZHVsZV9wbGF0Zm9ybV9kcml2ZXIoY2Ru czNfZHJpdmVyKTsKPiA+PiArCj4gPj4gK01PRFVMRV9BTElBUygicGxhdGZvcm06Y2RuczMiKTsK PiA+PiArTU9EVUxFX0FVVEhPUigiUGF3ZWwgTGFzemN6YWsgPHBhd2VsbEBjYWRlbmNlLmNvbT4i KTsKPiA+PiArTU9EVUxFX0xJQ0VOU0UoIkdQTCB2MiIpOwo+ID4+ICtNT0RVTEVfREVTQ1JJUFRJ T04oIkNhZGVuY2UgVVNCMyBEUkQgQ29udHJvbGxlciBEcml2ZXIiKTsKPiA+PiBkaWZmIC0tZ2l0 IGEvZHJpdmVycy91c2IvY2RuczMvY29yZS5oIGIvZHJpdmVycy91c2IvY2RuczMvY29yZS5oCj4g Pj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQKPiA+PiBpbmRleCAwMDAwMDAwMDAwMDAuLmZiNGIzOTIw NjE1OAo+ID4+IC0tLSAvZGV2L251bGwKPiA+PiArKysgYi9kcml2ZXJzL3VzYi9jZG5zMy9jb3Jl LmgKPiA+PiBAQCAtMCwwICsxLDExNiBAQAo+ID4+ICsvKiBTUERYLUxpY2Vuc2UtSWRlbnRpZmll cjogR1BMLTIuMCAqLwo+ID4+ICsvKgo+ID4+ICsgKiBDYWRlbmNlIFVTQlNTIERSRCBIZWFkZXIg RmlsZS4KPiA+PiArICoKPiA+PiArICogQ29weXJpZ2h0IChDKSAyMDE3LTIwMTggTlhQCj4gPj4g KyAqIENvcHlyaWdodCAoQykgMjAxOCBDYWRlbmNlLgo+ID4+ICsgKgo+ID4+ICsgKiBBdXRob3Jz OiBQZXRlciBDaGVuIDxwZXRlci5jaGVuQG54cC5jb20+Cj4gPj4gKyAqICAgICAgICAgIFBhd2Vs IExhc3pjemFrIDxwYXdlbGxAY2FkZW5jZS5jb20+Cj4gPj4gKyAqLwo+ID4+ICsjaW5jbHVkZSA8 bGludXgvdXNiL290Zy5oPgo+ID4+ICsKPiA+PiArI2lmbmRlZiBfX0xJTlVYX0NETlMzX0NPUkVf SAo+ID4+ICsjZGVmaW5lIF9fTElOVVhfQ0ROUzNfQ09SRV9ICj4gPj4gKwo+ID4+ICtzdHJ1Y3Qg Y2RuczM7Cj4gPj4gK2VudW0gY2RuczNfcm9sZXMgewo+ID4+ICsJQ0ROUzNfUk9MRV9IT1NUID0g MCwKPiA+PiArCUNETlMzX1JPTEVfR0FER0VULAo+ID4+ICsJQ0ROUzNfUk9MRV9FTkQsCj4gPj4g K307Cj4gPj4gKwo+ID4+ICsvKioKPiA+PiArICogc3RydWN0IGNkbnMzX3JvbGVfZHJpdmVyIC0g aG9zdC9nYWRnZXQgcm9sZSBkcml2ZXIKPiA+PiArICogQHN0YXJ0OiBzdGFydCB0aGlzIHJvbGUK PiA+PiArICogQHN0b3A6IHN0b3AgdGhpcyByb2xlCj4gPj4gKyAqIEBzdXNwZW5kOiBzdXNwZW5k IGNhbGxiYWNrIGZvciB0aGlzIHJvbGUKPiA+PiArICogQHJlc3VtZTogcmVzdW1lIGNhbGxiYWNr IGZvciB0aGlzIHJvbGUKPiA+PiArICogQGlycTogaXJxIGhhbmRsZXIgZm9yIHRoaXMgcm9sZQo+ ID5ubyBpcnEgbWVtYmVyLAo+ID4+ICsgKiBAbmFtZTogcm9sZSBuYW1lIHN0cmluZyAoaG9zdC9n YWRnZXQpCj4gPj4gKyAqIEBzdGF0ZTogY3VycmVudCBzdGF0ZQo+ID4+ICsgKi8KPiA+PiArc3Ry dWN0IGNkbnMzX3JvbGVfZHJpdmVyIHsKPiA+PiArCWludCAoKnN0YXJ0KShzdHJ1Y3QgY2RuczMg KmNkbnMpOwo+ID4+ICsJdm9pZCAoKnN0b3ApKHN0cnVjdCBjZG5zMyAqY2Rucyk7Cj4gPj4gKwlp bnQgKCpzdXNwZW5kKShzdHJ1Y3QgY2RuczMgKmNkbnMsIGJvb2wgZG9fd2FrZXVwKTsKPiA+PiAr CWludCAoKnJlc3VtZSkoc3RydWN0IGNkbnMzICpjZG5zLCBib29sIGhpYmVybmF0ZWQpOwo+ID4+ ICsJY29uc3QgY2hhciAqbmFtZTsKPiA+PiArI2RlZmluZSBDRE5TM19ST0xFX1NUQVRFX0lOQUNU SVZFCTAKPiA+PiArI2RlZmluZSBDRE5TM19ST0xFX1NUQVRFX0FDVElWRQkJMQo+ID4+ICsJaW50 IHN0YXRlOwo+ID4+ICt9Owo+ID4+ICsKPiA+PiArI2RlZmluZSBDRE5TM19YSENJX1JFU09VUkNF U19OVU0JMgo+ID4+ICsvKioKPiA+PiArICogc3RydWN0IGNkbnMzIC0gUmVwcmVzZW50YXRpb24g b2YgQ2FkZW5jZSBVU0IzIERSRCBjb250cm9sbGVyLgo+ID4+ICsgKiBAZGV2OiBwb2ludGVyIHRv IENhZGVuY2UgZGV2aWNlIHN0cnVjdAo+ID4+ICsgKiBAeGhjaV9yZWdzOiBwb2ludGVyIHRvIGJh c2Ugb2YgeGhjaSByZWdpc3RlcnMKPiA+PiArICogQHhoY2lfcmVzOiB0aGUgcmVzb3VyY2UgZm9y IHhoY2kKPiA+PiArICogQGRldl9yZWdzOiBwb2ludGVyIHRvIGJhc2Ugb2YgZGV2IHJlZ2lzdGVy cwo+ID4+ICsgKiBAb3RnX3JlZ3M6IHBvaW50ZXIgdG8gYmFzZSBvZiBvdGcgcmVnaXN0ZXJzCj4g Pm5vdCBwb2ludGVyCj4gCj4gV2h5ID8gCj4gc3RydWN0IGNkbnMzX290Z19jb21tb25fcmVncwkq b3RnX3JlZ3M7ClNvcnJ5LCBJIG1heSBzZWUgb3RnX3JlcyBhcyBvdGdfcmVncwoKPiAKPiBCdXQg SSBmb3Jnb3Q6Cj4gICogQG90Z19yZXM6IHRoZSByZXNvdXJjZSBmb3Igb3RnCj4gICogQG90Z192 MF9yZWdzOiBwb2ludGVyIHRvIGJhc2Ugb2YgdjAgb3RnIHJlZ2lzdGVycwo+ICAqIEBvdGdfdjFf cmVnczogcG9pbnRlciB0byBiYXNlIG9mIHYxIG90ZyByZWdpc3RlcnMKPiAKPiA+PiArICogQGly cTogaXJxIG51bWJlciBmb3IgY29udHJvbGxlcgo+ID4+ICsgKiBAcm9sZXM6IGFycmF5IG9mIHN1 cHBvcnRlZCByb2xlcyBmb3IgdGhpcyBjb250cm9sbGVyCj4gPj4gKyAqIEByb2xlOiBjdXJyZW50 IHJvbGUKPiA+PiArICogQGhvc3RfZGV2OiB0aGUgY2hpbGQgaG9zdCBkZXZpY2UgcG9pbnRlciBm b3IgY2RuczMgY29yZQo+ID4+ICsgKiBAZ2FkZ2V0X2RldjogdGhlIGNoaWxkIGdhZGdldCBkZXZp Y2UgcG9pbnRlciBmb3IgY2RuczMgY29yZQo+ID4+ICsgKiBAdXNiOiBwaHkgZm9yIHRoaXMgY29u dHJvbGxlcgo+ID4+ICsgKiBAcm9sZV9zd2l0Y2hfd3E6IHdvcmsgcXVldWUgaXRlbSBmb3Igcm9s ZSBzd2l0Y2gKPiA+PiArICogQGluX2xwbTogdGhlIGNvbnRyb2xsZXIgaW4gbG93IHBvd2VyIG1v ZGUKPiA+PiArICogQHdha2V1cF9pbnQ6IHRoZSB3YWtldXAgaW50ZXJydXB0Cj4gPj4gKyAqIEBt dXRleDogdGhlIG11dGV4IGZvciBjb25jdXJyZW50IGNvZGUgYXQgZHJpdmVyCj4gPj4gKyAqIEBk cl9tb2RlOiBzdXBwb3J0ZWQgbW9kZSBvZiBvcGVyYXRpb24gaXQgY2FuIGJlIG9ubHkgSG9zdCwg b25seSBEZXZpY2UKPiA+PiArICogICAgICAgICAgIG9yIE9URyBtb2RlIHRoYXQgYWxsb3cgdG8g c3dpdGNoIGJldHdlZW4gRGV2aWNlIGFuZCBIb3N0IG1vZGUuCj4gPj4gKyAqICAgICAgICAgICBU aGlzIGZpZWxkIGJhc2VkIG9uIGZpcm13YXJlIHNldHRpbmcsIGtlcm5lbCBjb25maWd1cmF0aW9u Cj4gPj4gKyAqICAgICAgICAgICBhbmQgaGFyZHdhcmUgY29uZmlndXJhdGlvbi4KPiA+PiArICog QGN1cnJlbnRfZHJfbW9kZTogY3VycmVudCBtb2RlIG9mIG9wZXJhdGlvbiB3aGVuIGluIGR1YWwt cm9sZSBtb2RlCj4gPj4gKyAqIEBkZXNpcmVkX2RyX21vZGU6IGRlc2lyZWQgbW9kZSBvZiBvcGVy YXRpb24gd2hlbiBpbiBkdWFsLXJvbGUgbW9kZS4KPiA+PiArICogICAgICAgICAgIFRoaXMgdmFs dWUgY2FuIGJlIGNoYW5nZWQgZHVyaW5nIHJ1bnRpbWUuCj4gPj4gKyAqICAgICAgICAgICBBdmFp bGFibGUgb3B0aW9ucyBkZXBlbmRzIG9uICBkcl9tb2RlOgo+ID4+ICsgKiAgICAgICAgICAgZHJf bW9kZSAgICAgICAgICAgICAgICAgfCAgZGVzaXJlZF9kcl9tb2RlIGFuZCBjdXJyZW50X2RyX21v ZGUKPiA+PiArICogICAgICAgICAgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KPiA+PiArICogICAgICAgICAgIFVTQl9EUl9N T0RFX0hPU1QgICAgICAgIHwgb25seSBVU0JfRFJfTU9ERV9IT1NUCj4gPj4gKyAqICAgICAgICAg ICBVU0JfRFJfTU9ERV9QRVJJUEhFUkFMICB8IG9ubHkgVVNCX0RSX01PREVfUEVSSVBIRVJBTAo+ ID4+ICsgKiAgICAgICAgICAgVVNCX0RSX01PREVfT1RHICAgICAgICAgfCBvbmx5IFVTQl9EUl9N T0RFX0hPU1QKPiA+PiArICogICAgICAgICAgIFVTQl9EUl9NT0RFX09URyAgICAgICAgIHwgb25s eSBVU0JfRFJfTU9ERV9QRVJJUEhFUkFMCj4gPj4gKyAqICAgICAgICAgICBVU0JfRFJfTU9ERV9P VEcgICAgICAgICB8IFVTQl9EUl9NT0RFX09URwo+ID4+ICsgKgo+ID4+ICsgKiAgICAgICAgICAg RGVzaXJlZF9kcl9yb2xlIGNhbiBiZSBjaGFuZ2VkIGJ5IG1lYW5zIG9mIGRlYnVnZnMuCj4gPj4g KyAqIEByb290OiBkZWJ1Z2ZzIHJvb3QgZm9sZGVyIHBvaW50ZXIKPiA+PiArICogQGRlYnVnX2Rp c2FibGU6Cj4gPj4gKyAqLwo+ID4+ICtzdHJ1Y3QgY2RuczMgewo+ID4+ICsJc3RydWN0IGRldmlj ZQkJCSpkZXY7Cj4gPj4gKwl2b2lkIF9faW9tZW0JCQkqeGhjaV9yZWdzOwo+ID4+ICsJc3RydWN0 IHJlc291cmNlCQkJeGhjaV9yZXNbQ0ROUzNfWEhDSV9SRVNPVVJDRVNfTlVNXTsKPiA+PiArCXN0 cnVjdCBjZG5zM191c2JfcmVncyBfX2lvbWVtCSpkZXZfcmVnczsKPiA+PiArCj4gPj4gKwlzdHJ1 Y3QgcmVzb3VyY2UJCQlvdGdfcmVzOwo+ID4+ICsJc3RydWN0IGNkbnMzX290Z19sZWdhY3lfcmVn cwkqb3RnX3YwX3JlZ3M7Cj4gPj4gKwlzdHJ1Y3QgY2RuczNfb3RnX3JlZ3MJCSpvdGdfdjFfcmVn czsKPiA+PiArCXN0cnVjdCBjZG5zM19vdGdfY29tbW9uX3JlZ3MJKm90Z19yZWdzOwo+ID4+ICsj ZGVmaW5lIENETlMzX0NPTlRST0xMRVJfVjAJMAo+ID4+ICsjZGVmaW5lIENETlMzX0NPTlRST0xM RVJfVjEJMQo+ID4+ICsJdTMyCQkJCXZlcnNpb247Cj4gPj4gKwo+ID4+ICsJaW50CQkJCWlycTsK PiA+PiArCXN0cnVjdCBjZG5zM19yb2xlX2RyaXZlcgkqcm9sZXNbQ0ROUzNfUk9MRV9FTkRdOwo+ ID4+ICsJZW51bSBjZG5zM19yb2xlcwkJcm9sZTsKPiA+PiArCXN0cnVjdCBwbGF0Zm9ybV9kZXZp Y2UJCSpob3N0X2RldjsKPiA+PiArCXN0cnVjdCBjZG5zM19kZXZpY2UJCSpnYWRnZXRfZGV2Owo+ ID4+ICsJc3RydWN0IHBoeQkJCSpwaHk7Cj4gPkRvZXMgdGhlIHNpbmdsZSBwaHkgc3VwcG9ydCBi b3RoIEhTIGFuZCBTUz8KPiA+PiArCXN0cnVjdCB3b3JrX3N0cnVjdAkJcm9sZV9zd2l0Y2hfd3E7 Cj4gPj4gKwlpbnQJCQkJaW5fbHBtOjE7Cj4gPj4gKwlpbnQJCQkJd2FrZXVwX2ludDoxOwo+ID4+ ICsJLyogbXV0ZXh0IHVzZWQgaW4gd29ya3F1ZXVlKi8KPiA+PiArCXN0cnVjdCBtdXRleAkJCW11 dGV4Owo+ID4+ICsJZW51bSB1c2JfZHJfbW9kZQkJZHJfbW9kZTsKPiA+PiArCWVudW0gdXNiX2Ry X21vZGUJCWN1cnJlbnRfZHJfbW9kZTsKPiA+PiArCWVudW0gdXNiX2RyX21vZGUJCWRlc2lyZWRf ZHJfbW9kZTsKPiA+PiArCXN0cnVjdCBkZW50cnkJCQkqcm9vdDsKPiA+PiArCWludAkJCQlkZWJ1 Z19kaXNhYmxlOjE7Cj4gPj4gK307Cj4gPj4gKwoKPiBbLi4uXQoKPiA+Cj4gVGhhbmtzLCAKPiBQ YXdlbAo=