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=-9.0 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_PASS,USER_AGENT_GIT 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 0BABFC43381 for ; Thu, 21 Feb 2019 20:25:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id BA7F42080F for ; Thu, 21 Feb 2019 20:25:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726684AbfBUUZT (ORCPT ); Thu, 21 Feb 2019 15:25:19 -0500 Received: from mail-out.m-online.net ([212.18.0.10]:36985 "EHLO mail-out.m-online.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726625AbfBUUZS (ORCPT ); Thu, 21 Feb 2019 15:25:18 -0500 Received: from frontend01.mail.m-online.net (unknown [192.168.8.182]) by mail-out.m-online.net (Postfix) with ESMTP id 4455Z32Gylz1qxK0; Thu, 21 Feb 2019 21:25:15 +0100 (CET) Received: from localhost (dynscan1.mnet-online.de [192.168.6.70]) by mail.m-online.net (Postfix) with ESMTP id 4455Z31sjPz1qswm; Thu, 21 Feb 2019 21:25:15 +0100 (CET) X-Virus-Scanned: amavisd-new at mnet-online.de Received: from mail.mnet-online.de ([192.168.8.182]) by localhost (dynscan1.mail.m-online.net [192.168.6.70]) (amavisd-new, port 10024) with ESMTP id po57tAK0rmMj; Thu, 21 Feb 2019 21:25:13 +0100 (CET) X-Auth-Info: HV9r+s9eq7+4YRsmf1iu2PrSI3yg4fcj+cVEIePOoHM= Received: from localhost.localdomain (p54833194.dip0.t-ipconnect.de [84.131.49.148]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.mnet-online.de (Postfix) with ESMTPSA; Thu, 21 Feb 2019 21:25:13 +0100 (CET) From: Anatolij Gustschin To: linux-usb@vger.kernel.org, linux-spi@vger.kernel.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: gregkh@linuxfoundation.org, broonie@kernel.org, atull@kernel.org, mdf@kernel.org Subject: [PATCH v4 3/3] fpga: Add fpga manager driver for ARRI Altera FPP Date: Thu, 21 Feb 2019 21:25:06 +0100 Message-Id: <20190221202506.17744-4-agust@denx.de> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190221202506.17744-1-agust@denx.de> References: <20190221202506.17744-1-agust@denx.de> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add FPGA manager driver for loading ARRI Altera FPGAs via fast passive parallel (FPP) interface using FTDI FT232H chip. Signed-off-by: Anatolij Gustschin --- .../ABI/testing/sysfs-driver-ftdi-fifo-fpp | 7 + drivers/fpga/Kconfig | 7 + drivers/fpga/Makefile | 1 + drivers/fpga/ftdi-fifo-fpp.c | 594 ++++++++++++++++++ 4 files changed, 609 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-driver-ftdi-fifo-fpp create mode 100644 drivers/fpga/ftdi-fifo-fpp.c diff --git a/Documentation/ABI/testing/sysfs-driver-ftdi-fifo-fpp b/Documentation/ABI/testing/sysfs-driver-ftdi-fifo-fpp new file mode 100644 index 000000000000..f3055100d07e --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-ftdi-fifo-fpp @@ -0,0 +1,7 @@ +What: /sys/bus/platform/devices/ftdi-fifo-fpp-mgr.N/cfg_mode +Date: Feb 2019 +Kernel Version: 5.2 +Contact: Anatolij Gustschin +Description: + Contains either "fifo" or "bitbang" and controls if fifo + of bitbang configuration mode is used in the driver. diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index c20445b867ae..19d82163a0b2 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -50,6 +50,13 @@ config FPGA_MGR_ALTERA_CVP FPGA manager driver support for Arria-V, Cyclone-V, Stratix-V and Arria 10 Altera FPGAs using the CvP interface over PCIe. +config FPGA_MGR_FTDI_FIFO_FPP + tristate "Altera FPP over FT232H FIFO" + depends on USB_FT232H_INTF + help + FPGA manager driver support for Altera fast passive parallel + interface (FPP) over FT232H FT245 FIFO. + config FPGA_MGR_ZYNQ_FPGA tristate "Xilinx Zynq FPGA" depends on ARCH_ZYNQ || COMPILE_TEST diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index c0dd4c82fbdb..61725d31e6d1 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_FPGA) += fpga-mgr.o # FPGA Manager Drivers obj-$(CONFIG_FPGA_MGR_ALTERA_CVP) += altera-cvp.o obj-$(CONFIG_FPGA_MGR_ALTERA_PS_SPI) += altera-ps-spi.o +obj-$(CONFIG_FPGA_MGR_FTDI_FIFO_FPP) += ftdi-fifo-fpp.o obj-$(CONFIG_FPGA_MGR_ICE40_SPI) += ice40-spi.o obj-$(CONFIG_FPGA_MGR_MACHXO2_SPI) += machxo2-spi.o obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o diff --git a/drivers/fpga/ftdi-fifo-fpp.c b/drivers/fpga/ftdi-fifo-fpp.c new file mode 100644 index 000000000000..2bc72335cd70 --- /dev/null +++ b/drivers/fpga/ftdi-fifo-fpp.c @@ -0,0 +1,594 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Altera FPGA firmware upload via FPP using FT232H Bitbang/FT245-FIFO. + * + * Copyright (C) 2017 - 2018 DENX Software Engineering + * Anatolij Gustschin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BULK_OUT_BUF_SZ SZ_1M +#define MAX_RETRIES 10 + +/* + * With logic of CPLD we can write the state of nConfig pin and + * read back the state of some pins (conf_done, init_done, nStatus). + * Status header and bit assignment in data register on CPLD. + */ +#define INPUT_HEADER_0 0xA5 +#define INPUT_HEADER_1 0x5A +#define IN_CONF_DONE BIT(0) +#define IN_INIT_DONE BIT(1) +#define IN_ADDR_SELECT BIT(4) +#define IN_BOARD_REV BIT(5) +#define OUT_NCONFIG BIT(0) +#define OUT_RESET_N BIT(1) + +enum fpp_board_rev { + BOARD_REVA = 1, + BOARD_REVB = 2, +}; + +enum fpp_addr_sel { + ADDR_SELECT_INVALID, + ADDR_SELECT_GND, + ADDR_SELECT_NC +}; + +struct fpp_mgr_ops { + int (*write_init)(struct fpga_manager *mgr, + struct fpga_image_info *info, + const char *buf, size_t count); + int (*write)(struct fpga_manager *mgr, const char *buf, size_t count); + int (*write_complete)(struct fpga_manager *mgr, + struct fpga_image_info *info); +}; + +struct fpp_fpga_mgr_priv { + struct platform_device *pdev; + struct usb_interface *intf; + const struct ft232h_intf_ops *iops; + struct fpga_manager *mgr; + struct fpp_mgr_ops *ops; + struct gpio_desc *nconfig; + struct gpio_desc *conf_done; + char cfg_mode[8]; + u8 out_data_port; + int index; + void *bulk_buf; + char usb_dev_id[32]; + char fpga_mgr_name[64]; + enum fpp_board_rev rev; + enum fpp_addr_sel addr_sel; +}; + +static int fpp_fpga_mgr_set_data_port(struct fpp_fpga_mgr_priv *priv, + u8 bitmask, u8 value) +{ + struct device *dev = &priv->pdev->dev; + struct bulk_desc desc; + u8 *data; + int ret; + + /* + * With CPLD connected (in FT245 FIFO mode) we use ACBUS8&9 + * pins to switch between data and command mode: + * ACBUS8&9 == 0, 0 --> normal mode (data communication) + * ACBUS8&9 == 1, 0 --> command mode + */ + gpiod_set_raw_value_cansleep(priv->nconfig, 1); + gpiod_set_raw_value_cansleep(priv->conf_done, 0); + msleep(50); + + /* Write commands to CPLD */ + ret = priv->iops->set_bitmode(priv->intf, 0x00, BITMODE_SYNCFF); + if (ret) + return ret; + + if (value) + priv->out_data_port |= bitmask; + else + priv->out_data_port &= ~bitmask; + + data = priv->bulk_buf; + *data = priv->out_data_port; + + desc.dir_out = true; + desc.act_len = 0; + desc.len = 1; + desc.data = data; + desc.timeout = FTDI_USB_WRITE_TIMEOUT; + + ret = priv->iops->bulk_xfer(priv->intf, &desc); + if (ret) { + dev_err(dev, "Writing in SYNCFF mode failed: %d\n", ret); + return ret; + } + + msleep(50); + /* Switch back to data mode with ACBUS8&9 back to low */ + gpiod_set_raw_value_cansleep(priv->nconfig, 0); + gpiod_set_raw_value_cansleep(priv->conf_done, 0); + msleep(50); + + return 0; +} + +static int fpp_fpga_mgr_bitbang_write_init(struct fpga_manager *mgr, + struct fpga_image_info *info, + const char *buf, size_t count) +{ + struct fpp_fpga_mgr_priv *priv = mgr->priv; + struct device *dev = &priv->pdev->dev; + int retries = MAX_RETRIES; + int ret; + + gpiod_set_value_cansleep(priv->nconfig, 0); + msleep(50); + gpiod_set_value_cansleep(priv->nconfig, 1); + msleep(50); + gpiod_set_value_cansleep(priv->nconfig, 0); + + /* Wait for CONF_DONE to get low */ + do { + msleep(50); + + ret = gpiod_get_value_cansleep(priv->conf_done); + if (ret < 0) { + dev_err(dev, "Failed to get CONF_DONE pin: %d\n", ret); + return ret; + } + + if (!ret) + break; + } while (--retries > 0); + + if (!retries) { + dev_warn(dev, "CONF_DONE low wait timeout\n"); + return -ETIMEDOUT; + } + + ret = priv->iops->set_bitmode(priv->intf, 0xff, BITMODE_BITBANG); + if (ret < 0) + return ret; + + /* Set max. working baud rate (for hardware without CPLD) */ + return priv->iops->set_baudrate(priv->intf, 700000); +} + +static int fpp_fpga_mgr_bitbang_write(struct fpga_manager *mgr, + const char *buf, size_t count) +{ + struct fpp_fpga_mgr_priv *priv = mgr->priv; + struct bulk_desc desc; + size_t blk_sz; + int ret; + + desc.data = priv->bulk_buf; + desc.dir_out = true; + desc.timeout = FTDI_USB_WRITE_TIMEOUT; + + while (count) { + blk_sz = min_t(size_t, count, BULK_OUT_BUF_SZ); + memcpy(priv->bulk_buf, buf, blk_sz); + desc.act_len = 0; + desc.len = blk_sz; + ret = priv->iops->bulk_xfer(priv->intf, &desc); + if (ret < 0) + return ret; + + buf += desc.act_len; + count -= desc.act_len; + } + + return 0; +} + +static int fpp_fpga_mgr_bitbang_write_complete(struct fpga_manager *mgr, + struct fpga_image_info *info) +{ + struct fpp_fpga_mgr_priv *priv = mgr->priv; + struct device *dev = &priv->pdev->dev; + int retries = MAX_RETRIES; + int ret; + + /* Wait for CONF_DONE to get high */ + do { + msleep(50); + + ret = gpiod_get_value_cansleep(priv->conf_done); + if (ret < 0) + return ret; + + if (ret) + break; + } while (--retries > 0); + + if (!retries) { + dev_warn(dev, "CONF_DONE wait timeout\n"); + return -ETIMEDOUT; + } + + priv->iops->disable_bitbang(priv->intf); + return 0; +} + +static inline bool status_hdr_is_valid(u8 *buf) +{ + return buf[0] == INPUT_HEADER_0 && buf[1] == INPUT_HEADER_1; +} + +static int fpp_fpga_mgr_read_status(struct fpp_fpga_mgr_priv *priv, u8 *status) +{ + struct device *dev = &priv->pdev->dev; + u8 *inbuf = priv->bulk_buf; + int retries = MAX_RETRIES; + int ret; + + if (!status) + return -EINVAL; + + /* Wait until CPLD sends valid header and status register */ + do { + ret = priv->iops->read_data(priv->intf, inbuf, 64); + if (ret < 0) { + dev_err(dev, "Can't read status data: %d\n", ret); + return ret; + } + + /* Check input buffer header */ + if (ret >= 4 && status_hdr_is_valid(inbuf)) { + *status = inbuf[2]; + return 0; + } + + /* Wait and read back status again */ + msleep(100); /* CPLD sends status every 100ms */ + } while (--retries > 0); + + dev_warn(dev, "Timeout when reading status\n"); + return -ETIMEDOUT; +} + +static int fpp_fpga_mgr_ft245_fifo_write_init(struct fpga_manager *mgr, + struct fpga_image_info *info, + const char *buf, size_t count) +{ + struct fpp_fpga_mgr_priv *priv = mgr->priv; + struct device *dev = &priv->pdev->dev; + int retries = MAX_RETRIES; + int ret; + u8 status; + + gpiod_direction_output_raw(priv->conf_done, 0); + + /* Set/reset nConfig via commands to CPLD */ + ret = fpp_fpga_mgr_set_data_port(priv, OUT_NCONFIG, 1); + if (ret) + return ret; + ret = fpp_fpga_mgr_set_data_port(priv, OUT_NCONFIG, 0); + if (ret) + return ret; + ret = fpp_fpga_mgr_set_data_port(priv, OUT_NCONFIG, 1); + if (ret) + return ret; + + /* In FT245 FIFO mode we need sync FIFO mode to talk to FPGA */ + ret = priv->iops->set_bitmode(priv->intf, 0xff, BITMODE_SYNCFF); + if (ret) + return ret; + + /* Wait until FPGA is ready for loading (conf_done zero) or timeout */ + do { + ret = fpp_fpga_mgr_read_status(priv, &status); + if (!ret) { + /* Check conf_done status */ + if ((status & IN_CONF_DONE) == 0) + break; + } + } while (--retries > 0); + + if (!retries) { + dev_warn(dev, "CONF_DONE wait timeout\n"); + return -ETIMEDOUT; + } + + /* Configure for max. baud rate (3MHz * 4 in bitbang mode) */ + return priv->iops->set_baudrate(priv->intf, 3000000); +} + +static int fpp_fpga_mgr_ft245_fifo_write(struct fpga_manager *mgr, + const char *buf, size_t count) +{ + return fpp_fpga_mgr_bitbang_write(mgr, buf, count); +} + +static int fpp_fpga_mgr_ft245_fifo_write_complete(struct fpga_manager *mgr, + struct fpga_image_info *info) +{ + struct fpp_fpga_mgr_priv *priv = mgr->priv; + struct device *dev = &priv->pdev->dev; + int retries = MAX_RETRIES; + int ret; + u8 mask, status; + + mask = IN_CONF_DONE | IN_INIT_DONE; + + do { + ret = fpp_fpga_mgr_read_status(priv, &status); + if (!ret) { + /* Check conf_done/init_done status */ + if ((status & mask) == mask) + break; + } + } while (--retries > 0); + + if (!retries) { + dev_warn(dev, "INIT_DONE wait timeout\n"); + return -ETIMEDOUT; + } + + /* Release Reset_n, keep nCONFIG high, too! */ + return fpp_fpga_mgr_set_data_port(priv, OUT_NCONFIG | OUT_RESET_N, 1); +} + +static enum fpga_mgr_states fpp_fpga_mgr_state(struct fpga_manager *mgr) +{ + return FPGA_MGR_STATE_UNKNOWN; +} + +static int fpp_fpga_mgr_write_init(struct fpga_manager *mgr, + struct fpga_image_info *info, + const char *buf, size_t count) +{ + struct fpp_fpga_mgr_priv *priv = mgr->priv; + + if (info && info->flags & FPGA_MGR_PARTIAL_RECONFIG) { + dev_err(&mgr->dev, "Partial reconfiguration not supported.\n"); + return -EINVAL; + } + + if (priv->ops->write_init) + return priv->ops->write_init(mgr, info, buf, count); + + return -ENODEV; +} + +static int fpp_fpga_mgr_write(struct fpga_manager *mgr, const char *buf, + size_t count) +{ + struct fpp_fpga_mgr_priv *priv = mgr->priv; + + if (priv->ops->write) + return priv->ops->write(mgr, buf, count); + + return -ENODEV; +} + +static int fpp_fpga_mgr_write_complete(struct fpga_manager *mgr, + struct fpga_image_info *info) +{ + struct fpp_fpga_mgr_priv *priv = mgr->priv; + + if (priv->ops->write_complete) + return priv->ops->write_complete(mgr, info); + + return -ENODEV; +} + +static struct fpp_mgr_ops fpp_mgr_bitbang_ops = { + .write_init = fpp_fpga_mgr_bitbang_write_init, + .write = fpp_fpga_mgr_bitbang_write, + .write_complete = fpp_fpga_mgr_bitbang_write_complete, +}; + +static struct fpp_mgr_ops fpp_mgr_ft245_fifo_ops = { + .write_init = fpp_fpga_mgr_ft245_fifo_write_init, + .write = fpp_fpga_mgr_ft245_fifo_write, + .write_complete = fpp_fpga_mgr_ft245_fifo_write_complete, +}; + +static const struct fpga_manager_ops fpp_fpga_mgr_ops = { + .state = fpp_fpga_mgr_state, + .write_init = fpp_fpga_mgr_write_init, + .write = fpp_fpga_mgr_write, + .write_complete = fpp_fpga_mgr_write_complete, +}; + +static ssize_t cfg_mode_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct fpga_manager *mgr = platform_get_drvdata(pdev); + struct fpp_fpga_mgr_priv *priv = mgr->priv; + + return snprintf(buf, PAGE_SIZE, "%s\n", priv->cfg_mode); +} + +static ssize_t cfg_mode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct platform_device *pdev = to_platform_device(dev); + struct fpga_manager *mgr = platform_get_drvdata(pdev); + struct fpp_fpga_mgr_priv *priv = mgr->priv; + + if (!count || count > sizeof(priv->cfg_mode)) + return -EINVAL; + + if (!strncmp(buf, "fifo", 4)) { + strncpy(priv->cfg_mode, buf, sizeof(priv->cfg_mode) - 1); + priv->cfg_mode[4] = 0; + priv->ops = &fpp_mgr_ft245_fifo_ops; + gpiod_direction_output_raw(priv->conf_done, 0); + } else if (!strncmp(buf, "bitbang", 7)) { + strncpy(priv->cfg_mode, buf, sizeof(priv->cfg_mode) - 1); + priv->cfg_mode[7] = 0; + priv->ops = &fpp_mgr_bitbang_ops; + gpiod_direction_input(priv->conf_done); + } else { + return -EINVAL; + } + + return count; +} + +static DEVICE_ATTR_RW(cfg_mode); + +static int fpp_fpga_mgr_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct fpp_fpga_mgr_priv *priv; + struct fpga_manager *mgr; + struct fifo_fpp_mgr_platform_data *pd; + int ret, retries = MAX_RETRIES; + char id_string[8]; + u8 status = 0; + + pd = dev->platform_data; + if (!pd) { + dev_err(dev, "Missing platform data.\n"); + return -EINVAL; + } + + if (!pd->ops || + !pd->ops->bulk_xfer || !pd->ops->ctrl_xfer || + !pd->ops->read_data || !pd->ops->write_data || + !pd->ops->set_bitmode || !pd->ops->set_baudrate || + !pd->ops->disable_bitbang) + return -EINVAL; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->intf = to_usb_interface(dev->parent); + priv->iops = pd->ops; + + ret = sscanf(dev_name(dev->parent), "%s", priv->usb_dev_id); + if (ret != 1) { + dev_err(dev, "Can't get parent device name: %d\n", ret); + return -ENODEV; + } + + priv->pdev = pdev; + priv->ops = &fpp_mgr_ft245_fifo_ops; + strncpy(priv->cfg_mode, "fifo", sizeof(priv->cfg_mode)); + + priv->nconfig = devm_gpiod_get(dev, "nconfig", GPIOD_OUT_LOW); + if (IS_ERR(priv->nconfig)) { + ret = PTR_ERR(priv->nconfig); + dev_err(dev, "Failed to get nconfig gpio: %d\n", ret); + return ret; + } + + priv->conf_done = devm_gpiod_get(dev, "conf_done", GPIOD_OUT_LOW); + if (IS_ERR(priv->conf_done)) { + ret = PTR_ERR(priv->conf_done); + dev_err(dev, "Failed to get conf_done gpio: %d\n", ret); + goto err_cfg1; + } + + priv->bulk_buf = devm_kmalloc(dev, BULK_OUT_BUF_SZ, + GFP_KERNEL | GFP_DMA32); + if (!priv->bulk_buf) { + ret = -ENOMEM; + goto err_cfg2; + } + + ret = priv->iops->set_bitmode(priv->intf, 0xff, BITMODE_SYNCFF); + if (ret) + goto err_cfg2; + + /* Read status register from CPLD */ + do { + ret = fpp_fpga_mgr_read_status(priv, &status); + if (!ret) + break; + } while (--retries > 0); + + if (!retries) { + ret = -ETIMEDOUT; + goto err_cfg2; + } + + priv->rev = (status & IN_BOARD_REV) ? BOARD_REVB : BOARD_REVA; + + if (priv->rev == BOARD_REVB) { + priv->addr_sel = (status & IN_ADDR_SELECT) ? + ADDR_SELECT_NC : ADDR_SELECT_GND; + if (priv->addr_sel == ADDR_SELECT_NC) + strncpy(id_string, "right", sizeof(id_string)); + else + strncpy(id_string, "left", sizeof(id_string)); + } else { + priv->addr_sel = ADDR_SELECT_INVALID; + strncpy(id_string, "single", sizeof(id_string)); + } + + dev_info(dev, "Board Rev %d, Addr Sel %d\n", priv->rev, priv->addr_sel); + + /* Use unique board ID and USB bus/port in FPGA manager name */ + snprintf(priv->fpga_mgr_name, sizeof(priv->fpga_mgr_name), + "ftdi-fpp-fpga-mgr %s %s", id_string, priv->usb_dev_id); + + mgr = devm_fpga_mgr_create(dev, priv->fpga_mgr_name, + &fpp_fpga_mgr_ops, priv); + if (!mgr) + goto err_cfg2; + + platform_set_drvdata(pdev, mgr); + + ret = fpga_mgr_register(mgr); + if (ret) { + dev_err(dev, "unable to register FPGA manager\n"); + goto err_cfg2; + } + + ret = device_create_file(dev, &dev_attr_cfg_mode); + if (ret) + dev_warn(dev, "Can't create cfg_mode interface %d\n", ret); + + return 0; + +err_cfg2: + devm_gpiod_put(dev, priv->conf_done); +err_cfg1: + devm_gpiod_put(dev, priv->nconfig); + return ret; +} + +static int fpp_fpga_mgr_remove(struct platform_device *pdev) +{ + struct fpga_manager *mgr = platform_get_drvdata(pdev); + struct fpp_fpga_mgr_priv *priv = mgr->priv; + + device_remove_file(&pdev->dev, &dev_attr_cfg_mode); + fpga_mgr_unregister(mgr); + devm_gpiod_put(&pdev->dev, priv->conf_done); + devm_gpiod_put(&pdev->dev, priv->nconfig); + return 0; +} + +static struct platform_driver fpp_fpga_mgr_driver = { + .driver.name = "ftdi-fifo-fpp-mgr", + .probe = fpp_fpga_mgr_probe, + .remove = fpp_fpga_mgr_remove, +}; + +module_platform_driver(fpp_fpga_mgr_driver); + +MODULE_ALIAS("platform:ftdi-fifo-fpp-mgr"); +MODULE_AUTHOR("Anatolij Gustschin "); +MODULE_DESCRIPTION("FT232H Bitbang/FT245-FIFO FPP FPGA Manager Driver"); +MODULE_LICENSE("GPL v2"); -- 2.17.1 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,3/3] fpga: Add fpga manager driver for ARRI Altera FPP From: Anatolij Gustschin Message-Id: <20190221202506.17744-4-agust@denx.de> Date: Thu, 21 Feb 2019 21:25:06 +0100 To: linux-usb@vger.kernel.org, linux-spi@vger.kernel.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: gregkh@linuxfoundation.org, broonie@kernel.org, atull@kernel.org, mdf@kernel.org List-ID: QWRkIEZQR0EgbWFuYWdlciBkcml2ZXIgZm9yIGxvYWRpbmcgQVJSSSBBbHRlcmEgRlBHQXMgdmlh IGZhc3QKcGFzc2l2ZSBwYXJhbGxlbCAoRlBQKSBpbnRlcmZhY2UgdXNpbmcgRlRESSBGVDIzMkgg Y2hpcC4KClNpZ25lZC1vZmYtYnk6IEFuYXRvbGlqIEd1c3RzY2hpbiA8YWd1c3RAZGVueC5kZT4K LS0tCiAuLi4vQUJJL3Rlc3Rpbmcvc3lzZnMtZHJpdmVyLWZ0ZGktZmlmby1mcHAgICAgfCAgIDcg KwogZHJpdmVycy9mcGdhL0tjb25maWcgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICA3ICsK IGRyaXZlcnMvZnBnYS9NYWtlZmlsZSAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgMSArCiBk cml2ZXJzL2ZwZ2EvZnRkaS1maWZvLWZwcC5jICAgICAgICAgICAgICAgICAgfCA1OTQgKysrKysr KysrKysrKysrKysrCiA0IGZpbGVzIGNoYW5nZWQsIDYwOSBpbnNlcnRpb25zKCspCiBjcmVhdGUg bW9kZSAxMDA2NDQgRG9jdW1lbnRhdGlvbi9BQkkvdGVzdGluZy9zeXNmcy1kcml2ZXItZnRkaS1m aWZvLWZwcAogY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvZnBnYS9mdGRpLWZpZm8tZnBwLmMK CmRpZmYgLS1naXQgYS9Eb2N1bWVudGF0aW9uL0FCSS90ZXN0aW5nL3N5c2ZzLWRyaXZlci1mdGRp LWZpZm8tZnBwIGIvRG9jdW1lbnRhdGlvbi9BQkkvdGVzdGluZy9zeXNmcy1kcml2ZXItZnRkaS1m aWZvLWZwcApuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAwMDAwMDAuLmYzMDU1MTAw ZDA3ZQotLS0gL2Rldi9udWxsCisrKyBiL0RvY3VtZW50YXRpb24vQUJJL3Rlc3Rpbmcvc3lzZnMt ZHJpdmVyLWZ0ZGktZmlmby1mcHAKQEAgLTAsMCArMSw3IEBACitXaGF0OgkJL3N5cy9idXMvcGxh dGZvcm0vZGV2aWNlcy9mdGRpLWZpZm8tZnBwLW1nci5OL2NmZ19tb2RlCitEYXRlOgkJRmViIDIw MTkKK0tlcm5lbCBWZXJzaW9uOgk1LjIKK0NvbnRhY3Q6CUFuYXRvbGlqIEd1c3RzY2hpbiA8YWd1 c3RAZGVueC5kZT4KK0Rlc2NyaXB0aW9uOgorCQlDb250YWlucyBlaXRoZXIgImZpZm8iIG9yICJi aXRiYW5nIiBhbmQgY29udHJvbHMgaWYgZmlmbworCQlvZiBiaXRiYW5nIGNvbmZpZ3VyYXRpb24g bW9kZSBpcyB1c2VkIGluIHRoZSBkcml2ZXIuCmRpZmYgLS1naXQgYS9kcml2ZXJzL2ZwZ2EvS2Nv bmZpZyBiL2RyaXZlcnMvZnBnYS9LY29uZmlnCmluZGV4IGMyMDQ0NWI4NjdhZS4uMTlkODIxNjNh MGIyIDEwMDY0NAotLS0gYS9kcml2ZXJzL2ZwZ2EvS2NvbmZpZworKysgYi9kcml2ZXJzL2ZwZ2Ev S2NvbmZpZwpAQCAtNTAsNiArNTAsMTMgQEAgY29uZmlnIEZQR0FfTUdSX0FMVEVSQV9DVlAKIAkg IEZQR0EgbWFuYWdlciBkcml2ZXIgc3VwcG9ydCBmb3IgQXJyaWEtViwgQ3ljbG9uZS1WLCBTdHJh dGl4LVYKIAkgIGFuZCBBcnJpYSAxMCBBbHRlcmEgRlBHQXMgdXNpbmcgdGhlIEN2UCBpbnRlcmZh Y2Ugb3ZlciBQQ0llLgogCitjb25maWcgRlBHQV9NR1JfRlRESV9GSUZPX0ZQUAorCXRyaXN0YXRl ICJBbHRlcmEgRlBQIG92ZXIgRlQyMzJIIEZJRk8iCisJZGVwZW5kcyBvbiBVU0JfRlQyMzJIX0lO VEYKKwloZWxwCisJICBGUEdBIG1hbmFnZXIgZHJpdmVyIHN1cHBvcnQgZm9yIEFsdGVyYSBmYXN0 IHBhc3NpdmUgcGFyYWxsZWwKKwkgIGludGVyZmFjZSAoRlBQKSBvdmVyIEZUMjMySCBGVDI0NSBG SUZPLgorCiBjb25maWcgRlBHQV9NR1JfWllOUV9GUEdBCiAJdHJpc3RhdGUgIlhpbGlueCBaeW5x IEZQR0EiCiAJZGVwZW5kcyBvbiBBUkNIX1pZTlEgfHwgQ09NUElMRV9URVNUCmRpZmYgLS1naXQg YS9kcml2ZXJzL2ZwZ2EvTWFrZWZpbGUgYi9kcml2ZXJzL2ZwZ2EvTWFrZWZpbGUKaW5kZXggYzBk ZDRjODJmYmRiLi42MTcyNWQzMWU2ZDEgMTAwNjQ0Ci0tLSBhL2RyaXZlcnMvZnBnYS9NYWtlZmls ZQorKysgYi9kcml2ZXJzL2ZwZ2EvTWFrZWZpbGUKQEAgLTksNiArOSw3IEBAIG9iai0kKENPTkZJ R19GUEdBKQkJCSs9IGZwZ2EtbWdyLm8KICMgRlBHQSBNYW5hZ2VyIERyaXZlcnMKIG9iai0kKENP TkZJR19GUEdBX01HUl9BTFRFUkFfQ1ZQKQkrPSBhbHRlcmEtY3ZwLm8KIG9iai0kKENPTkZJR19G UEdBX01HUl9BTFRFUkFfUFNfU1BJKQkrPSBhbHRlcmEtcHMtc3BpLm8KK29iai0kKENPTkZJR19G UEdBX01HUl9GVERJX0ZJRk9fRlBQKQkrPSBmdGRpLWZpZm8tZnBwLm8KIG9iai0kKENPTkZJR19G UEdBX01HUl9JQ0U0MF9TUEkpCSs9IGljZTQwLXNwaS5vCiBvYmotJChDT05GSUdfRlBHQV9NR1Jf TUFDSFhPMl9TUEkpCSs9IG1hY2h4bzItc3BpLm8KIG9iai0kKENPTkZJR19GUEdBX01HUl9TT0NG UEdBKQkJKz0gc29jZnBnYS5vCmRpZmYgLS1naXQgYS9kcml2ZXJzL2ZwZ2EvZnRkaS1maWZvLWZw cC5jIGIvZHJpdmVycy9mcGdhL2Z0ZGktZmlmby1mcHAuYwpuZXcgZmlsZSBtb2RlIDEwMDY0NApp bmRleCAwMDAwMDAwMDAwMDAuLjJiYzcyMzM1Y2Q3MAotLS0gL2Rldi9udWxsCisrKyBiL2RyaXZl cnMvZnBnYS9mdGRpLWZpZm8tZnBwLmMKQEAgLTAsMCArMSw1OTQgQEAKKy8vIFNQRFgtTGljZW5z ZS1JZGVudGlmaWVyOiBHUEwtMi4wCisvKgorICogQWx0ZXJhIEZQR0EgZmlybXdhcmUgdXBsb2Fk IHZpYSBGUFAgdXNpbmcgRlQyMzJIIEJpdGJhbmcvRlQyNDUtRklGTy4KKyAqCisgKiBDb3B5cmln aHQgKEMpIDIwMTcgLSAyMDE4IERFTlggU29mdHdhcmUgRW5naW5lZXJpbmcKKyAqIEFuYXRvbGlq IEd1c3RzY2hpbiA8YWd1c3RAZGVueC5kZT4KKyAqLworCisjaW5jbHVkZSA8bGludXgvYml0b3Bz Lmg+CisjaW5jbHVkZSA8bGludXgvZGVsYXkuaD4KKyNpbmNsdWRlIDxsaW51eC9mcGdhL2ZwZ2Et bWdyLmg+CisjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+CisjaW5jbHVkZSA8bGludXgva2VybmVs Lmg+CisjaW5jbHVkZSA8bGludXgvc2l6ZXMuaD4KKyNpbmNsdWRlIDxsaW51eC9zbGFiLmg+Cisj aW5jbHVkZSA8bGludXgvZ3Bpby9jb25zdW1lci5oPgorI2luY2x1ZGUgPGxpbnV4L3BsYXRmb3Jt X2RldmljZS5oPgorI2luY2x1ZGUgPGxpbnV4L3VzYi5oPgorI2luY2x1ZGUgPGxpbnV4L3VzYi9m dDIzMmgtaW50Zi5oPgorCisjZGVmaW5lIEJVTEtfT1VUX0JVRl9TWglTWl8xTQorI2RlZmluZSBN QVhfUkVUUklFUwkxMAorCisvKgorICogV2l0aCBsb2dpYyBvZiBDUExEIHdlIGNhbiB3cml0ZSB0 aGUgc3RhdGUgb2YgbkNvbmZpZyBwaW4gYW5kCisgKiByZWFkIGJhY2sgdGhlIHN0YXRlIG9mIHNv bWUgcGlucyAoY29uZl9kb25lLCBpbml0X2RvbmUsIG5TdGF0dXMpLgorICogU3RhdHVzIGhlYWRl ciBhbmQgYml0IGFzc2lnbm1lbnQgaW4gZGF0YSByZWdpc3RlciBvbiBDUExELgorICovCisjZGVm aW5lIElOUFVUX0hFQURFUl8wCTB4QTUKKyNkZWZpbmUgSU5QVVRfSEVBREVSXzEJMHg1QQorI2Rl ZmluZSBJTl9DT05GX0RPTkUJQklUKDApCisjZGVmaW5lIElOX0lOSVRfRE9ORQlCSVQoMSkKKyNk ZWZpbmUgSU5fQUREUl9TRUxFQ1QJQklUKDQpCisjZGVmaW5lIElOX0JPQVJEX1JFVglCSVQoNSkK KyNkZWZpbmUgT1VUX05DT05GSUcJQklUKDApCisjZGVmaW5lIE9VVF9SRVNFVF9OCUJJVCgxKQor CitlbnVtIGZwcF9ib2FyZF9yZXYgeworCUJPQVJEX1JFVkEgPSAxLAorCUJPQVJEX1JFVkIgPSAy LAorfTsKKworZW51bSBmcHBfYWRkcl9zZWwgeworCUFERFJfU0VMRUNUX0lOVkFMSUQsCisJQURE Ul9TRUxFQ1RfR05ELAorCUFERFJfU0VMRUNUX05DCit9OworCitzdHJ1Y3QgZnBwX21ncl9vcHMg eworCWludCAoKndyaXRlX2luaXQpKHN0cnVjdCBmcGdhX21hbmFnZXIgKm1nciwKKwkJCSAgc3Ry dWN0IGZwZ2FfaW1hZ2VfaW5mbyAqaW5mbywKKwkJCSAgY29uc3QgY2hhciAqYnVmLCBzaXplX3Qg Y291bnQpOworCWludCAoKndyaXRlKShzdHJ1Y3QgZnBnYV9tYW5hZ2VyICptZ3IsIGNvbnN0IGNo YXIgKmJ1Ziwgc2l6ZV90IGNvdW50KTsKKwlpbnQgKCp3cml0ZV9jb21wbGV0ZSkoc3RydWN0IGZw Z2FfbWFuYWdlciAqbWdyLAorCQkJICAgICAgc3RydWN0IGZwZ2FfaW1hZ2VfaW5mbyAqaW5mbyk7 Cit9OworCitzdHJ1Y3QgZnBwX2ZwZ2FfbWdyX3ByaXYgeworCXN0cnVjdCBwbGF0Zm9ybV9kZXZp Y2UJCSpwZGV2OworCXN0cnVjdCB1c2JfaW50ZXJmYWNlCQkqaW50ZjsKKwljb25zdCBzdHJ1Y3Qg ZnQyMzJoX2ludGZfb3BzCSppb3BzOworCXN0cnVjdCBmcGdhX21hbmFnZXIJKm1ncjsKKwlzdHJ1 Y3QgZnBwX21ncl9vcHMJKm9wczsKKwlzdHJ1Y3QgZ3Bpb19kZXNjCSpuY29uZmlnOworCXN0cnVj dCBncGlvX2Rlc2MJKmNvbmZfZG9uZTsKKwljaGFyCQkJY2ZnX21vZGVbOF07CisJdTgJCQlvdXRf ZGF0YV9wb3J0OworCWludAkJCWluZGV4OworCXZvaWQJCQkqYnVsa19idWY7CisJY2hhcgkJCXVz Yl9kZXZfaWRbMzJdOworCWNoYXIJCQlmcGdhX21ncl9uYW1lWzY0XTsKKwllbnVtIGZwcF9ib2Fy ZF9yZXYJcmV2OworCWVudW0gZnBwX2FkZHJfc2VsCWFkZHJfc2VsOworfTsKKworc3RhdGljIGlu dCBmcHBfZnBnYV9tZ3Jfc2V0X2RhdGFfcG9ydChzdHJ1Y3QgZnBwX2ZwZ2FfbWdyX3ByaXYgKnBy aXYsCisJCQkJICAgICAgdTggYml0bWFzaywgdTggdmFsdWUpCit7CisJc3RydWN0IGRldmljZSAq ZGV2ID0gJnByaXYtPnBkZXYtPmRldjsKKwlzdHJ1Y3QgYnVsa19kZXNjIGRlc2M7CisJdTggKmRh dGE7CisJaW50IHJldDsKKworCS8qCisJICogV2l0aCBDUExEIGNvbm5lY3RlZCAoaW4gRlQyNDUg RklGTyBtb2RlKSB3ZSB1c2UgQUNCVVM4JjkKKwkgKiBwaW5zIHRvIHN3aXRjaCBiZXR3ZWVuIGRh dGEgYW5kIGNvbW1hbmQgbW9kZToKKwkgKiBBQ0JVUzgmOSA9PSAwLCAwICAtLT4gbm9ybWFsIG1v ZGUgKGRhdGEgY29tbXVuaWNhdGlvbikKKwkgKiBBQ0JVUzgmOSA9PSAxLCAwICAtLT4gY29tbWFu ZCBtb2RlCisJICovCisJZ3Bpb2Rfc2V0X3Jhd192YWx1ZV9jYW5zbGVlcChwcml2LT5uY29uZmln LCAxKTsKKwlncGlvZF9zZXRfcmF3X3ZhbHVlX2NhbnNsZWVwKHByaXYtPmNvbmZfZG9uZSwgMCk7 CisJbXNsZWVwKDUwKTsKKworCS8qIFdyaXRlIGNvbW1hbmRzIHRvIENQTEQgKi8KKwlyZXQgPSBw cml2LT5pb3BzLT5zZXRfYml0bW9kZShwcml2LT5pbnRmLCAweDAwLCBCSVRNT0RFX1NZTkNGRik7 CisJaWYgKHJldCkKKwkJcmV0dXJuIHJldDsKKworCWlmICh2YWx1ZSkKKwkJcHJpdi0+b3V0X2Rh dGFfcG9ydCB8PSBiaXRtYXNrOworCWVsc2UKKwkJcHJpdi0+b3V0X2RhdGFfcG9ydCAmPSB+Yml0 bWFzazsKKworCWRhdGEgPSBwcml2LT5idWxrX2J1ZjsKKwkqZGF0YSA9IHByaXYtPm91dF9kYXRh X3BvcnQ7CisKKwlkZXNjLmRpcl9vdXQgPSB0cnVlOworCWRlc2MuYWN0X2xlbiA9IDA7CisJZGVz Yy5sZW4gPSAxOworCWRlc2MuZGF0YSA9IGRhdGE7CisJZGVzYy50aW1lb3V0ID0gRlRESV9VU0Jf V1JJVEVfVElNRU9VVDsKKworCXJldCA9IHByaXYtPmlvcHMtPmJ1bGtfeGZlcihwcml2LT5pbnRm LCAmZGVzYyk7CisJaWYgKHJldCkgeworCQlkZXZfZXJyKGRldiwgIldyaXRpbmcgaW4gU1lOQ0ZG IG1vZGUgZmFpbGVkOiAlZFxuIiwgcmV0KTsKKwkJcmV0dXJuIHJldDsKKwl9CisKKwltc2xlZXAo NTApOworCS8qIFN3aXRjaCBiYWNrIHRvIGRhdGEgbW9kZSB3aXRoIEFDQlVTOCY5IGJhY2sgdG8g bG93ICovCisJZ3Bpb2Rfc2V0X3Jhd192YWx1ZV9jYW5zbGVlcChwcml2LT5uY29uZmlnLCAwKTsK KwlncGlvZF9zZXRfcmF3X3ZhbHVlX2NhbnNsZWVwKHByaXYtPmNvbmZfZG9uZSwgMCk7CisJbXNs ZWVwKDUwKTsKKworCXJldHVybiAwOworfQorCitzdGF0aWMgaW50IGZwcF9mcGdhX21ncl9iaXRi YW5nX3dyaXRlX2luaXQoc3RydWN0IGZwZ2FfbWFuYWdlciAqbWdyLAorCQkJCQkgICBzdHJ1Y3Qg ZnBnYV9pbWFnZV9pbmZvICppbmZvLAorCQkJCQkgICBjb25zdCBjaGFyICpidWYsIHNpemVfdCBj b3VudCkKK3sKKwlzdHJ1Y3QgZnBwX2ZwZ2FfbWdyX3ByaXYgKnByaXYgPSBtZ3ItPnByaXY7CisJ c3RydWN0IGRldmljZSAqZGV2ID0gJnByaXYtPnBkZXYtPmRldjsKKwlpbnQgcmV0cmllcyA9IE1B WF9SRVRSSUVTOworCWludCByZXQ7CisKKwlncGlvZF9zZXRfdmFsdWVfY2Fuc2xlZXAocHJpdi0+ bmNvbmZpZywgMCk7CisJbXNsZWVwKDUwKTsKKwlncGlvZF9zZXRfdmFsdWVfY2Fuc2xlZXAocHJp di0+bmNvbmZpZywgMSk7CisJbXNsZWVwKDUwKTsKKwlncGlvZF9zZXRfdmFsdWVfY2Fuc2xlZXAo cHJpdi0+bmNvbmZpZywgMCk7CisKKwkvKiBXYWl0IGZvciBDT05GX0RPTkUgdG8gZ2V0IGxvdyAq LworCWRvIHsKKwkJbXNsZWVwKDUwKTsKKworCQlyZXQgPSBncGlvZF9nZXRfdmFsdWVfY2Fuc2xl ZXAocHJpdi0+Y29uZl9kb25lKTsKKwkJaWYgKHJldCA8IDApIHsKKwkJCWRldl9lcnIoZGV2LCAi RmFpbGVkIHRvIGdldCBDT05GX0RPTkUgcGluOiAlZFxuIiwgcmV0KTsKKwkJCXJldHVybiByZXQ7 CisJCX0KKworCQlpZiAoIXJldCkKKwkJCWJyZWFrOworCX0gd2hpbGUgKC0tcmV0cmllcyA+IDAp OworCisJaWYgKCFyZXRyaWVzKSB7CisJCWRldl93YXJuKGRldiwgIkNPTkZfRE9ORSBsb3cgd2Fp dCB0aW1lb3V0XG4iKTsKKwkJcmV0dXJuIC1FVElNRURPVVQ7CisJfQorCisJcmV0ID0gcHJpdi0+ aW9wcy0+c2V0X2JpdG1vZGUocHJpdi0+aW50ZiwgMHhmZiwgQklUTU9ERV9CSVRCQU5HKTsKKwlp ZiAocmV0IDwgMCkKKwkJcmV0dXJuIHJldDsKKworCS8qIFNldCBtYXguIHdvcmtpbmcgYmF1ZCBy YXRlIChmb3IgaGFyZHdhcmUgd2l0aG91dCBDUExEKSAqLworCXJldHVybiBwcml2LT5pb3BzLT5z ZXRfYmF1ZHJhdGUocHJpdi0+aW50ZiwgNzAwMDAwKTsKK30KKworc3RhdGljIGludCBmcHBfZnBn YV9tZ3JfYml0YmFuZ193cml0ZShzdHJ1Y3QgZnBnYV9tYW5hZ2VyICptZ3IsCisJCQkJICAgICAg Y29uc3QgY2hhciAqYnVmLCBzaXplX3QgY291bnQpCit7CisJc3RydWN0IGZwcF9mcGdhX21ncl9w cml2ICpwcml2ID0gbWdyLT5wcml2OworCXN0cnVjdCBidWxrX2Rlc2MgZGVzYzsKKwlzaXplX3Qg YmxrX3N6OworCWludCByZXQ7CisKKwlkZXNjLmRhdGEgPSBwcml2LT5idWxrX2J1ZjsKKwlkZXNj LmRpcl9vdXQgPSB0cnVlOworCWRlc2MudGltZW91dCA9IEZURElfVVNCX1dSSVRFX1RJTUVPVVQ7 CisKKwl3aGlsZSAoY291bnQpIHsKKwkJYmxrX3N6ID0gbWluX3Qoc2l6ZV90LCBjb3VudCwgQlVM S19PVVRfQlVGX1NaKTsKKwkJbWVtY3B5KHByaXYtPmJ1bGtfYnVmLCBidWYsIGJsa19zeik7CisJ CWRlc2MuYWN0X2xlbiA9IDA7CisJCWRlc2MubGVuID0gYmxrX3N6OworCQlyZXQgPSBwcml2LT5p b3BzLT5idWxrX3hmZXIocHJpdi0+aW50ZiwgJmRlc2MpOworCQlpZiAocmV0IDwgMCkKKwkJCXJl dHVybiByZXQ7CisKKwkJYnVmICs9IGRlc2MuYWN0X2xlbjsKKwkJY291bnQgLT0gZGVzYy5hY3Rf bGVuOworCX0KKworCXJldHVybiAwOworfQorCitzdGF0aWMgaW50IGZwcF9mcGdhX21ncl9iaXRi YW5nX3dyaXRlX2NvbXBsZXRlKHN0cnVjdCBmcGdhX21hbmFnZXIgKm1nciwKKwkJCQkJICAgICAg IHN0cnVjdCBmcGdhX2ltYWdlX2luZm8gKmluZm8pCit7CisJc3RydWN0IGZwcF9mcGdhX21ncl9w cml2ICpwcml2ID0gbWdyLT5wcml2OworCXN0cnVjdCBkZXZpY2UgKmRldiA9ICZwcml2LT5wZGV2 LT5kZXY7CisJaW50IHJldHJpZXMgPSBNQVhfUkVUUklFUzsKKwlpbnQgcmV0OworCisJLyogV2Fp dCBmb3IgQ09ORl9ET05FIHRvIGdldCBoaWdoICovCisJZG8geworCQltc2xlZXAoNTApOworCisJ CXJldCA9IGdwaW9kX2dldF92YWx1ZV9jYW5zbGVlcChwcml2LT5jb25mX2RvbmUpOworCQlpZiAo cmV0IDwgMCkKKwkJCXJldHVybiByZXQ7CisKKwkJaWYgKHJldCkKKwkJCWJyZWFrOworCX0gd2hp bGUgKC0tcmV0cmllcyA+IDApOworCisJaWYgKCFyZXRyaWVzKSB7CisJCWRldl93YXJuKGRldiwg IkNPTkZfRE9ORSB3YWl0IHRpbWVvdXRcbiIpOworCQlyZXR1cm4gLUVUSU1FRE9VVDsKKwl9CisK Kwlwcml2LT5pb3BzLT5kaXNhYmxlX2JpdGJhbmcocHJpdi0+aW50Zik7CisJcmV0dXJuIDA7Cit9 CisKK3N0YXRpYyBpbmxpbmUgYm9vbCBzdGF0dXNfaGRyX2lzX3ZhbGlkKHU4ICpidWYpCit7CisJ cmV0dXJuIGJ1ZlswXSA9PSBJTlBVVF9IRUFERVJfMCAmJiBidWZbMV0gPT0gSU5QVVRfSEVBREVS XzE7Cit9CisKK3N0YXRpYyBpbnQgZnBwX2ZwZ2FfbWdyX3JlYWRfc3RhdHVzKHN0cnVjdCBmcHBf ZnBnYV9tZ3JfcHJpdiAqcHJpdiwgdTggKnN0YXR1cykKK3sKKwlzdHJ1Y3QgZGV2aWNlICpkZXYg PSAmcHJpdi0+cGRldi0+ZGV2OworCXU4ICppbmJ1ZiA9IHByaXYtPmJ1bGtfYnVmOworCWludCBy ZXRyaWVzID0gTUFYX1JFVFJJRVM7CisJaW50IHJldDsKKworCWlmICghc3RhdHVzKQorCQlyZXR1 cm4gLUVJTlZBTDsKKworCS8qIFdhaXQgdW50aWwgQ1BMRCBzZW5kcyB2YWxpZCBoZWFkZXIgYW5k IHN0YXR1cyByZWdpc3RlciAqLworCWRvIHsKKwkJcmV0ID0gcHJpdi0+aW9wcy0+cmVhZF9kYXRh KHByaXYtPmludGYsIGluYnVmLCA2NCk7CisJCWlmIChyZXQgPCAwKSB7CisJCQlkZXZfZXJyKGRl diwgIkNhbid0IHJlYWQgc3RhdHVzIGRhdGE6ICVkXG4iLCByZXQpOworCQkJcmV0dXJuIHJldDsK KwkJfQorCisJCS8qIENoZWNrIGlucHV0IGJ1ZmZlciBoZWFkZXIgKi8KKwkJaWYgKHJldCA+PSA0 ICYmIHN0YXR1c19oZHJfaXNfdmFsaWQoaW5idWYpKSB7CisJCQkqc3RhdHVzID0gaW5idWZbMl07 CisJCQlyZXR1cm4gMDsKKwkJfQorCisJCS8qIFdhaXQgYW5kIHJlYWQgYmFjayBzdGF0dXMgYWdh aW4gKi8KKwkJbXNsZWVwKDEwMCk7IC8qIENQTEQgc2VuZHMgc3RhdHVzIGV2ZXJ5IDEwMG1zICov CisJfSB3aGlsZSAoLS1yZXRyaWVzID4gMCk7CisKKwlkZXZfd2FybihkZXYsICJUaW1lb3V0IHdo ZW4gcmVhZGluZyBzdGF0dXNcbiIpOworCXJldHVybiAtRVRJTUVET1VUOworfQorCitzdGF0aWMg aW50IGZwcF9mcGdhX21ncl9mdDI0NV9maWZvX3dyaXRlX2luaXQoc3RydWN0IGZwZ2FfbWFuYWdl ciAqbWdyLAorCQkJCQkgICAgICBzdHJ1Y3QgZnBnYV9pbWFnZV9pbmZvICppbmZvLAorCQkJCQkg ICAgICBjb25zdCBjaGFyICpidWYsIHNpemVfdCBjb3VudCkKK3sKKwlzdHJ1Y3QgZnBwX2ZwZ2Ff bWdyX3ByaXYgKnByaXYgPSBtZ3ItPnByaXY7CisJc3RydWN0IGRldmljZSAqZGV2ID0gJnByaXYt PnBkZXYtPmRldjsKKwlpbnQgcmV0cmllcyA9IE1BWF9SRVRSSUVTOworCWludCByZXQ7CisJdTgg c3RhdHVzOworCisJZ3Bpb2RfZGlyZWN0aW9uX291dHB1dF9yYXcocHJpdi0+Y29uZl9kb25lLCAw KTsKKworCS8qIFNldC9yZXNldCBuQ29uZmlnIHZpYSBjb21tYW5kcyB0byBDUExEICovCisJcmV0 ID0gZnBwX2ZwZ2FfbWdyX3NldF9kYXRhX3BvcnQocHJpdiwgT1VUX05DT05GSUcsIDEpOworCWlm IChyZXQpCisJCXJldHVybiByZXQ7CisJcmV0ID0gZnBwX2ZwZ2FfbWdyX3NldF9kYXRhX3BvcnQo cHJpdiwgT1VUX05DT05GSUcsIDApOworCWlmIChyZXQpCisJCXJldHVybiByZXQ7CisJcmV0ID0g ZnBwX2ZwZ2FfbWdyX3NldF9kYXRhX3BvcnQocHJpdiwgT1VUX05DT05GSUcsIDEpOworCWlmIChy ZXQpCisJCXJldHVybiByZXQ7CisKKwkvKiBJbiBGVDI0NSBGSUZPIG1vZGUgd2UgbmVlZCBzeW5j IEZJRk8gbW9kZSB0byB0YWxrIHRvIEZQR0EgKi8KKwlyZXQgPSBwcml2LT5pb3BzLT5zZXRfYml0 bW9kZShwcml2LT5pbnRmLCAweGZmLCBCSVRNT0RFX1NZTkNGRik7CisJaWYgKHJldCkKKwkJcmV0 dXJuIHJldDsKKworCS8qIFdhaXQgdW50aWwgRlBHQSBpcyByZWFkeSBmb3IgbG9hZGluZyAoY29u Zl9kb25lIHplcm8pIG9yIHRpbWVvdXQgKi8KKwlkbyB7CisJCXJldCA9IGZwcF9mcGdhX21ncl9y ZWFkX3N0YXR1cyhwcml2LCAmc3RhdHVzKTsKKwkJaWYgKCFyZXQpIHsKKwkJCS8qIENoZWNrIGNv bmZfZG9uZSBzdGF0dXMgKi8KKwkJCWlmICgoc3RhdHVzICYgSU5fQ09ORl9ET05FKSA9PSAwKQor CQkJCWJyZWFrOworCQl9CisJfSB3aGlsZSAoLS1yZXRyaWVzID4gMCk7CisKKwlpZiAoIXJldHJp ZXMpIHsKKwkJZGV2X3dhcm4oZGV2LCAiQ09ORl9ET05FIHdhaXQgdGltZW91dFxuIik7CisJCXJl dHVybiAtRVRJTUVET1VUOworCX0KKworCS8qIENvbmZpZ3VyZSBmb3IgbWF4LiBiYXVkIHJhdGUg KDNNSHogKiA0IGluIGJpdGJhbmcgbW9kZSkgKi8KKwlyZXR1cm4gcHJpdi0+aW9wcy0+c2V0X2Jh dWRyYXRlKHByaXYtPmludGYsIDMwMDAwMDApOworfQorCitzdGF0aWMgaW50IGZwcF9mcGdhX21n cl9mdDI0NV9maWZvX3dyaXRlKHN0cnVjdCBmcGdhX21hbmFnZXIgKm1nciwKKwkJCQkJIGNvbnN0 IGNoYXIgKmJ1Ziwgc2l6ZV90IGNvdW50KQoreworCXJldHVybiBmcHBfZnBnYV9tZ3JfYml0YmFu Z193cml0ZShtZ3IsIGJ1ZiwgY291bnQpOworfQorCitzdGF0aWMgaW50IGZwcF9mcGdhX21ncl9m dDI0NV9maWZvX3dyaXRlX2NvbXBsZXRlKHN0cnVjdCBmcGdhX21hbmFnZXIgKm1nciwKKwkJCQkJ CSAgc3RydWN0IGZwZ2FfaW1hZ2VfaW5mbyAqaW5mbykKK3sKKwlzdHJ1Y3QgZnBwX2ZwZ2FfbWdy X3ByaXYgKnByaXYgPSBtZ3ItPnByaXY7CisJc3RydWN0IGRldmljZSAqZGV2ID0gJnByaXYtPnBk ZXYtPmRldjsKKwlpbnQgcmV0cmllcyA9IE1BWF9SRVRSSUVTOworCWludCByZXQ7CisJdTggbWFz aywgc3RhdHVzOworCisJbWFzayA9IElOX0NPTkZfRE9ORSB8IElOX0lOSVRfRE9ORTsKKworCWRv IHsKKwkJcmV0ID0gZnBwX2ZwZ2FfbWdyX3JlYWRfc3RhdHVzKHByaXYsICZzdGF0dXMpOworCQlp ZiAoIXJldCkgeworCQkJLyogQ2hlY2sgY29uZl9kb25lL2luaXRfZG9uZSBzdGF0dXMgKi8KKwkJ CWlmICgoc3RhdHVzICYgbWFzaykgPT0gbWFzaykKKwkJCQlicmVhazsKKwkJfQorCX0gd2hpbGUg KC0tcmV0cmllcyA+IDApOworCisJaWYgKCFyZXRyaWVzKSB7CisJCWRldl93YXJuKGRldiwgIklO SVRfRE9ORSB3YWl0IHRpbWVvdXRcbiIpOworCQlyZXR1cm4gLUVUSU1FRE9VVDsKKwl9CisKKwkv KiBSZWxlYXNlIFJlc2V0X24sIGtlZXAgbkNPTkZJRyBoaWdoLCB0b28hICovCisJcmV0dXJuIGZw cF9mcGdhX21ncl9zZXRfZGF0YV9wb3J0KHByaXYsIE9VVF9OQ09ORklHIHwgT1VUX1JFU0VUX04s IDEpOworfQorCitzdGF0aWMgZW51bSBmcGdhX21ncl9zdGF0ZXMgZnBwX2ZwZ2FfbWdyX3N0YXRl KHN0cnVjdCBmcGdhX21hbmFnZXIgKm1ncikKK3sKKwlyZXR1cm4gRlBHQV9NR1JfU1RBVEVfVU5L Tk9XTjsKK30KKworc3RhdGljIGludCBmcHBfZnBnYV9tZ3Jfd3JpdGVfaW5pdChzdHJ1Y3QgZnBn YV9tYW5hZ2VyICptZ3IsCisJCQkJICAgc3RydWN0IGZwZ2FfaW1hZ2VfaW5mbyAqaW5mbywKKwkJ CQkgICBjb25zdCBjaGFyICpidWYsIHNpemVfdCBjb3VudCkKK3sKKwlzdHJ1Y3QgZnBwX2ZwZ2Ff bWdyX3ByaXYgKnByaXYgPSBtZ3ItPnByaXY7CisKKwlpZiAoaW5mbyAmJiBpbmZvLT5mbGFncyAm IEZQR0FfTUdSX1BBUlRJQUxfUkVDT05GSUcpIHsKKwkJZGV2X2VycigmbWdyLT5kZXYsICJQYXJ0 aWFsIHJlY29uZmlndXJhdGlvbiBub3Qgc3VwcG9ydGVkLlxuIik7CisJCXJldHVybiAtRUlOVkFM OworCX0KKworCWlmIChwcml2LT5vcHMtPndyaXRlX2luaXQpCisJCXJldHVybiBwcml2LT5vcHMt PndyaXRlX2luaXQobWdyLCBpbmZvLCBidWYsIGNvdW50KTsKKworCXJldHVybiAtRU5PREVWOwor fQorCitzdGF0aWMgaW50IGZwcF9mcGdhX21ncl93cml0ZShzdHJ1Y3QgZnBnYV9tYW5hZ2VyICpt Z3IsIGNvbnN0IGNoYXIgKmJ1ZiwKKwkJCSAgICAgIHNpemVfdCBjb3VudCkKK3sKKwlzdHJ1Y3Qg ZnBwX2ZwZ2FfbWdyX3ByaXYgKnByaXYgPSBtZ3ItPnByaXY7CisKKwlpZiAocHJpdi0+b3BzLT53 cml0ZSkKKwkJcmV0dXJuIHByaXYtPm9wcy0+d3JpdGUobWdyLCBidWYsIGNvdW50KTsKKworCXJl dHVybiAtRU5PREVWOworfQorCitzdGF0aWMgaW50IGZwcF9mcGdhX21ncl93cml0ZV9jb21wbGV0 ZShzdHJ1Y3QgZnBnYV9tYW5hZ2VyICptZ3IsCisJCQkJICAgICAgIHN0cnVjdCBmcGdhX2ltYWdl X2luZm8gKmluZm8pCit7CisJc3RydWN0IGZwcF9mcGdhX21ncl9wcml2ICpwcml2ID0gbWdyLT5w cml2OworCisJaWYgKHByaXYtPm9wcy0+d3JpdGVfY29tcGxldGUpCisJCXJldHVybiBwcml2LT5v cHMtPndyaXRlX2NvbXBsZXRlKG1nciwgaW5mbyk7CisKKwlyZXR1cm4gLUVOT0RFVjsKK30KKwor c3RhdGljIHN0cnVjdCBmcHBfbWdyX29wcyBmcHBfbWdyX2JpdGJhbmdfb3BzID0geworCS53cml0 ZV9pbml0CT0gZnBwX2ZwZ2FfbWdyX2JpdGJhbmdfd3JpdGVfaW5pdCwKKwkud3JpdGUJCT0gZnBw X2ZwZ2FfbWdyX2JpdGJhbmdfd3JpdGUsCisJLndyaXRlX2NvbXBsZXRlCT0gZnBwX2ZwZ2FfbWdy X2JpdGJhbmdfd3JpdGVfY29tcGxldGUsCit9OworCitzdGF0aWMgc3RydWN0IGZwcF9tZ3Jfb3Bz IGZwcF9tZ3JfZnQyNDVfZmlmb19vcHMgPSB7CisJLndyaXRlX2luaXQJPSBmcHBfZnBnYV9tZ3Jf ZnQyNDVfZmlmb193cml0ZV9pbml0LAorCS53cml0ZQkJPSBmcHBfZnBnYV9tZ3JfZnQyNDVfZmlm b193cml0ZSwKKwkud3JpdGVfY29tcGxldGUJPSBmcHBfZnBnYV9tZ3JfZnQyNDVfZmlmb193cml0 ZV9jb21wbGV0ZSwKK307CisKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgZnBnYV9tYW5hZ2VyX29wcyBm cHBfZnBnYV9tZ3Jfb3BzID0geworCS5zdGF0ZQkJPSBmcHBfZnBnYV9tZ3Jfc3RhdGUsCisJLndy aXRlX2luaXQJPSBmcHBfZnBnYV9tZ3Jfd3JpdGVfaW5pdCwKKwkud3JpdGUJCT0gZnBwX2ZwZ2Ff bWdyX3dyaXRlLAorCS53cml0ZV9jb21wbGV0ZQk9IGZwcF9mcGdhX21ncl93cml0ZV9jb21wbGV0 ZSwKK307CisKK3N0YXRpYyBzc2l6ZV90IGNmZ19tb2RlX3Nob3coc3RydWN0IGRldmljZSAqZGV2 LCBzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwKKwkJCSAgICAgY2hhciAqYnVmKQorewor CXN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYgPSB0b19wbGF0Zm9ybV9kZXZpY2UoZGV2KTsK KwlzdHJ1Y3QgZnBnYV9tYW5hZ2VyICptZ3IgPSBwbGF0Zm9ybV9nZXRfZHJ2ZGF0YShwZGV2KTsK KwlzdHJ1Y3QgZnBwX2ZwZ2FfbWdyX3ByaXYgKnByaXYgPSBtZ3ItPnByaXY7CisKKwlyZXR1cm4g c25wcmludGYoYnVmLCBQQUdFX1NJWkUsICIlc1xuIiwgcHJpdi0+Y2ZnX21vZGUpOworfQorCitz dGF0aWMgc3NpemVfdCBjZmdfbW9kZV9zdG9yZShzdHJ1Y3QgZGV2aWNlICpkZXYsIHN0cnVjdCBk ZXZpY2VfYXR0cmlidXRlICphdHRyLAorCQkJICAgICAgY29uc3QgY2hhciAqYnVmLCBzaXplX3Qg Y291bnQpCit7CisJc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldiA9IHRvX3BsYXRmb3JtX2Rl dmljZShkZXYpOworCXN0cnVjdCBmcGdhX21hbmFnZXIgKm1nciA9IHBsYXRmb3JtX2dldF9kcnZk YXRhKHBkZXYpOworCXN0cnVjdCBmcHBfZnBnYV9tZ3JfcHJpdiAqcHJpdiA9IG1nci0+cHJpdjsK KworCWlmICghY291bnQgfHwgY291bnQgPiBzaXplb2YocHJpdi0+Y2ZnX21vZGUpKQorCQlyZXR1 cm4gLUVJTlZBTDsKKworCWlmICghc3RybmNtcChidWYsICJmaWZvIiwgNCkpIHsKKwkJc3RybmNw eShwcml2LT5jZmdfbW9kZSwgYnVmLCBzaXplb2YocHJpdi0+Y2ZnX21vZGUpIC0gMSk7CisJCXBy aXYtPmNmZ19tb2RlWzRdID0gMDsKKwkJcHJpdi0+b3BzID0gJmZwcF9tZ3JfZnQyNDVfZmlmb19v cHM7CisJCWdwaW9kX2RpcmVjdGlvbl9vdXRwdXRfcmF3KHByaXYtPmNvbmZfZG9uZSwgMCk7CisJ fSBlbHNlIGlmICghc3RybmNtcChidWYsICJiaXRiYW5nIiwgNykpIHsKKwkJc3RybmNweShwcml2 LT5jZmdfbW9kZSwgYnVmLCBzaXplb2YocHJpdi0+Y2ZnX21vZGUpIC0gMSk7CisJCXByaXYtPmNm Z19tb2RlWzddID0gMDsKKwkJcHJpdi0+b3BzID0gJmZwcF9tZ3JfYml0YmFuZ19vcHM7CisJCWdw aW9kX2RpcmVjdGlvbl9pbnB1dChwcml2LT5jb25mX2RvbmUpOworCX0gZWxzZSB7CisJCXJldHVy biAtRUlOVkFMOworCX0KKworCXJldHVybiBjb3VudDsKK30KKworc3RhdGljIERFVklDRV9BVFRS X1JXKGNmZ19tb2RlKTsKKworc3RhdGljIGludCBmcHBfZnBnYV9tZ3JfcHJvYmUoc3RydWN0IHBs YXRmb3JtX2RldmljZSAqcGRldikKK3sKKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSAmcGRldi0+ZGV2 OworCXN0cnVjdCBmcHBfZnBnYV9tZ3JfcHJpdiAqcHJpdjsKKwlzdHJ1Y3QgZnBnYV9tYW5hZ2Vy ICptZ3I7CisJc3RydWN0IGZpZm9fZnBwX21ncl9wbGF0Zm9ybV9kYXRhICpwZDsKKwlpbnQgcmV0 LCByZXRyaWVzID0gTUFYX1JFVFJJRVM7CisJY2hhciBpZF9zdHJpbmdbOF07CisJdTggc3RhdHVz ID0gMDsKKworCXBkID0gZGV2LT5wbGF0Zm9ybV9kYXRhOworCWlmICghcGQpIHsKKwkJZGV2X2Vy cihkZXYsICJNaXNzaW5nIHBsYXRmb3JtIGRhdGEuXG4iKTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJ fQorCisJaWYgKCFwZC0+b3BzIHx8CisJICAgICFwZC0+b3BzLT5idWxrX3hmZXIgfHwgIXBkLT5v cHMtPmN0cmxfeGZlciB8fAorCSAgICAhcGQtPm9wcy0+cmVhZF9kYXRhIHx8ICFwZC0+b3BzLT53 cml0ZV9kYXRhIHx8CisJICAgICFwZC0+b3BzLT5zZXRfYml0bW9kZSB8fCAhcGQtPm9wcy0+c2V0 X2JhdWRyYXRlIHx8CisJICAgICFwZC0+b3BzLT5kaXNhYmxlX2JpdGJhbmcpCisJCXJldHVybiAt RUlOVkFMOworCisJcHJpdiA9IGRldm1fa3phbGxvYyhkZXYsIHNpemVvZigqcHJpdiksIEdGUF9L RVJORUwpOworCWlmICghcHJpdikKKwkJcmV0dXJuIC1FTk9NRU07CisKKwlwcml2LT5pbnRmID0g dG9fdXNiX2ludGVyZmFjZShkZXYtPnBhcmVudCk7CisJcHJpdi0+aW9wcyA9IHBkLT5vcHM7CisK KwlyZXQgPSBzc2NhbmYoZGV2X25hbWUoZGV2LT5wYXJlbnQpLCAiJXMiLCBwcml2LT51c2JfZGV2 X2lkKTsKKwlpZiAocmV0ICE9IDEpIHsKKwkJZGV2X2VycihkZXYsICJDYW4ndCBnZXQgcGFyZW50 IGRldmljZSBuYW1lOiAlZFxuIiwgcmV0KTsKKwkJcmV0dXJuIC1FTk9ERVY7CisJfQorCisJcHJp di0+cGRldiA9IHBkZXY7CisJcHJpdi0+b3BzID0gJmZwcF9tZ3JfZnQyNDVfZmlmb19vcHM7CisJ c3RybmNweShwcml2LT5jZmdfbW9kZSwgImZpZm8iLCBzaXplb2YocHJpdi0+Y2ZnX21vZGUpKTsK KworCXByaXYtPm5jb25maWcgPSBkZXZtX2dwaW9kX2dldChkZXYsICJuY29uZmlnIiwgR1BJT0Rf T1VUX0xPVyk7CisJaWYgKElTX0VSUihwcml2LT5uY29uZmlnKSkgeworCQlyZXQgPSBQVFJfRVJS KHByaXYtPm5jb25maWcpOworCQlkZXZfZXJyKGRldiwgIkZhaWxlZCB0byBnZXQgbmNvbmZpZyBn cGlvOiAlZFxuIiwgcmV0KTsKKwkJcmV0dXJuIHJldDsKKwl9CisKKwlwcml2LT5jb25mX2RvbmUg PSBkZXZtX2dwaW9kX2dldChkZXYsICJjb25mX2RvbmUiLCBHUElPRF9PVVRfTE9XKTsKKwlpZiAo SVNfRVJSKHByaXYtPmNvbmZfZG9uZSkpIHsKKwkJcmV0ID0gUFRSX0VSUihwcml2LT5jb25mX2Rv bmUpOworCQlkZXZfZXJyKGRldiwgIkZhaWxlZCB0byBnZXQgY29uZl9kb25lIGdwaW86ICVkXG4i LCByZXQpOworCQlnb3RvIGVycl9jZmcxOworCX0KKworCXByaXYtPmJ1bGtfYnVmID0gZGV2bV9r bWFsbG9jKGRldiwgQlVMS19PVVRfQlVGX1NaLAorCQkJCSAgICAgIEdGUF9LRVJORUwgfCBHRlBf RE1BMzIpOworCWlmICghcHJpdi0+YnVsa19idWYpIHsKKwkJcmV0ID0gLUVOT01FTTsKKwkJZ290 byBlcnJfY2ZnMjsKKwl9CisKKwlyZXQgPSBwcml2LT5pb3BzLT5zZXRfYml0bW9kZShwcml2LT5p bnRmLCAweGZmLCBCSVRNT0RFX1NZTkNGRik7CisJaWYgKHJldCkKKwkJZ290byBlcnJfY2ZnMjsK KworCS8qIFJlYWQgc3RhdHVzIHJlZ2lzdGVyIGZyb20gQ1BMRCAqLworCWRvIHsKKwkJcmV0ID0g ZnBwX2ZwZ2FfbWdyX3JlYWRfc3RhdHVzKHByaXYsICZzdGF0dXMpOworCQlpZiAoIXJldCkKKwkJ CWJyZWFrOworCX0gd2hpbGUgKC0tcmV0cmllcyA+IDApOworCisJaWYgKCFyZXRyaWVzKSB7CisJ CXJldCA9IC1FVElNRURPVVQ7CisJCWdvdG8gZXJyX2NmZzI7CisJfQorCisJcHJpdi0+cmV2ID0g KHN0YXR1cyAmIElOX0JPQVJEX1JFVikgPyBCT0FSRF9SRVZCIDogQk9BUkRfUkVWQTsKKworCWlm IChwcml2LT5yZXYgPT0gQk9BUkRfUkVWQikgeworCQlwcml2LT5hZGRyX3NlbCA9IChzdGF0dXMg JiBJTl9BRERSX1NFTEVDVCkgPworCQkJCSBBRERSX1NFTEVDVF9OQyA6IEFERFJfU0VMRUNUX0dO RDsKKwkJaWYgKHByaXYtPmFkZHJfc2VsID09IEFERFJfU0VMRUNUX05DKQorCQkJc3RybmNweShp ZF9zdHJpbmcsICJyaWdodCIsIHNpemVvZihpZF9zdHJpbmcpKTsKKwkJZWxzZQorCQkJc3RybmNw eShpZF9zdHJpbmcsICJsZWZ0Iiwgc2l6ZW9mKGlkX3N0cmluZykpOworCX0gZWxzZSB7CisJCXBy aXYtPmFkZHJfc2VsID0gQUREUl9TRUxFQ1RfSU5WQUxJRDsKKwkJc3RybmNweShpZF9zdHJpbmcs ICJzaW5nbGUiLCBzaXplb2YoaWRfc3RyaW5nKSk7CisJfQorCisJZGV2X2luZm8oZGV2LCAiQm9h cmQgUmV2ICVkLCBBZGRyIFNlbCAlZFxuIiwgcHJpdi0+cmV2LCBwcml2LT5hZGRyX3NlbCk7CisK KwkvKiBVc2UgdW5pcXVlIGJvYXJkIElEIGFuZCBVU0IgYnVzL3BvcnQgaW4gRlBHQSBtYW5hZ2Vy IG5hbWUgKi8KKwlzbnByaW50Zihwcml2LT5mcGdhX21ncl9uYW1lLCBzaXplb2YocHJpdi0+ZnBn YV9tZ3JfbmFtZSksCisJCSAiZnRkaS1mcHAtZnBnYS1tZ3IgJXMgJXMiLCBpZF9zdHJpbmcsIHBy aXYtPnVzYl9kZXZfaWQpOworCisJbWdyID0gZGV2bV9mcGdhX21ncl9jcmVhdGUoZGV2LCBwcml2 LT5mcGdhX21ncl9uYW1lLAorCQkJCSAgICZmcHBfZnBnYV9tZ3Jfb3BzLCBwcml2KTsKKwlpZiAo IW1ncikKKwkJZ290byBlcnJfY2ZnMjsKKworCXBsYXRmb3JtX3NldF9kcnZkYXRhKHBkZXYsIG1n cik7CisKKwlyZXQgPSBmcGdhX21ncl9yZWdpc3RlcihtZ3IpOworCWlmIChyZXQpIHsKKwkJZGV2 X2VycihkZXYsICJ1bmFibGUgdG8gcmVnaXN0ZXIgRlBHQSBtYW5hZ2VyXG4iKTsKKwkJZ290byBl cnJfY2ZnMjsKKwl9CisKKwlyZXQgPSBkZXZpY2VfY3JlYXRlX2ZpbGUoZGV2LCAmZGV2X2F0dHJf Y2ZnX21vZGUpOworCWlmIChyZXQpCisJCWRldl93YXJuKGRldiwgIkNhbid0IGNyZWF0ZSBjZmdf bW9kZSBpbnRlcmZhY2UgJWRcbiIsIHJldCk7CisKKwlyZXR1cm4gMDsKKworZXJyX2NmZzI6CisJ ZGV2bV9ncGlvZF9wdXQoZGV2LCBwcml2LT5jb25mX2RvbmUpOworZXJyX2NmZzE6CisJZGV2bV9n cGlvZF9wdXQoZGV2LCBwcml2LT5uY29uZmlnKTsKKwlyZXR1cm4gcmV0OworfQorCitzdGF0aWMg aW50IGZwcF9mcGdhX21ncl9yZW1vdmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldikKK3sK KwlzdHJ1Y3QgZnBnYV9tYW5hZ2VyICptZ3IgPSBwbGF0Zm9ybV9nZXRfZHJ2ZGF0YShwZGV2KTsK KwlzdHJ1Y3QgZnBwX2ZwZ2FfbWdyX3ByaXYgKnByaXYgPSBtZ3ItPnByaXY7CisKKwlkZXZpY2Vf cmVtb3ZlX2ZpbGUoJnBkZXYtPmRldiwgJmRldl9hdHRyX2NmZ19tb2RlKTsKKwlmcGdhX21ncl91 bnJlZ2lzdGVyKG1ncik7CisJZGV2bV9ncGlvZF9wdXQoJnBkZXYtPmRldiwgcHJpdi0+Y29uZl9k b25lKTsKKwlkZXZtX2dwaW9kX3B1dCgmcGRldi0+ZGV2LCBwcml2LT5uY29uZmlnKTsKKwlyZXR1 cm4gMDsKK30KKworc3RhdGljIHN0cnVjdCBwbGF0Zm9ybV9kcml2ZXIgZnBwX2ZwZ2FfbWdyX2Ry aXZlciA9IHsKKwkuZHJpdmVyLm5hbWUJPSAiZnRkaS1maWZvLWZwcC1tZ3IiLAorCS5wcm9iZQkJ PSBmcHBfZnBnYV9tZ3JfcHJvYmUsCisJLnJlbW92ZQkJPSBmcHBfZnBnYV9tZ3JfcmVtb3ZlLAor fTsKKworbW9kdWxlX3BsYXRmb3JtX2RyaXZlcihmcHBfZnBnYV9tZ3JfZHJpdmVyKTsKKworTU9E VUxFX0FMSUFTKCJwbGF0Zm9ybTpmdGRpLWZpZm8tZnBwLW1nciIpOworTU9EVUxFX0FVVEhPUigi QW5hdG9saWogR3VzdHNjaGluIDxhZ3VzdEBkZW54LmRlPiIpOworTU9EVUxFX0RFU0NSSVBUSU9O KCJGVDIzMkggQml0YmFuZy9GVDI0NS1GSUZPIEZQUCBGUEdBIE1hbmFnZXIgRHJpdmVyIik7CitN T0RVTEVfTElDRU5TRSgiR1BMIHYyIik7Cg==