From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Return-Path: From: Anatolij Gustschin Subject: [PATCH v2 3/3] fpga: Add fpga manager driver for ARRI Altera FPP Date: Tue, 20 Nov 2018 01:28:21 +0100 Message-Id: <20181120002821.12794-4-agust@denx.de> In-Reply-To: <20181120002821.12794-1-agust@denx.de> References: <20181120002821.12794-1-agust@denx.de> 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: 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..084e691d0983 --- /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: Nov 2018 +Kernel Version: 4.21 +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 205042b441ea..584866a27c35 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -59,6 +59,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 7a2d73ba7122..8c1d714bd440 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..652a5430bdf2 --- /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)); + 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)); + 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: [v2,3/3] fpga: Add fpga manager driver for ARRI Altera FPP From: Anatolij Gustschin Message-Id: <20181120002821.12794-4-agust@denx.de> Date: Tue, 20 Nov 2018 01:28:21 +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 aWZvLWZwcApuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAwMDAwMDAuLjA4NGU2OTFk MDk4MwotLS0gL2Rldi9udWxsCisrKyBiL0RvY3VtZW50YXRpb24vQUJJL3Rlc3Rpbmcvc3lzZnMt ZHJpdmVyLWZ0ZGktZmlmby1mcHAKQEAgLTAsMCArMSw3IEBACitXaGF0OgkJL3N5cy9idXMvcGxh dGZvcm0vZGV2aWNlcy9mdGRpLWZpZm8tZnBwLW1nci5OL2NmZ19tb2RlCitEYXRlOgkJTm92IDIw MTgKK0tlcm5lbCBWZXJzaW9uOgk0LjIxCitDb250YWN0OglBbmF0b2xpaiBHdXN0c2NoaW4gPGFn dXN0QGRlbnguZGU+CitEZXNjcmlwdGlvbjoKKwkJQ29udGFpbnMgZWl0aGVyICJmaWZvIiBvciAi Yml0YmFuZyIgYW5kIGNvbnRyb2xzIGlmIGZpZm8KKwkJb2YgYml0YmFuZyBjb25maWd1cmF0aW9u IG1vZGUgaXMgdXNlZCBpbiB0aGUgZHJpdmVyLgpkaWZmIC0tZ2l0IGEvZHJpdmVycy9mcGdhL0tj b25maWcgYi9kcml2ZXJzL2ZwZ2EvS2NvbmZpZwppbmRleCAyMDUwNDJiNDQxZWEuLjU4NDg2NmEy N2MzNSAxMDA2NDQKLS0tIGEvZHJpdmVycy9mcGdhL0tjb25maWcKKysrIGIvZHJpdmVycy9mcGdh L0tjb25maWcKQEAgLTU5LDYgKzU5LDEzIEBAIGNvbmZpZyBGUEdBX01HUl9BTFRFUkFfQ1ZQCiAJ ICBGUEdBIG1hbmFnZXIgZHJpdmVyIHN1cHBvcnQgZm9yIEFycmlhLVYsIEN5Y2xvbmUtViwgU3Ry YXRpeC1WCiAJICBhbmQgQXJyaWEgMTAgQWx0ZXJhIEZQR0FzIHVzaW5nIHRoZSBDdlAgaW50ZXJm YWNlIG92ZXIgUENJZS4KIAorY29uZmlnIEZQR0FfTUdSX0ZURElfRklGT19GUFAKKwl0cmlzdGF0 ZSAiQWx0ZXJhIEZQUCBvdmVyIEZUMjMySCBGSUZPIgorCWRlcGVuZHMgb24gVVNCX0ZUMjMySF9J TlRGCisJaGVscAorCSAgRlBHQSBtYW5hZ2VyIGRyaXZlciBzdXBwb3J0IGZvciBBbHRlcmEgZmFz dCBwYXNzaXZlIHBhcmFsbGVsCisJICBpbnRlcmZhY2UgKEZQUCkgb3ZlciBGVDIzMkggRlQyNDUg RklGTy4KKwogY29uZmlnIEZQR0FfTUdSX1pZTlFfRlBHQQogCXRyaXN0YXRlICJYaWxpbnggWnlu cSBGUEdBIgogCWRlcGVuZHMgb24gQVJDSF9aWU5RIHx8IENPTVBJTEVfVEVTVApkaWZmIC0tZ2l0 IGEvZHJpdmVycy9mcGdhL01ha2VmaWxlIGIvZHJpdmVycy9mcGdhL01ha2VmaWxlCmluZGV4IDdh MmQ3M2JhNzEyMi4uOGMxZDcxNGJkNDQwIDEwMDY0NAotLS0gYS9kcml2ZXJzL2ZwZ2EvTWFrZWZp bGUKKysrIGIvZHJpdmVycy9mcGdhL01ha2VmaWxlCkBAIC05LDYgKzksNyBAQCBvYmotJChDT05G SUdfRlBHQSkJCQkrPSBmcGdhLW1nci5vCiAjIEZQR0EgTWFuYWdlciBEcml2ZXJzCiBvYmotJChD T05GSUdfRlBHQV9NR1JfQUxURVJBX0NWUCkJKz0gYWx0ZXJhLWN2cC5vCiBvYmotJChDT05GSUdf RlBHQV9NR1JfQUxURVJBX1BTX1NQSSkJKz0gYWx0ZXJhLXBzLXNwaS5vCitvYmotJChDT05GSUdf RlBHQV9NR1JfRlRESV9GSUZPX0ZQUCkJKz0gZnRkaS1maWZvLWZwcC5vCiBvYmotJChDT05GSUdf RlBHQV9NR1JfSUNFNDBfU1BJKQkrPSBpY2U0MC1zcGkubwogb2JqLSQoQ09ORklHX0ZQR0FfTUdS X01BQ0hYTzJfU1BJKQkrPSBtYWNoeG8yLXNwaS5vCiBvYmotJChDT05GSUdfRlBHQV9NR1JfU09D RlBHQSkJCSs9IHNvY2ZwZ2EubwpkaWZmIC0tZ2l0IGEvZHJpdmVycy9mcGdhL2Z0ZGktZmlmby1m cHAuYyBiL2RyaXZlcnMvZnBnYS9mdGRpLWZpZm8tZnBwLmMKbmV3IGZpbGUgbW9kZSAxMDA2NDQK aW5kZXggMDAwMDAwMDAwMDAwLi42NTJhNTQzMGJkZjIKLS0tIC9kZXYvbnVsbAorKysgYi9kcml2 ZXJzL2ZwZ2EvZnRkaS1maWZvLWZwcC5jCkBAIC0wLDAgKzEsNTk0IEBACisvLyBTUERYLUxpY2Vu c2UtSWRlbnRpZmllcjogR1BMLTIuMAorLyoKKyAqIEFsdGVyYSBGUEdBIGZpcm13YXJlIHVwbG9h ZCB2aWEgRlBQIHVzaW5nIEZUMjMySCBCaXRiYW5nL0ZUMjQ1LUZJRk8uCisgKgorICogQ29weXJp Z2h0IChDKSAyMDE3IC0gMjAxOCBERU5YIFNvZnR3YXJlIEVuZ2luZWVyaW5nCisgKiBBbmF0b2xp aiBHdXN0c2NoaW4gPGFndXN0QGRlbnguZGU+CisgKi8KKworI2luY2x1ZGUgPGxpbnV4L2JpdG9w cy5oPgorI2luY2x1ZGUgPGxpbnV4L2RlbGF5Lmg+CisjaW5jbHVkZSA8bGludXgvZnBnYS9mcGdh LW1nci5oPgorI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPgorI2luY2x1ZGUgPGxpbnV4L2tlcm5l bC5oPgorI2luY2x1ZGUgPGxpbnV4L3NpemVzLmg+CisjaW5jbHVkZSA8bGludXgvc2xhYi5oPgor I2luY2x1ZGUgPGxpbnV4L2dwaW8vY29uc3VtZXIuaD4KKyNpbmNsdWRlIDxsaW51eC9wbGF0Zm9y bV9kZXZpY2UuaD4KKyNpbmNsdWRlIDxsaW51eC91c2IuaD4KKyNpbmNsdWRlIDxsaW51eC91c2Iv ZnQyMzJoLWludGYuaD4KKworI2RlZmluZQlCVUxLX09VVF9CVUZfU1oJU1pfMU0KKyNkZWZpbmUJ TUFYX1JFVFJJRVMJMTAKKworLyoKKyAqIFdpdGggbG9naWMgb2YgQ1BMRCB3ZSBjYW4gd3JpdGUg dGhlIHN0YXRlIG9mIG5Db25maWcgcGluIGFuZAorICogcmVhZCBiYWNrIHRoZSBzdGF0ZSBvZiBz b21lIHBpbnMgKGNvbmZfZG9uZSwgaW5pdF9kb25lLCBuU3RhdHVzKS4KKyAqIFN0YXR1cyBoZWFk ZXIgYW5kIGJpdCBhc3NpZ25tZW50IGluIGRhdGEgcmVnaXN0ZXIgb24gQ1BMRC4KKyAqLworI2Rl ZmluZSBJTlBVVF9IRUFERVJfMAkweEE1CisjZGVmaW5lIElOUFVUX0hFQURFUl8xCTB4NUEKKyNk ZWZpbmUgSU5fQ09ORl9ET05FCUJJVCgwKQorI2RlZmluZSBJTl9JTklUX0RPTkUJQklUKDEpCisj ZGVmaW5lIElOX0FERFJfU0VMRUNUCUJJVCg0KQorI2RlZmluZSBJTl9CT0FSRF9SRVYJQklUKDUp CisjZGVmaW5lIE9VVF9OQ09ORklHCUJJVCgwKQorI2RlZmluZSBPVVRfUkVTRVRfTglCSVQoMSkK KworZW51bSBmcHBfYm9hcmRfcmV2IHsKKwlCT0FSRF9SRVZBID0gMSwKKwlCT0FSRF9SRVZCID0g MiwKK307CisKK2VudW0gZnBwX2FkZHJfc2VsIHsKKwlBRERSX1NFTEVDVF9JTlZBTElELAorCUFE RFJfU0VMRUNUX0dORCwKKwlBRERSX1NFTEVDVF9OQworfTsKKworc3RydWN0IGZwcF9tZ3Jfb3Bz IHsKKwlpbnQgKCp3cml0ZV9pbml0KShzdHJ1Y3QgZnBnYV9tYW5hZ2VyICptZ3IsCisJCQkgIHN0 cnVjdCBmcGdhX2ltYWdlX2luZm8gKmluZm8sCisJCQkgIGNvbnN0IGNoYXIgKmJ1Ziwgc2l6ZV90 IGNvdW50KTsKKwlpbnQgKCp3cml0ZSkoc3RydWN0IGZwZ2FfbWFuYWdlciAqbWdyLCBjb25zdCBj aGFyICpidWYsIHNpemVfdCBjb3VudCk7CisJaW50ICgqd3JpdGVfY29tcGxldGUpKHN0cnVjdCBm cGdhX21hbmFnZXIgKm1nciwKKwkJCSAgICAgIHN0cnVjdCBmcGdhX2ltYWdlX2luZm8gKmluZm8p OworfTsKKworc3RydWN0IGZwcF9mcGdhX21ncl9wcml2IHsKKwlzdHJ1Y3QgcGxhdGZvcm1fZGV2 aWNlCQkqcGRldjsKKwlzdHJ1Y3QgdXNiX2ludGVyZmFjZQkJKmludGY7CisJY29uc3Qgc3RydWN0 IGZ0MjMyaF9pbnRmX29wcwkqaW9wczsKKwlzdHJ1Y3QgZnBnYV9tYW5hZ2VyCSptZ3I7CisJc3Ry dWN0IGZwcF9tZ3Jfb3BzCSpvcHM7CisJc3RydWN0IGdwaW9fZGVzYwkqbmNvbmZpZzsKKwlzdHJ1 Y3QgZ3Bpb19kZXNjCSpjb25mX2RvbmU7CisJY2hhcgkJCWNmZ19tb2RlWzhdOworCXU4CQkJb3V0 X2RhdGFfcG9ydDsKKwlpbnQJCQlpbmRleDsKKwl2b2lkCQkJKmJ1bGtfYnVmOworCWNoYXIJCQl1 c2JfZGV2X2lkWzMyXTsKKwljaGFyCQkJZnBnYV9tZ3JfbmFtZVs2NF07CisJZW51bSBmcHBfYm9h cmRfcmV2CXJldjsKKwllbnVtIGZwcF9hZGRyX3NlbAlhZGRyX3NlbDsKK307CisKK3N0YXRpYyBp bnQgZnBwX2ZwZ2FfbWdyX3NldF9kYXRhX3BvcnQoc3RydWN0IGZwcF9mcGdhX21ncl9wcml2ICpw cml2LAorCQkJCSAgICAgIHU4IGJpdG1hc2ssIHU4IHZhbHVlKQoreworCXN0cnVjdCBkZXZpY2Ug KmRldiA9ICZwcml2LT5wZGV2LT5kZXY7CisJc3RydWN0IGJ1bGtfZGVzYyBkZXNjOworCXU4ICpk YXRhOworCWludCByZXQ7CisKKwkvKgorCSAqIFdpdGggQ1BMRCBjb25uZWN0ZWQgKGluIEZUMjQ1 IEZJRk8gbW9kZSkgd2UgdXNlIEFDQlVTOCY5CisJICogcGlucyB0byBzd2l0Y2ggYmV0d2VlbiBk YXRhIGFuZCBjb21tYW5kIG1vZGU6CisJICogQUNCVVM4JjkgPT0gMCwgMCAgLS0+IG5vcm1hbCBt b2RlIChkYXRhIGNvbW11bmljYXRpb24pCisJICogQUNCVVM4JjkgPT0gMSwgMCAgLS0+IGNvbW1h bmQgbW9kZQorCSAqLworCWdwaW9kX3NldF9yYXdfdmFsdWVfY2Fuc2xlZXAocHJpdi0+bmNvbmZp ZywgMSk7CisJZ3Bpb2Rfc2V0X3Jhd192YWx1ZV9jYW5zbGVlcChwcml2LT5jb25mX2RvbmUsIDAp OworCW1zbGVlcCg1MCk7CisKKwkvKiBXcml0ZSBjb21tYW5kcyB0byBDUExEICovCisJcmV0ID0g cHJpdi0+aW9wcy0+c2V0X2JpdG1vZGUocHJpdi0+aW50ZiwgMHgwMCwgQklUTU9ERV9TWU5DRkYp OworCWlmIChyZXQpCisJCXJldHVybiByZXQ7CisKKwlpZiAodmFsdWUpCisJCXByaXYtPm91dF9k YXRhX3BvcnQgfD0gYml0bWFzazsKKwllbHNlCisJCXByaXYtPm91dF9kYXRhX3BvcnQgJj0gfmJp dG1hc2s7CisKKwlkYXRhID0gcHJpdi0+YnVsa19idWY7CisJKmRhdGEgPSBwcml2LT5vdXRfZGF0 YV9wb3J0OworCisJZGVzYy5kaXJfb3V0ID0gdHJ1ZTsKKwlkZXNjLmFjdF9sZW4gPSAwOworCWRl c2MubGVuID0gMTsKKwlkZXNjLmRhdGEgPSBkYXRhOworCWRlc2MudGltZW91dCA9IEZURElfVVNC X1dSSVRFX1RJTUVPVVQ7CisKKwlyZXQgPSBwcml2LT5pb3BzLT5idWxrX3hmZXIocHJpdi0+aW50 ZiwgJmRlc2MpOworCWlmIChyZXQpIHsKKwkJZGV2X2VycihkZXYsICJXcml0aW5nIGluIFNZTkNG RiBtb2RlIGZhaWxlZDogJWRcbiIsIHJldCk7CisJCXJldHVybiByZXQ7CisJfQorCisJbXNsZWVw KDUwKTsKKwkvKiBTd2l0Y2ggYmFjayB0byBkYXRhIG1vZGUgd2l0aCBBQ0JVUzgmOSBiYWNrIHRv IGxvdyAqLworCWdwaW9kX3NldF9yYXdfdmFsdWVfY2Fuc2xlZXAocHJpdi0+bmNvbmZpZywgMCk7 CisJZ3Bpb2Rfc2V0X3Jhd192YWx1ZV9jYW5zbGVlcChwcml2LT5jb25mX2RvbmUsIDApOworCW1z bGVlcCg1MCk7CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGludCBmcHBfZnBnYV9tZ3JfYml0 YmFuZ193cml0ZV9pbml0KHN0cnVjdCBmcGdhX21hbmFnZXIgKm1nciwKKwkJCQkJICAgc3RydWN0 IGZwZ2FfaW1hZ2VfaW5mbyAqaW5mbywKKwkJCQkJICAgY29uc3QgY2hhciAqYnVmLCBzaXplX3Qg Y291bnQpCit7CisJc3RydWN0IGZwcF9mcGdhX21ncl9wcml2ICpwcml2ID0gbWdyLT5wcml2Owor CXN0cnVjdCBkZXZpY2UgKmRldiA9ICZwcml2LT5wZGV2LT5kZXY7CisJaW50IHJldHJpZXMgPSBN QVhfUkVUUklFUzsKKwlpbnQgcmV0OworCisJZ3Bpb2Rfc2V0X3ZhbHVlX2NhbnNsZWVwKHByaXYt Pm5jb25maWcsIDApOworCW1zbGVlcCg1MCk7CisJZ3Bpb2Rfc2V0X3ZhbHVlX2NhbnNsZWVwKHBy aXYtPm5jb25maWcsIDEpOworCW1zbGVlcCg1MCk7CisJZ3Bpb2Rfc2V0X3ZhbHVlX2NhbnNsZWVw KHByaXYtPm5jb25maWcsIDApOworCisJLyogV2FpdCBmb3IgQ09ORl9ET05FIHRvIGdldCBsb3cg Ki8KKwlkbyB7CisJCW1zbGVlcCg1MCk7CisKKwkJcmV0ID0gZ3Bpb2RfZ2V0X3ZhbHVlX2NhbnNs ZWVwKHByaXYtPmNvbmZfZG9uZSk7CisJCWlmIChyZXQgPCAwKSB7CisJCQlkZXZfZXJyKGRldiwg IkZhaWxlZCB0byBnZXQgQ09ORl9ET05FIHBpbjogJWRcbiIsIHJldCk7CisJCQlyZXR1cm4gcmV0 OworCQl9CisKKwkJaWYgKCFyZXQpCisJCQlicmVhazsKKwl9IHdoaWxlICgtLXJldHJpZXMgPiAw KTsKKworCWlmICghcmV0cmllcykgeworCQlkZXZfd2FybihkZXYsICJDT05GX0RPTkUgbG93IHdh aXQgdGltZW91dFxuIik7CisJCXJldHVybiAtRVRJTUVET1VUOworCX0KKworCXJldCA9IHByaXYt PmlvcHMtPnNldF9iaXRtb2RlKHByaXYtPmludGYsIDB4ZmYsIEJJVE1PREVfQklUQkFORyk7CisJ aWYgKHJldCA8IDApCisJCXJldHVybiByZXQ7CisKKwkvKiBTZXQgbWF4LiB3b3JraW5nIGJhdWQg cmF0ZSAoZm9yIGhhcmR3YXJlIHdpdGhvdXQgQ1BMRCkgKi8KKwlyZXR1cm4gcHJpdi0+aW9wcy0+ c2V0X2JhdWRyYXRlKHByaXYtPmludGYsIDcwMDAwMCk7Cit9CisKK3N0YXRpYyBpbnQgZnBwX2Zw Z2FfbWdyX2JpdGJhbmdfd3JpdGUoc3RydWN0IGZwZ2FfbWFuYWdlciAqbWdyLAorCQkJCSAgICAg IGNvbnN0IGNoYXIgKmJ1Ziwgc2l6ZV90IGNvdW50KQoreworCXN0cnVjdCBmcHBfZnBnYV9tZ3Jf cHJpdiAqcHJpdiA9IG1nci0+cHJpdjsKKwlzdHJ1Y3QgYnVsa19kZXNjIGRlc2M7CisJc2l6ZV90 IGJsa19zejsKKwlpbnQgcmV0OworCisJZGVzYy5kYXRhID0gcHJpdi0+YnVsa19idWY7CisJZGVz Yy5kaXJfb3V0ID0gdHJ1ZTsKKwlkZXNjLnRpbWVvdXQgPSBGVERJX1VTQl9XUklURV9USU1FT1VU OworCisJd2hpbGUgKGNvdW50KSB7CisJCWJsa19zeiA9IG1pbl90KHNpemVfdCwgY291bnQsIEJV TEtfT1VUX0JVRl9TWik7CisJCW1lbWNweShwcml2LT5idWxrX2J1ZiwgYnVmLCBibGtfc3opOwor CQlkZXNjLmFjdF9sZW4gPSAwOworCQlkZXNjLmxlbiA9IGJsa19zejsKKwkJcmV0ID0gcHJpdi0+ aW9wcy0+YnVsa194ZmVyKHByaXYtPmludGYsICZkZXNjKTsKKwkJaWYgKHJldCA8IDApCisJCQly ZXR1cm4gcmV0OworCisJCWJ1ZiArPSBkZXNjLmFjdF9sZW47CisJCWNvdW50IC09IGRlc2MuYWN0 X2xlbjsKKwl9CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGludCBmcHBfZnBnYV9tZ3JfYml0 YmFuZ193cml0ZV9jb21wbGV0ZShzdHJ1Y3QgZnBnYV9tYW5hZ2VyICptZ3IsCisJCQkJCSAgICAg ICBzdHJ1Y3QgZnBnYV9pbWFnZV9pbmZvICppbmZvKQoreworCXN0cnVjdCBmcHBfZnBnYV9tZ3Jf cHJpdiAqcHJpdiA9IG1nci0+cHJpdjsKKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSAmcHJpdi0+cGRl di0+ZGV2OworCWludCByZXRyaWVzID0gTUFYX1JFVFJJRVM7CisJaW50IHJldDsKKworCS8qIFdh aXQgZm9yIENPTkZfRE9ORSB0byBnZXQgaGlnaCAqLworCWRvIHsKKwkJbXNsZWVwKDUwKTsKKwor CQlyZXQgPSBncGlvZF9nZXRfdmFsdWVfY2Fuc2xlZXAocHJpdi0+Y29uZl9kb25lKTsKKwkJaWYg KHJldCA8IDApCisJCQlyZXR1cm4gcmV0OworCisJCWlmIChyZXQpCisJCQlicmVhazsKKwl9IHdo aWxlICgtLXJldHJpZXMgPiAwKTsKKworCWlmICghcmV0cmllcykgeworCQlkZXZfd2FybihkZXYs ICJDT05GX0RPTkUgd2FpdCB0aW1lb3V0XG4iKTsKKwkJcmV0dXJuIC1FVElNRURPVVQ7CisJfQor CisJcHJpdi0+aW9wcy0+ZGlzYWJsZV9iaXRiYW5nKHByaXYtPmludGYpOworCXJldHVybiAwOwor fQorCitzdGF0aWMgaW5saW5lIGJvb2wgc3RhdHVzX2hkcl9pc192YWxpZCh1OCAqYnVmKQorewor CXJldHVybiBidWZbMF0gPT0gSU5QVVRfSEVBREVSXzAgJiYgYnVmWzFdID09IElOUFVUX0hFQURF Ul8xOworfQorCitzdGF0aWMgaW50IGZwcF9mcGdhX21ncl9yZWFkX3N0YXR1cyhzdHJ1Y3QgZnBw X2ZwZ2FfbWdyX3ByaXYgKnByaXYsIHU4ICpzdGF0dXMpCit7CisJc3RydWN0IGRldmljZSAqZGV2 ID0gJnByaXYtPnBkZXYtPmRldjsKKwl1OCAqaW5idWYgPSBwcml2LT5idWxrX2J1ZjsKKwlpbnQg cmV0cmllcyA9IE1BWF9SRVRSSUVTOworCWludCByZXQ7CisKKwlpZiAoIXN0YXR1cykKKwkJcmV0 dXJuIC1FSU5WQUw7CisKKwkvKiBXYWl0IHVudGlsIENQTEQgc2VuZHMgdmFsaWQgaGVhZGVyIGFu ZCBzdGF0dXMgcmVnaXN0ZXIgKi8KKwlkbyB7CisJCXJldCA9IHByaXYtPmlvcHMtPnJlYWRfZGF0 YShwcml2LT5pbnRmLCBpbmJ1ZiwgNjQpOworCQlpZiAocmV0IDwgMCkgeworCQkJZGV2X2Vycihk ZXYsICJDYW4ndCByZWFkIHN0YXR1cyBkYXRhOiAlZFxuIiwgcmV0KTsKKwkJCXJldHVybiByZXQ7 CisJCX0KKworCQkvKiBDaGVjayBpbnB1dCBidWZmZXIgaGVhZGVyICovCisJCWlmIChyZXQgPj0g NCAmJiBzdGF0dXNfaGRyX2lzX3ZhbGlkKGluYnVmKSkgeworCQkJKnN0YXR1cyA9IGluYnVmWzJd OworCQkJcmV0dXJuIDA7CisJCX0KKworCQkvKiBXYWl0IGFuZCByZWFkIGJhY2sgc3RhdHVzIGFn YWluICovCisJCW1zbGVlcCgxMDApOyAvKiBDUExEIHNlbmRzIHN0YXR1cyBldmVyeSAxMDBtcyAq LworCX0gd2hpbGUgKC0tcmV0cmllcyA+IDApOworCisJZGV2X3dhcm4oZGV2LCAiVGltZW91dCB3 aGVuIHJlYWRpbmcgc3RhdHVzXG4iKTsKKwlyZXR1cm4gLUVUSU1FRE9VVDsKK30KKworc3RhdGlj IGludCBmcHBfZnBnYV9tZ3JfZnQyNDVfZmlmb193cml0ZV9pbml0KHN0cnVjdCBmcGdhX21hbmFn ZXIgKm1nciwKKwkJCQkJICAgICAgc3RydWN0IGZwZ2FfaW1hZ2VfaW5mbyAqaW5mbywKKwkJCQkJ ICAgICAgY29uc3QgY2hhciAqYnVmLCBzaXplX3QgY291bnQpCit7CisJc3RydWN0IGZwcF9mcGdh X21ncl9wcml2ICpwcml2ID0gbWdyLT5wcml2OworCXN0cnVjdCBkZXZpY2UgKmRldiA9ICZwcml2 LT5wZGV2LT5kZXY7CisJaW50IHJldHJpZXMgPSBNQVhfUkVUUklFUzsKKwlpbnQgcmV0OworCXU4 IHN0YXR1czsKKworCWdwaW9kX2RpcmVjdGlvbl9vdXRwdXRfcmF3KHByaXYtPmNvbmZfZG9uZSwg MCk7CisKKwkvKiBTZXQvcmVzZXQgbkNvbmZpZyB2aWEgY29tbWFuZHMgdG8gQ1BMRCAqLworCXJl dCA9IGZwcF9mcGdhX21ncl9zZXRfZGF0YV9wb3J0KHByaXYsIE9VVF9OQ09ORklHLCAxKTsKKwlp ZiAocmV0KQorCQlyZXR1cm4gcmV0OworCXJldCA9IGZwcF9mcGdhX21ncl9zZXRfZGF0YV9wb3J0 KHByaXYsIE9VVF9OQ09ORklHLCAwKTsKKwlpZiAocmV0KQorCQlyZXR1cm4gcmV0OworCXJldCA9 IGZwcF9mcGdhX21ncl9zZXRfZGF0YV9wb3J0KHByaXYsIE9VVF9OQ09ORklHLCAxKTsKKwlpZiAo cmV0KQorCQlyZXR1cm4gcmV0OworCisJLyogSW4gRlQyNDUgRklGTyBtb2RlIHdlIG5lZWQgc3lu YyBGSUZPIG1vZGUgdG8gdGFsayB0byBGUEdBICovCisJcmV0ID0gcHJpdi0+aW9wcy0+c2V0X2Jp dG1vZGUocHJpdi0+aW50ZiwgMHhmZiwgQklUTU9ERV9TWU5DRkYpOworCWlmIChyZXQpCisJCXJl dHVybiByZXQ7CisKKwkvKiBXYWl0IHVudGlsIEZQR0EgaXMgcmVhZHkgZm9yIGxvYWRpbmcgKGNv bmZfZG9uZSB6ZXJvKSBvciB0aW1lb3V0ICovCisJZG8geworCQlyZXQgPSBmcHBfZnBnYV9tZ3Jf cmVhZF9zdGF0dXMocHJpdiwgJnN0YXR1cyk7CisJCWlmICghcmV0KSB7CisJCQkvKiBDaGVjayBj b25mX2RvbmUgc3RhdHVzICovCisJCQlpZiAoKHN0YXR1cyAmIElOX0NPTkZfRE9ORSkgPT0gMCkK KwkJCQlicmVhazsKKwkJfQorCX0gd2hpbGUgKC0tcmV0cmllcyA+IDApOworCisJaWYgKCFyZXRy aWVzKSB7CisJCWRldl93YXJuKGRldiwgIkNPTkZfRE9ORSB3YWl0IHRpbWVvdXRcbiIpOworCQly ZXR1cm4gLUVUSU1FRE9VVDsKKwl9CisKKwkvKiBDb25maWd1cmUgZm9yIG1heC4gYmF1ZCByYXRl ICgzTUh6ICogNCBpbiBiaXRiYW5nIG1vZGUpICovCisJcmV0dXJuIHByaXYtPmlvcHMtPnNldF9i YXVkcmF0ZShwcml2LT5pbnRmLCAzMDAwMDAwKTsKK30KKworc3RhdGljIGludCBmcHBfZnBnYV9t Z3JfZnQyNDVfZmlmb193cml0ZShzdHJ1Y3QgZnBnYV9tYW5hZ2VyICptZ3IsCisJCQkJCSBjb25z dCBjaGFyICpidWYsIHNpemVfdCBjb3VudCkKK3sKKwlyZXR1cm4gZnBwX2ZwZ2FfbWdyX2JpdGJh bmdfd3JpdGUobWdyLCBidWYsIGNvdW50KTsKK30KKworc3RhdGljIGludCBmcHBfZnBnYV9tZ3Jf ZnQyNDVfZmlmb193cml0ZV9jb21wbGV0ZShzdHJ1Y3QgZnBnYV9tYW5hZ2VyICptZ3IsCisJCQkJ CQkgIHN0cnVjdCBmcGdhX2ltYWdlX2luZm8gKmluZm8pCit7CisJc3RydWN0IGZwcF9mcGdhX21n cl9wcml2ICpwcml2ID0gbWdyLT5wcml2OworCXN0cnVjdCBkZXZpY2UgKmRldiA9ICZwcml2LT5w ZGV2LT5kZXY7CisJaW50IHJldHJpZXMgPSBNQVhfUkVUUklFUzsKKwlpbnQgcmV0OworCXU4IG1h c2ssIHN0YXR1czsKKworCW1hc2sgPSBJTl9DT05GX0RPTkUgfCBJTl9JTklUX0RPTkU7CisKKwlk byB7CisJCXJldCA9IGZwcF9mcGdhX21ncl9yZWFkX3N0YXR1cyhwcml2LCAmc3RhdHVzKTsKKwkJ aWYgKCFyZXQpIHsKKwkJCS8qIENoZWNrIGNvbmZfZG9uZS9pbml0X2RvbmUgc3RhdHVzICovCisJ CQlpZiAoKHN0YXR1cyAmIG1hc2spID09IG1hc2spCisJCQkJYnJlYWs7CisJCX0KKwl9IHdoaWxl ICgtLXJldHJpZXMgPiAwKTsKKworCWlmICghcmV0cmllcykgeworCQlkZXZfd2FybihkZXYsICJJ TklUX0RPTkUgd2FpdCB0aW1lb3V0XG4iKTsKKwkJcmV0dXJuIC1FVElNRURPVVQ7CisJfQorCisJ LyogUmVsZWFzZSBSZXNldF9uLCBrZWVwIG5DT05GSUcgaGlnaCwgdG9vISAqLworCXJldHVybiBm cHBfZnBnYV9tZ3Jfc2V0X2RhdGFfcG9ydChwcml2LCBPVVRfTkNPTkZJRyB8IE9VVF9SRVNFVF9O LCAxKTsKK30KKworc3RhdGljIGVudW0gZnBnYV9tZ3Jfc3RhdGVzIGZwcF9mcGdhX21ncl9zdGF0 ZShzdHJ1Y3QgZnBnYV9tYW5hZ2VyICptZ3IpCit7CisJcmV0dXJuIEZQR0FfTUdSX1NUQVRFX1VO S05PV047Cit9CisKK3N0YXRpYyBpbnQgZnBwX2ZwZ2FfbWdyX3dyaXRlX2luaXQoc3RydWN0IGZw Z2FfbWFuYWdlciAqbWdyLAorCQkJCSAgIHN0cnVjdCBmcGdhX2ltYWdlX2luZm8gKmluZm8sCisJ CQkJICAgY29uc3QgY2hhciAqYnVmLCBzaXplX3QgY291bnQpCit7CisJc3RydWN0IGZwcF9mcGdh X21ncl9wcml2ICpwcml2ID0gbWdyLT5wcml2OworCisJaWYgKGluZm8gJiYgaW5mby0+ZmxhZ3Mg JiBGUEdBX01HUl9QQVJUSUFMX1JFQ09ORklHKSB7CisJCWRldl9lcnIoJm1nci0+ZGV2LCAiUGFy dGlhbCByZWNvbmZpZ3VyYXRpb24gbm90IHN1cHBvcnRlZC5cbiIpOworCQlyZXR1cm4gLUVJTlZB TDsKKwl9CisKKwlpZiAocHJpdi0+b3BzLT53cml0ZV9pbml0KQorCQlyZXR1cm4gcHJpdi0+b3Bz LT53cml0ZV9pbml0KG1nciwgaW5mbywgYnVmLCBjb3VudCk7CisKKwlyZXR1cm4gLUVOT0RFVjsK K30KKworc3RhdGljIGludCBmcHBfZnBnYV9tZ3Jfd3JpdGUoc3RydWN0IGZwZ2FfbWFuYWdlciAq bWdyLCBjb25zdCBjaGFyICpidWYsCisJCQkgICAgICBzaXplX3QgY291bnQpCit7CisJc3RydWN0 IGZwcF9mcGdhX21ncl9wcml2ICpwcml2ID0gbWdyLT5wcml2OworCisJaWYgKHByaXYtPm9wcy0+ d3JpdGUpCisJCXJldHVybiBwcml2LT5vcHMtPndyaXRlKG1nciwgYnVmLCBjb3VudCk7CisKKwly ZXR1cm4gLUVOT0RFVjsKK30KKworc3RhdGljIGludCBmcHBfZnBnYV9tZ3Jfd3JpdGVfY29tcGxl dGUoc3RydWN0IGZwZ2FfbWFuYWdlciAqbWdyLAorCQkJCSAgICAgICBzdHJ1Y3QgZnBnYV9pbWFn ZV9pbmZvICppbmZvKQoreworCXN0cnVjdCBmcHBfZnBnYV9tZ3JfcHJpdiAqcHJpdiA9IG1nci0+ cHJpdjsKKworCWlmIChwcml2LT5vcHMtPndyaXRlX2NvbXBsZXRlKQorCQlyZXR1cm4gcHJpdi0+ b3BzLT53cml0ZV9jb21wbGV0ZShtZ3IsIGluZm8pOworCisJcmV0dXJuIC1FTk9ERVY7Cit9CisK K3N0YXRpYyBzdHJ1Y3QgZnBwX21ncl9vcHMgZnBwX21ncl9iaXRiYW5nX29wcyA9IHsKKwkud3Jp dGVfaW5pdAk9IGZwcF9mcGdhX21ncl9iaXRiYW5nX3dyaXRlX2luaXQsCisJLndyaXRlCQk9IGZw cF9mcGdhX21ncl9iaXRiYW5nX3dyaXRlLAorCS53cml0ZV9jb21wbGV0ZQk9IGZwcF9mcGdhX21n cl9iaXRiYW5nX3dyaXRlX2NvbXBsZXRlLAorfTsKKworc3RhdGljIHN0cnVjdCBmcHBfbWdyX29w cyBmcHBfbWdyX2Z0MjQ1X2ZpZm9fb3BzID0geworCS53cml0ZV9pbml0CT0gZnBwX2ZwZ2FfbWdy X2Z0MjQ1X2ZpZm9fd3JpdGVfaW5pdCwKKwkud3JpdGUJCT0gZnBwX2ZwZ2FfbWdyX2Z0MjQ1X2Zp Zm9fd3JpdGUsCisJLndyaXRlX2NvbXBsZXRlCT0gZnBwX2ZwZ2FfbWdyX2Z0MjQ1X2ZpZm9fd3Jp dGVfY29tcGxldGUsCit9OworCitzdGF0aWMgY29uc3Qgc3RydWN0IGZwZ2FfbWFuYWdlcl9vcHMg ZnBwX2ZwZ2FfbWdyX29wcyA9IHsKKwkuc3RhdGUJCT0gZnBwX2ZwZ2FfbWdyX3N0YXRlLAorCS53 cml0ZV9pbml0CT0gZnBwX2ZwZ2FfbWdyX3dyaXRlX2luaXQsCisJLndyaXRlCQk9IGZwcF9mcGdh X21ncl93cml0ZSwKKwkud3JpdGVfY29tcGxldGUJPSBmcHBfZnBnYV9tZ3Jfd3JpdGVfY29tcGxl dGUsCit9OworCitzdGF0aWMgc3NpemVfdCBjZmdfbW9kZV9zaG93KHN0cnVjdCBkZXZpY2UgKmRl diwgc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmF0dHIsCisJCQkgICAgIGNoYXIgKmJ1ZikKK3sK KwlzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2ID0gdG9fcGxhdGZvcm1fZGV2aWNlKGRldik7 CisJc3RydWN0IGZwZ2FfbWFuYWdlciAqbWdyID0gcGxhdGZvcm1fZ2V0X2RydmRhdGEocGRldik7 CisJc3RydWN0IGZwcF9mcGdhX21ncl9wcml2ICpwcml2ID0gbWdyLT5wcml2OworCisJcmV0dXJu IHNucHJpbnRmKGJ1ZiwgUEFHRV9TSVpFLCAiJXNcbiIsIHByaXYtPmNmZ19tb2RlKTsKK30KKwor c3RhdGljIHNzaXplX3QgY2ZnX21vZGVfc3RvcmUoc3RydWN0IGRldmljZSAqZGV2LCBzdHJ1Y3Qg ZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwKKwkJCSAgICAgIGNvbnN0IGNoYXIgKmJ1Ziwgc2l6ZV90 IGNvdW50KQoreworCXN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYgPSB0b19wbGF0Zm9ybV9k ZXZpY2UoZGV2KTsKKwlzdHJ1Y3QgZnBnYV9tYW5hZ2VyICptZ3IgPSBwbGF0Zm9ybV9nZXRfZHJ2 ZGF0YShwZGV2KTsKKwlzdHJ1Y3QgZnBwX2ZwZ2FfbWdyX3ByaXYgKnByaXYgPSBtZ3ItPnByaXY7 CisKKwlpZiAoIWNvdW50IHx8IGNvdW50ID4gc2l6ZW9mKHByaXYtPmNmZ19tb2RlKSkKKwkJcmV0 dXJuIC1FSU5WQUw7CisKKwlpZiAoIXN0cm5jbXAoYnVmLCAiZmlmbyIsIDQpKSB7CisJCXN0cm5j cHkocHJpdi0+Y2ZnX21vZGUsIGJ1Ziwgc2l6ZW9mKHByaXYtPmNmZ19tb2RlKSk7CisJCXByaXYt PmNmZ19tb2RlWzRdID0gMDsKKwkJcHJpdi0+b3BzID0gJmZwcF9tZ3JfZnQyNDVfZmlmb19vcHM7 CisJCWdwaW9kX2RpcmVjdGlvbl9vdXRwdXRfcmF3KHByaXYtPmNvbmZfZG9uZSwgMCk7CisJfSBl bHNlIGlmICghc3RybmNtcChidWYsICJiaXRiYW5nIiwgNykpIHsKKwkJc3RybmNweShwcml2LT5j ZmdfbW9kZSwgYnVmLCBzaXplb2YocHJpdi0+Y2ZnX21vZGUpKTsKKwkJcHJpdi0+Y2ZnX21vZGVb N10gPSAwOworCQlwcml2LT5vcHMgPSAmZnBwX21ncl9iaXRiYW5nX29wczsKKwkJZ3Bpb2RfZGly ZWN0aW9uX2lucHV0KHByaXYtPmNvbmZfZG9uZSk7CisJfSBlbHNlIHsKKwkJcmV0dXJuIC1FSU5W QUw7CisJfQorCisJcmV0dXJuIGNvdW50OworfQorCitzdGF0aWMgREVWSUNFX0FUVFJfUlcoY2Zn X21vZGUpOworCitzdGF0aWMgaW50IGZwcF9mcGdhX21ncl9wcm9iZShzdHJ1Y3QgcGxhdGZvcm1f ZGV2aWNlICpwZGV2KQoreworCXN0cnVjdCBkZXZpY2UgKmRldiA9ICZwZGV2LT5kZXY7CisJc3Ry dWN0IGZwcF9mcGdhX21ncl9wcml2ICpwcml2OworCXN0cnVjdCBmcGdhX21hbmFnZXIgKm1ncjsK KwlzdHJ1Y3QgZmlmb19mcHBfbWdyX3BsYXRmb3JtX2RhdGEgKnBkOworCWludCByZXQsIHJldHJp ZXMgPSBNQVhfUkVUUklFUzsKKwljaGFyIGlkX3N0cmluZ1s4XTsKKwl1OCBzdGF0dXMgPSAwOwor CisJcGQgPSBkZXYtPnBsYXRmb3JtX2RhdGE7CisJaWYgKCFwZCkgeworCQlkZXZfZXJyKGRldiwg Ik1pc3NpbmcgcGxhdGZvcm0gZGF0YS5cbiIpOworCQlyZXR1cm4gLUVJTlZBTDsKKwl9CisKKwlp ZiAoIXBkLT5vcHMgfHwKKwkgICAgIXBkLT5vcHMtPmJ1bGtfeGZlciB8fCAhcGQtPm9wcy0+Y3Ry bF94ZmVyIHx8CisJICAgICFwZC0+b3BzLT5yZWFkX2RhdGEgfHwgIXBkLT5vcHMtPndyaXRlX2Rh dGEgfHwKKwkgICAgIXBkLT5vcHMtPnNldF9iaXRtb2RlIHx8ICFwZC0+b3BzLT5zZXRfYmF1ZHJh dGUgfHwKKwkgICAgIXBkLT5vcHMtPmRpc2FibGVfYml0YmFuZykKKwkJcmV0dXJuIC1FSU5WQUw7 CisKKwlwcml2ID0gZGV2bV9remFsbG9jKGRldiwgc2l6ZW9mKCpwcml2KSwgR0ZQX0tFUk5FTCk7 CisJaWYgKCFwcml2KQorCQlyZXR1cm4gLUVOT01FTTsKKworCXByaXYtPmludGYgPSB0b191c2Jf aW50ZXJmYWNlKGRldi0+cGFyZW50KTsKKwlwcml2LT5pb3BzID0gcGQtPm9wczsKKworCXJldCA9 IHNzY2FuZihkZXZfbmFtZShkZXYtPnBhcmVudCksICIlcyIsIHByaXYtPnVzYl9kZXZfaWQpOwor CWlmIChyZXQgIT0gMSkgeworCQlkZXZfZXJyKGRldiwgIkNhbid0IGdldCBwYXJlbnQgZGV2aWNl IG5hbWU6ICVkXG4iLCByZXQpOworCQlyZXR1cm4gLUVOT0RFVjsKKwl9CisKKwlwcml2LT5wZGV2 ID0gcGRldjsKKwlwcml2LT5vcHMgPSAmZnBwX21ncl9mdDI0NV9maWZvX29wczsKKwlzdHJuY3B5 KHByaXYtPmNmZ19tb2RlLCAiZmlmbyIsIHNpemVvZihwcml2LT5jZmdfbW9kZSkpOworCisJcHJp di0+bmNvbmZpZyA9IGRldm1fZ3Bpb2RfZ2V0KGRldiwgIm5jb25maWciLCBHUElPRF9PVVRfTE9X KTsKKwlpZiAoSVNfRVJSKHByaXYtPm5jb25maWcpKSB7CisJCXJldCA9IFBUUl9FUlIocHJpdi0+ bmNvbmZpZyk7CisJCWRldl9lcnIoZGV2LCAiRmFpbGVkIHRvIGdldCBuY29uZmlnIGdwaW86ICVk XG4iLCByZXQpOworCQlyZXR1cm4gcmV0OworCX0KKworCXByaXYtPmNvbmZfZG9uZSA9IGRldm1f Z3Bpb2RfZ2V0KGRldiwgImNvbmZfZG9uZSIsIEdQSU9EX09VVF9MT1cpOworCWlmIChJU19FUlIo cHJpdi0+Y29uZl9kb25lKSkgeworCQlyZXQgPSBQVFJfRVJSKHByaXYtPmNvbmZfZG9uZSk7CisJ CWRldl9lcnIoZGV2LCAiRmFpbGVkIHRvIGdldCBjb25mX2RvbmUgZ3BpbzogJWRcbiIsIHJldCk7 CisJCWdvdG8gZXJyX2NmZzE7CisJfQorCisJcHJpdi0+YnVsa19idWYgPSBkZXZtX2ttYWxsb2Mo ZGV2LCBCVUxLX09VVF9CVUZfU1osCisJCQkJICAgICAgR0ZQX0tFUk5FTCB8IEdGUF9ETUEzMik7 CisJaWYgKCFwcml2LT5idWxrX2J1ZikgeworCQlyZXQgPSAtRU5PTUVNOworCQlnb3RvIGVycl9j ZmcyOworCX0KKworCXJldCA9IHByaXYtPmlvcHMtPnNldF9iaXRtb2RlKHByaXYtPmludGYsIDB4 ZmYsIEJJVE1PREVfU1lOQ0ZGKTsKKwlpZiAocmV0KQorCQlnb3RvIGVycl9jZmcyOworCisJLyog UmVhZCBzdGF0dXMgcmVnaXN0ZXIgZnJvbSBDUExEICovCisJZG8geworCQlyZXQgPSBmcHBfZnBn YV9tZ3JfcmVhZF9zdGF0dXMocHJpdiwgJnN0YXR1cyk7CisJCWlmICghcmV0KQorCQkJYnJlYWs7 CisJfSB3aGlsZSAoLS1yZXRyaWVzID4gMCk7CisKKwlpZiAoIXJldHJpZXMpIHsKKwkJcmV0ID0g LUVUSU1FRE9VVDsKKwkJZ290byBlcnJfY2ZnMjsKKwl9CisKKwlwcml2LT5yZXYgPSAoc3RhdHVz ICYgSU5fQk9BUkRfUkVWKSA/IEJPQVJEX1JFVkIgOiBCT0FSRF9SRVZBOworCisJaWYgKHByaXYt PnJldiA9PSBCT0FSRF9SRVZCKSB7CisJCXByaXYtPmFkZHJfc2VsID0gKHN0YXR1cyAmIElOX0FE RFJfU0VMRUNUKSA/CisJCQkJIEFERFJfU0VMRUNUX05DIDogQUREUl9TRUxFQ1RfR05EOworCQlp ZiAocHJpdi0+YWRkcl9zZWwgPT0gQUREUl9TRUxFQ1RfTkMpCisJCQlzdHJuY3B5KGlkX3N0cmlu ZywgInJpZ2h0Iiwgc2l6ZW9mKGlkX3N0cmluZykpOworCQllbHNlCisJCQlzdHJuY3B5KGlkX3N0 cmluZywgImxlZnQiLCBzaXplb2YoaWRfc3RyaW5nKSk7CisJfSBlbHNlIHsKKwkJcHJpdi0+YWRk cl9zZWwgPSBBRERSX1NFTEVDVF9JTlZBTElEOworCQlzdHJuY3B5KGlkX3N0cmluZywgInNpbmds ZSIsIHNpemVvZihpZF9zdHJpbmcpKTsKKwl9CisKKwlkZXZfaW5mbyhkZXYsICJCb2FyZCBSZXYg JWQsIEFkZHIgU2VsICVkXG4iLCBwcml2LT5yZXYsIHByaXYtPmFkZHJfc2VsKTsKKworCS8qIFVz ZSB1bmlxdWUgYm9hcmQgSUQgYW5kIFVTQiBidXMvcG9ydCBpbiBGUEdBIG1hbmFnZXIgbmFtZSAq LworCXNucHJpbnRmKHByaXYtPmZwZ2FfbWdyX25hbWUsIHNpemVvZihwcml2LT5mcGdhX21ncl9u YW1lKSwKKwkJICJmdGRpLWZwcC1mcGdhLW1nciAlcyAlcyIsIGlkX3N0cmluZywgcHJpdi0+dXNi X2Rldl9pZCk7CisKKwltZ3IgPSBkZXZtX2ZwZ2FfbWdyX2NyZWF0ZShkZXYsIHByaXYtPmZwZ2Ff bWdyX25hbWUsCisJCQkJICAgJmZwcF9mcGdhX21ncl9vcHMsIHByaXYpOworCWlmICghbWdyKQor CQlnb3RvIGVycl9jZmcyOworCisJcGxhdGZvcm1fc2V0X2RydmRhdGEocGRldiwgbWdyKTsKKwor CXJldCA9IGZwZ2FfbWdyX3JlZ2lzdGVyKG1ncik7CisJaWYgKHJldCkgeworCQlkZXZfZXJyKGRl diwgInVuYWJsZSB0byByZWdpc3RlciBGUEdBIG1hbmFnZXJcbiIpOworCQlnb3RvIGVycl9jZmcy OworCX0KKworCXJldCA9IGRldmljZV9jcmVhdGVfZmlsZShkZXYsICZkZXZfYXR0cl9jZmdfbW9k ZSk7CisJaWYgKHJldCkKKwkJZGV2X3dhcm4oZGV2LCAiQ2FuJ3QgY3JlYXRlIGNmZ19tb2RlIGlu dGVyZmFjZSAlZFxuIiwgcmV0KTsKKworCXJldHVybiAwOworCitlcnJfY2ZnMjoKKwlkZXZtX2dw aW9kX3B1dChkZXYsIHByaXYtPmNvbmZfZG9uZSk7CitlcnJfY2ZnMToKKwlkZXZtX2dwaW9kX3B1 dChkZXYsIHByaXYtPm5jb25maWcpOworCXJldHVybiByZXQ7Cit9CisKK3N0YXRpYyBpbnQgZnBw X2ZwZ2FfbWdyX3JlbW92ZShzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2KQoreworCXN0cnVj dCBmcGdhX21hbmFnZXIgKm1nciA9IHBsYXRmb3JtX2dldF9kcnZkYXRhKHBkZXYpOworCXN0cnVj dCBmcHBfZnBnYV9tZ3JfcHJpdiAqcHJpdiA9IG1nci0+cHJpdjsKKworCWRldmljZV9yZW1vdmVf ZmlsZSgmcGRldi0+ZGV2LCAmZGV2X2F0dHJfY2ZnX21vZGUpOworCWZwZ2FfbWdyX3VucmVnaXN0 ZXIobWdyKTsKKwlkZXZtX2dwaW9kX3B1dCgmcGRldi0+ZGV2LCBwcml2LT5jb25mX2RvbmUpOwor CWRldm1fZ3Bpb2RfcHV0KCZwZGV2LT5kZXYsIHByaXYtPm5jb25maWcpOworCXJldHVybiAwOwor fQorCitzdGF0aWMgc3RydWN0IHBsYXRmb3JtX2RyaXZlciBmcHBfZnBnYV9tZ3JfZHJpdmVyID0g eworCS5kcml2ZXIubmFtZQk9ICJmdGRpLWZpZm8tZnBwLW1nciIsCisJLnByb2JlCQk9IGZwcF9m cGdhX21ncl9wcm9iZSwKKwkucmVtb3ZlCQk9IGZwcF9mcGdhX21ncl9yZW1vdmUsCit9OworCitt b2R1bGVfcGxhdGZvcm1fZHJpdmVyKGZwcF9mcGdhX21ncl9kcml2ZXIpOworCitNT0RVTEVfQUxJ QVMoInBsYXRmb3JtOmZ0ZGktZmlmby1mcHAtbWdyIik7CitNT0RVTEVfQVVUSE9SKCJBbmF0b2xp aiBHdXN0c2NoaW4gPGFndXN0QGRlbnguZGU+Iik7CitNT0RVTEVfREVTQ1JJUFRJT04oIkZUMjMy SCBCaXRiYW5nL0ZUMjQ1LUZJRk8gRlBQIEZQR0EgTWFuYWdlciBEcml2ZXIiKTsKK01PRFVMRV9M SUNFTlNFKCJHUEwgdjIiKTsK