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 17110C4360F for ; Thu, 21 Feb 2019 20:25:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 982502083B for ; Thu, 21 Feb 2019 20:25:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726805AbfBUUZY (ORCPT ); Thu, 21 Feb 2019 15:25:24 -0500 Received: from mail-out.m-online.net ([212.18.0.9]:40661 "EHLO mail-out.m-online.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726075AbfBUUZT (ORCPT ); Thu, 21 Feb 2019 15:25:19 -0500 Received: from frontend01.mail.m-online.net (unknown [192.168.8.182]) by mail-out.m-online.net (Postfix) with ESMTP id 4455Yz1HRbz1qxQ5; Thu, 21 Feb 2019 21:25:11 +0100 (CET) Received: from localhost (dynscan1.mnet-online.de [192.168.6.70]) by mail.m-online.net (Postfix) with ESMTP id 4455Yz0VDrz1qswn; Thu, 21 Feb 2019 21:25:11 +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 ie4-QGS8udEJ; Thu, 21 Feb 2019 21:25:07 +0100 (CET) X-Auth-Info: yetTfUJFsOxCTAaJHYKCOfuLdxN7udPVqFy1xFdehqo= 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:07 +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 1/3] usb: misc: add driver for FT232H based FPGA configuration devices Date: Thu, 21 Feb 2019 21:25:04 +0100 Message-Id: <20190221202506.17744-2-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 USB interface driver for ARRI FPGA configuration devices based on FTDI FT232H chip. Depending on USB PID the driver registers different platform devices describing an FPGA configuration interface. One FPGA configuration interface type is the usual SPI bus with additional control and status GPIOs. For this interface type the FTDI MPSSE mode is utilized to support SPI bus and GPIO-L/H pins for SPI bus chipselect and SPI slave device I/O. Subsequent patch adds an MPSSE SPI controller driver for USB-SPI bus support. The actual FPGA configuration driver for SPI bus is already available in the FPGA manager framework (altera-ps-spi module). Another FPGA configuration interface type is the FT245 FIFO (connected via CPLD) with additional control and status GPIOs on FT232H ACBUS. This interface is used to configure FPGAs using Altera fast passive parallel (FPP) interface. Subsequent patch will add an FPP FPGA manager driver for it. The FTDI protocol code and prototypes was borrowed from libftdi. Signed-off-by: Anatolij Gustschin --- MAINTAINERS | 8 + drivers/usb/misc/Kconfig | 10 + drivers/usb/misc/Makefile | 1 + drivers/usb/misc/ft232h-intf.c | 1467 +++++++++++++++++++++++++++++++ include/linux/usb/ft232h-intf.h | 206 +++++ 5 files changed, 1692 insertions(+) create mode 100644 drivers/usb/misc/ft232h-intf.c create mode 100644 include/linux/usb/ft232h-intf.h diff --git a/MAINTAINERS b/MAINTAINERS index 8b53eb3db271..2a489b63d138 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15968,6 +15968,14 @@ S: Maintained F: Documentation/usb/acm.txt F: drivers/usb/class/cdc-acm.* +USB ARRI FPGA CONFIGURATION ADAPTER DRIVER +M: Anatolij Gustschin +L: linux-usb@vger.kernel.org +S: Maintained +F: drivers/usb/misc/ft232h-intf.c +F: drivers/spi/spi-ftdi-mpsse.c +F: include/linux/usb/ft232h-intf.h + USB AR5523 WIRELESS DRIVER M: Pontus Fuchs L: linux-wireless@vger.kernel.org diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index be04c117fe80..439efc543bb3 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -276,3 +276,13 @@ config USB_CHAOSKEY To compile this driver as a module, choose M here: the module will be called chaoskey. + +config USB_FT232H_INTF + tristate "FTDI FT232H FPGA configuration interface driver" + depends on GPIOLIB + help + Enable driver support for the FT232H based USB-GPIO/SPI/FIFO + interface adapter for FPGA configuration. Additional drivers + such as spi-ftdi-mpsse, altera-ps-spi, ftdi-fifo-fpp and + fpga-mgr must be enabled in order to use the functionality of + the device. diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 109f54f5b9aa..af935effb019 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_USB_CYTHERM) += cytherm.o obj-$(CONFIG_USB_EMI26) += emi26.o obj-$(CONFIG_USB_EMI62) += emi62.o obj-$(CONFIG_USB_EZUSB_FX2) += ezusb.o +obj-$(CONFIG_USB_FT232H_INTF) += ft232h-intf.o obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.o obj-$(CONFIG_USB_IDMOUSE) += idmouse.o obj-$(CONFIG_USB_IOWARRIOR) += iowarrior.o diff --git a/drivers/usb/misc/ft232h-intf.c b/drivers/usb/misc/ft232h-intf.c new file mode 100644 index 000000000000..6f99257b9fbd --- /dev/null +++ b/drivers/usb/misc/ft232h-intf.c @@ -0,0 +1,1467 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * FTDI FT232H interface driver for ARRI FPGA configuration + * + * Copyright (C) 2017 - 2018 DENX Software Engineering + * Anatolij Gustschin + * + * Figure: FT232H, FPGA Devices and Drivers Relationship + * + * +-------------+ + * | | + * | STRATIX V |PS-SPI FT245 FIFO & GPIO + * | +-----+ +-------------------+ + * | on Board 1 | + + | + * | | +----+---+ + * | PCIe | ADBUS&ACBUS | CPLD | + * +---+---------+ Connection Options +----+---+ + * ^ (MPSSE or FIFO&GPIO) | + * + + +------+-------+ + * altera-cvp +-----------+----------+ | FPP | + * | FT232H | | | + * | 0x0403:0x7148 | | ARRIA 10 | + * | 0x0403:0x7149 | | | + * +----------+-----------+ | on Board 2 | + * | | | + * +-----------+------------+ | PCIe | + * creates | ft232h-intf (USB misc) | +----------+---+ + * platform | bulk/ctrl xfer | ^ + * devices |ACBUS GPIO Ctrl (0x7148)| | + * below |MPSSE GPIO Ctrl (0x7149)| | + * +-------+-------+--------+ | + * | | | + * for +----+ +------+ for | + * PID 0x7149 | | PID 0x7148 | + * +---------+--------+ +-------+---------+ | + * | ftdi-mpsse-spi | | | | + * | altera-ps-spi in | |ftdi-fifo-fpp-mgr| | + * | spi_board_info | | | | + * +---------+--------+ +--------+--------+ | + * ^ ^ | + * Drivers: | | | + * + | | + * MPSSE SPI master(spi-ftdi-mpsse) | + + * ^ | | + * | + + + * altera-ps-spi ftdi-fifo-fpp altera-cvp + * FPGA Manager FPGA Manager FPGA Manager + * + * + * When using your custom USB product ID, this FT232H interface driver + * also allows to register the GPIO controller for CBUS pins or for + * MPSSE GPIO pins. Below are examples how to use the driver as CBUS- + * or MPSSE-GPIO controller. + * + * For CBUS-GPIOs add new entry with your PID to ft232h_intf_table[]: + * static const struct ft232h_intf_info ftdi_cbus_gpio_intf_info = { + * .use_cbus_gpio_ctrl = true, + * }; + * { USB_DEVICE(FTDI_VID, PID), + * .driver_info = (kernel_ulong_t)&ftdi_cbus_gpio_intf_info }, + * + * For MPSSE-GPIO add new entry with your PID to ft232h_intf_table[]: + * static const struct ft232h_intf_info ftdi_mpsse_gpio_intf_info = { + * .use_mpsse_gpio_ctrl = true, + * }; + * { USB_DEVICE(FTDI_VID, PID), + * .driver_info = (kernel_ulong_t)&ftdi_mpsse_gpio_intf_info }, + * + * With custom USB product IDs it is also possible to use FT232H SPI bus + * with different SPI slave devices attached (e.g. SPI-NOR flash chips, + * spidev, etc.). Example below shows how to add a bus with two SPI slave + * devices for your USB PID: + * + * static struct spi_board_info ftdi_spi_bus_info[] = { + * { + * .modalias = "w25q32", + * .mode = SPI_MODE_0, + * .max_speed_hz = 60000000, + * .bus_num = 0, + * .chip_select = 0, // TCK/SK at ADBUS0 + * }, + * { + * .modalias = "spidev", + * .mode = SPI_MODE_0 | SPI_LSB_FIRST | SPI_CS_HIGH, + * .max_speed_hz = 30000000, + * .bus_num = 0, + * .chip_select = 5, // GPIOH0 at ACBUS0 + * }, + * }; + * + * static const struct mpsse_spi_platform_data ftdi_spi_bus_plat_data = { + * .ops = &ft232h_intf_ops, + * .spi_info = ftdi_spi_bus_info, + * .spi_info_len = ARRAY_SIZE(ftdi_spi_bus_info), + * }; + * + * static const struct ft232h_intf_info ftdi_spi_bus_intf_info = { + * .probe = ft232h_intf_spi_probe, + * .remove = ft232h_intf_spi_remove, + * .plat_data = &ftdi_spi_bus_plat_data, + * }; + * { USB_DEVICE(FTDI_VID, YOUR_PID), + * .driver_info = (kernel_ulong_t)&ftdi_spi_bus_intf_info }, + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ft232h_intf_priv { + struct usb_interface *intf; + struct usb_device *udev; + struct mutex io_mutex; /* sync I/O with disconnect */ + struct mutex ops_mutex; + int bitbang_enabled; + int id; + int index; + u8 bulk_in; + u8 bulk_out; + size_t bulk_in_sz; + void *bulk_in_buf; + + const struct usb_device_id *usb_dev_id; + struct ft232h_intf_info *info; + struct platform_device *fifo_pdev; + struct platform_device *spi_pdev; + struct gpiod_lookup_table *lookup_fifo; + struct gpiod_lookup_table *lookup_cs; + + struct gpio_chip cbus_gpio; + const char *cbus_gpio_names[4]; + u8 cbus_pin_offsets[4]; + u8 cbus_mask; + u8 pinbuf[4]; + u8 eeprom[FTDI_MAX_EEPROM_SIZE]; + + struct gpio_chip mpsse_gpio; + u8 gpiol_mask; + u8 gpioh_mask; + u8 gpiol_dir; + u8 gpioh_dir; + u8 tx_buf[4]; +}; + +/* Device info struct used for device specific init. */ +struct ft232h_intf_info { + unsigned int use_cbus_gpio_ctrl; + unsigned int use_mpsse_gpio_ctrl; + int (*probe)(struct usb_interface *intf, const void *plat_data); + int (*remove)(struct usb_interface *intf); + const void *plat_data; /* optional, passed to probe() */ +}; + +static DEFINE_IDA(ftdi_devid_ida); + +/* Use baudrate calculation borrowed from libftdi */ +static unsigned int ftdi_to_clkbits(unsigned int baudrate, unsigned int clk, + unsigned int clk_div, + unsigned int *encoded_divisor) +{ + static const char frac_code[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; + unsigned int best_baud = 0; + unsigned int best_div; + + if (baudrate >= clk / clk_div) { + *encoded_divisor = 0; + best_baud = clk / clk_div; + } else if (baudrate >= clk / (clk_div + clk_div / 2)) { + *encoded_divisor = 1; + best_baud = clk / (clk_div + clk_div / 2); + } else if (baudrate >= clk / (2 * clk_div)) { + *encoded_divisor = 2; + best_baud = clk / (2 * clk_div); + } else { + /* + * Divide by 16 to have 3 fractional bits and + * one bit for rounding + */ + best_div = DIV_ROUND_CLOSEST(clk * 8 / clk_div, baudrate); + + if (best_div > 0x20000) + best_div = 0x1ffff; + + best_baud = DIV_ROUND_CLOSEST(clk * 8 / clk_div, best_div); + + *encoded_divisor = (best_div >> 3) | + (frac_code[best_div & 0x7] << 14); + } + return best_baud; +} + +#define H_CLK 120000000 +#define C_CLK 48000000 +static int ftdi_convert_baudrate(struct ft232h_intf_priv *priv, int baud, + u16 *value, u16 *index) +{ + unsigned int encoded_divisor = 0; + unsigned int best_baud; + + if (baud <= 0) + return -EINVAL; + + /* + * On H Devices, use 12000000 baudrate when possible. + * We have a 14 bit divisor, a 1 bit divisor switch (10 or 16), + * three fractional bits and a 120 MHz clock. Assume AN_120 + * "Sub-integer divisors between 0 and 2 are not allowed" holds + * for DIV/10 CLK too, so /1, /1.5 and /2 can be handled the same + */ + if (baud * 10 > H_CLK / 0x3fff) { + best_baud = ftdi_to_clkbits(baud, H_CLK, 10, &encoded_divisor); + encoded_divisor |= 0x20000; /* switch on CLK/10 */ + } else { + best_baud = ftdi_to_clkbits(baud, C_CLK, 16, &encoded_divisor); + } + + if (!best_baud) { + pr_err("Invalid baudrate: %d\n", baud); + return -EINVAL; + } + + /* Check within tolerance (about 5%) */ + if ((best_baud * 2 < baud) || + (best_baud < baud + ? (best_baud * 21 < baud * 20) + : (baud * 21 < best_baud * 20))) { + pr_err("Unsupported baudrate.\n"); + return -EINVAL; + } + + /* Split into "value" and "index" values */ + *value = (u16)(encoded_divisor & 0xffff); + *index = (u16)(((encoded_divisor >> 8) & 0xff00) | priv->index); + + dev_dbg(&priv->intf->dev, "best baud %u, v/i: %d, %d\n", + best_baud, *value, *index); + return best_baud; +} + +/* + * ftdi_ctrl_xfer - FTDI control endpoint transfer + * @intf: USB interface pointer + * @desc: pointer to descriptor struct for control transfer + * + * Return: + * Return: If successful, the number of bytes transferred. Otherwise, + * a negative error number. + */ +static int ftdi_ctrl_xfer(struct usb_interface *intf, struct ctrl_desc *desc) +{ + struct ft232h_intf_priv *priv = usb_get_intfdata(intf); + struct usb_device *udev = priv->udev; + unsigned int pipe; + int ret; + + mutex_lock(&priv->io_mutex); + if (!priv->intf) { + ret = -ENODEV; + goto exit; + } + + if (!desc->data && desc->size) + desc->data = priv->bulk_in_buf; + + if (desc->dir_out) + pipe = usb_sndctrlpipe(udev, 0); + else + pipe = usb_rcvctrlpipe(udev, 0); + + ret = usb_control_msg(udev, pipe, desc->request, desc->requesttype, + desc->value, desc->index, desc->data, desc->size, + desc->timeout); + if (ret < 0) + dev_dbg(&udev->dev, "ctrl msg failed: %d\n", ret); +exit: + mutex_unlock(&priv->io_mutex); + return ret; +} + +/* + * ftdi_bulk_xfer - FTDI bulk endpoint transfer + * @intf: USB interface pointer + * @desc: pointer to descriptor struct for bulk-in or bulk-out transfer + * + * Return: + * If successful, 0. Otherwise a negative error number. The number of + * actual bytes transferred will be stored in the @desc->act_len field + * of the descriptor struct. + */ +static int ftdi_bulk_xfer(struct usb_interface *intf, struct bulk_desc *desc) +{ + struct ft232h_intf_priv *priv = usb_get_intfdata(intf); + struct usb_device *udev = priv->udev; + unsigned int pipe; + int ret; + + mutex_lock(&priv->io_mutex); + if (!priv->intf) { + ret = -ENODEV; + goto exit; + } + + if (desc->dir_out) + pipe = usb_sndbulkpipe(udev, priv->bulk_out); + else + pipe = usb_rcvbulkpipe(udev, priv->bulk_in); + + ret = usb_bulk_msg(udev, pipe, desc->data, desc->len, + &desc->act_len, desc->timeout); + if (ret) + dev_dbg(&udev->dev, "bulk msg failed: %d\n", ret); + +exit: + mutex_unlock(&priv->io_mutex); + return ret; +} + +/* + * ftdi_set_baudrate - set the device baud rate + * @intf: USB interface pointer + * @baudrate: baud rate value to set + * + * Return: If successful, 0. Otherwise a negative error number. + */ +static int ftdi_set_baudrate(struct usb_interface *intf, int baudrate) +{ + struct ft232h_intf_priv *priv = usb_get_intfdata(intf); + struct ctrl_desc desc; + u16 index, value; + int ret; + + if (priv->bitbang_enabled) + baudrate *= 4; + + ret = ftdi_convert_baudrate(priv, baudrate, &value, &index); + if (ret < 0) + return ret; + + desc.dir_out = true; + desc.request = FTDI_SIO_SET_BAUDRATE_REQUEST; + desc.requesttype = USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT; + desc.value = value; + desc.index = index; + desc.data = NULL; + desc.size = 0; + desc.timeout = USB_CTRL_SET_TIMEOUT; + + ret = ftdi_ctrl_xfer(intf, &desc); + if (ret < 0) { + dev_dbg(&intf->dev, "failed to set baudrate: %d\n", ret); + return ret; + } + + return 0; +} + +/* + * ftdi_read_data - read from FTDI bulk-in endpoint + * @intf: USB interface pointer + * @buf: pointer to data buffer + * @len: length in bytes of the data to read + * + * The two modem status bytes transferred in every read will + * be removed and will not appear in the data buffer. + * + * Return: + * If successful, the number of data bytes received (can be 0). + * Otherwise, a negative error number. + */ +static int ftdi_read_data(struct usb_interface *intf, void *buf, size_t len) +{ + struct ft232h_intf_priv *priv = usb_get_intfdata(intf); + struct bulk_desc desc; + int ret; + + desc.act_len = 0; + desc.dir_out = false; + desc.data = priv->bulk_in_buf; + /* Device sends 2 additional status bytes, read at least len + 2 */ + desc.len = min_t(size_t, len + 2, priv->bulk_in_sz); + desc.timeout = FTDI_USB_READ_TIMEOUT; + + ret = ftdi_bulk_xfer(intf, &desc); + if (ret) + return ret; + + /* Only status bytes and no data? */ + if (desc.act_len <= 2) + return 0; + + /* Skip first two status bytes */ + ret = desc.act_len - 2; + if (ret > len) + ret = len; + memcpy(buf, desc.data + 2, ret); + return ret; +} + +/* + * ftdi_write_data - write to FTDI bulk-out endpoint + * @intf: USB interface pointer + * @buf: pointer to data buffer + * @len: length in bytes of the data to send + * + * Return: + * If successful, the number of bytes transferred. Otherwise a negative + * error number. + */ +static int ftdi_write_data(struct usb_interface *intf, + const char *buf, size_t len) +{ + struct bulk_desc desc; + int ret; + + desc.act_len = 0; + desc.dir_out = true; + desc.data = (char *)buf; + desc.len = len; + desc.timeout = FTDI_USB_WRITE_TIMEOUT; + + ret = ftdi_bulk_xfer(intf, &desc); + if (ret < 0) + return ret; + + return desc.act_len; +} + +/* + * ftdi_set_bitmode - configure bitbang mode + * @intf: USB interface pointer + * @bitmask: line configuration bitmask + * @mode: bitbang mode to set + * + * Return: + * If successful, 0. Otherwise a negative error number. + */ +static int ftdi_set_bitmode(struct usb_interface *intf, unsigned char bitmask, + unsigned char mode) +{ + struct ft232h_intf_priv *priv = usb_get_intfdata(intf); + struct ctrl_desc desc; + int ret; + + desc.dir_out = true; + desc.data = NULL; + desc.request = FTDI_SIO_SET_BITMODE_REQUEST; + desc.requesttype = USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT; + desc.index = 1; + desc.value = (mode << 8) | bitmask; + desc.size = 0; + desc.timeout = USB_CTRL_SET_TIMEOUT; + + ret = ftdi_ctrl_xfer(intf, &desc); + if (ret < 0) + return ret; + + switch (mode) { + case BITMODE_BITBANG: + case BITMODE_CBUS: + case BITMODE_SYNCBB: + case BITMODE_SYNCFF: + priv->bitbang_enabled = 1; + break; + case BITMODE_MPSSE: + case BITMODE_RESET: + default: + priv->bitbang_enabled = 0; + break; + } + + return 0; +} + +/* + * ftdi_disable_bitbang - disable bitbang mode + * @intf: USB interface pointer + * + * Return: + * If successful, 0. Otherwise a negative error number. + */ +static int ftdi_disable_bitbang(struct usb_interface *intf) +{ + int ret; + + ret = ftdi_set_bitmode(intf, 0, BITMODE_RESET); + if (ret < 0) { + dev_dbg(&intf->dev, "disable bitbang failed: %d\n", ret); + return ret; + } + + return 0; +} + +static int ftdi_read_eeprom(struct ft232h_intf_priv *priv) +{ + struct ctrl_desc desc; + unsigned int i; + int ret; + + desc.dir_out = false; + desc.request = FTDI_SIO_READ_EEPROM_REQUEST; + desc.requesttype = USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN; + desc.value = 0; + desc.size = 2; + desc.timeout = USB_CTRL_GET_TIMEOUT; + + for (i = 0; i < FTDI_MAX_EEPROM_SIZE / 2; i++) { + desc.index = i; + desc.data = &priv->eeprom[i * 2]; + + ret = ftdi_ctrl_xfer(priv->intf, &desc); + if (ret < 0) { + dev_dbg(&priv->intf->dev, "EEPROM read failed: %d\n", + ret); + return ret; + } + } + + print_hex_dump_debug("EEPROM: ", DUMP_PREFIX_OFFSET, 16, 1, + priv->eeprom, sizeof(priv->eeprom), 1); + return 0; +} + +/* + * ACBUS GPIO functions + */ +static const char *ftdi_acbus_names[5] = { + "ACBUS5", "ACBUS6", NULL, "ACBUS8", "ACBUS9" +}; + +static int ftdi_cbus_gpio_read_pins(struct ft232h_intf_priv *priv, + unsigned char *pins) +{ + struct gpio_chip *chip = &priv->cbus_gpio; + struct ctrl_desc desc; + int ret; + + desc.dir_out = false; + desc.request = FTDI_SIO_READ_PINS_REQUEST; + desc.requesttype = USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN; + desc.value = 0; + desc.index = 1; + desc.data = &priv->pinbuf[0]; + desc.size = 1; + desc.timeout = USB_CTRL_GET_TIMEOUT; + + ret = ftdi_ctrl_xfer(priv->intf, &desc); + if (ret < 0) { + dev_dbg(chip->parent, "failed to get pin values: %d\n", ret); + return ret; + } + + *pins = priv->pinbuf[0]; + return 0; +} + +static inline void ftdi_cbus_init_gpio_data(struct ft232h_intf_priv *priv, + int gpio_num, int cbus_num) +{ + switch (cbus_num) { + case 5: + case 6: + priv->cbus_pin_offsets[gpio_num] = cbus_num - 5; + break; + case 8: + case 9: + priv->cbus_pin_offsets[gpio_num] = cbus_num - 6; + break; + default: + return; + } + + priv->cbus_gpio_names[gpio_num] = ftdi_acbus_names[cbus_num - 5]; +} + +static int ftdi_cbus_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct ft232h_intf_priv *priv = gpiochip_get_data(chip); + unsigned int offs; + int ret; + u8 pins = 0; + + ret = ftdi_cbus_gpio_read_pins(priv, &pins); + if (ret) + return ret; + + offs = priv->cbus_pin_offsets[offset]; + + return !!(pins & BIT(offs)); +} + +static void ftdi_cbus_gpio_set(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct ft232h_intf_priv *priv = gpiochip_get_data(chip); + unsigned int offs; + int ret; + + offs = priv->cbus_pin_offsets[offset]; + + if (value) + priv->cbus_mask |= BIT(offs); + else + priv->cbus_mask &= ~BIT(offs); + + ret = ftdi_set_bitmode(priv->intf, priv->cbus_mask, BITMODE_CBUS); + if (ret < 0) + dev_dbg(chip->parent, "setting pin value failed: %d\n", ret); +} + +static int ftdi_cbus_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct ft232h_intf_priv *priv = gpiochip_get_data(chip); + unsigned int offs; + + offs = priv->cbus_pin_offsets[offset]; + /* Direction bits are in the upper nibble */ + priv->cbus_mask &= ~(BIT(offs) << 4); + + return ftdi_set_bitmode(priv->intf, priv->cbus_mask, BITMODE_CBUS); +} + +static int ftdi_cbus_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct ft232h_intf_priv *priv = gpiochip_get_data(chip); + unsigned int offs; + + offs = priv->cbus_pin_offsets[offset]; + priv->cbus_mask |= BIT(offs) << 4; + + if (value) + priv->cbus_mask |= BIT(offs); + else + priv->cbus_mask &= ~BIT(offs); + + return ftdi_set_bitmode(priv->intf, priv->cbus_mask, BITMODE_CBUS); +} + +static int ft232h_intf_add_cbus_gpio(struct ft232h_intf_priv *priv) +{ + struct device *dev = &priv->intf->dev; + char **names, *label; + int ngpio = 0; + int i, ret; + u8 val; + + ret = ftdi_read_eeprom(priv); + if (ret < 0) + return ret; + + /* Check if I/O mode is enabled for supported pins 5, 6, 8, 9 */ + for (i = 5; i < 10; i++) { + val = priv->eeprom[0x18 + i / 2] >> (i % 2 ? 4 : 0); + if ((val & 0x0f) == FTDI_232H_CBUS_IOMODE) { + dev_dbg(dev, "gpio-%d @ ACBUS%d\n", + priv->cbus_gpio.ngpio, i); + priv->cbus_gpio.ngpio++; + ftdi_cbus_init_gpio_data(priv, ngpio++, i); + } + } + + if (!priv->cbus_gpio.ngpio) { + dev_warn(dev, "I/O mode disabled in EEPROM\n"); + return -ENODEV; + } + + label = devm_kasprintf(dev, GFP_KERNEL, "ftdi-cbus-gpio.%d", priv->id); + if (!label) + return -ENOMEM; + + priv->cbus_gpio.label = label; + priv->cbus_gpio.parent = dev; + priv->cbus_gpio.owner = THIS_MODULE; + priv->cbus_gpio.base = -1; + priv->cbus_gpio.can_sleep = true; + priv->cbus_gpio.set = ftdi_cbus_gpio_set; + priv->cbus_gpio.get = ftdi_cbus_gpio_get; + priv->cbus_gpio.direction_input = ftdi_cbus_gpio_direction_input; + priv->cbus_gpio.direction_output = ftdi_cbus_gpio_direction_output; + + names = devm_kcalloc(dev, priv->cbus_gpio.ngpio, sizeof(char *), + GFP_KERNEL); + if (!names) + return -ENOMEM; + + for (i = 0; i < priv->cbus_gpio.ngpio; i++) { + if (!priv->cbus_gpio_names[i]) + continue; + names[i] = devm_kasprintf(dev, GFP_KERNEL, "cbus.%d-%s", + priv->id, priv->cbus_gpio_names[i]); + if (!names[i]) + return -ENOMEM; + } + + priv->cbus_gpio.names = (const char *const *)names; + + ret = devm_gpiochip_add_data(dev, &priv->cbus_gpio, priv); + if (ret) { + dev_warn(dev, "failed to add CBUS gpiochip: %d\n", ret); + return ret; + } + + dev_info(dev, "using %d CBUS pins\n", priv->cbus_gpio.ngpio); + return 0; +} + +/* + * MPSSE CS and GPIO-L/-H support + */ +#define SET_BITS_LOW 0x80 +#define GET_BITS_LOW 0x81 +#define SET_BITS_HIGH 0x82 +#define GET_BITS_HIGH 0x83 + +static int ftdi_mpsse_get_port_pins(struct ft232h_intf_priv *priv, bool low) +{ + struct device *dev = &priv->intf->dev; + int ret, tout = 10; + u8 rxbuf[4]; + + if (low) + priv->tx_buf[0] = GET_BITS_LOW; + else + priv->tx_buf[0] = GET_BITS_HIGH; + + ret = ftdi_write_data(priv->intf, priv->tx_buf, 1); + if (ret < 0) { + dev_dbg_ratelimited(dev, "Writing port pins cmd failed: %d\n", + ret); + return ret; + } + + rxbuf[0] = 0; + do { + usleep_range(5000, 5200); + ret = ftdi_read_data(priv->intf, rxbuf, 1); + tout--; + if (!tout) { + dev_err(dev, "Timeout when getting port pins\n"); + return -ETIMEDOUT; + } + } while (ret == 0); + + if (ret < 0) + return ret; + + if (ret != 1) + return -EINVAL; + + if (low) + priv->gpiol_mask = rxbuf[0]; + else + priv->gpioh_mask = rxbuf[0]; + + return 0; +} + +static int ftdi_mpsse_set_port_pins(struct ft232h_intf_priv *priv, bool low) +{ + struct device *dev = &priv->intf->dev; + int ret; + + if (low) { + priv->tx_buf[0] = SET_BITS_LOW; + priv->tx_buf[1] = priv->gpiol_mask; + priv->tx_buf[2] = priv->gpiol_dir; + } else { + priv->tx_buf[0] = SET_BITS_HIGH; + priv->tx_buf[1] = priv->gpioh_mask; + priv->tx_buf[2] = priv->gpioh_dir; + } + + ret = ftdi_write_data(priv->intf, priv->tx_buf, 3); + if (ret < 0) { + dev_dbg_ratelimited(dev, "Failed to set GPIO pins: %d\n", + ret); + return ret; + } + + return 0; +} + +static int ftdi_mpsse_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct ft232h_intf_priv *priv = gpiochip_get_data(chip); + int ret, val; + bool low; + + mutex_lock(&priv->io_mutex); + if (!priv->intf) { + mutex_unlock(&priv->io_mutex); + return -ENODEV; + } + mutex_unlock(&priv->io_mutex); + + dev_dbg(chip->parent, "%s: offset %d\n", __func__, offset); + + low = offset < 5; + + mutex_lock(&priv->ops_mutex); + + ret = ftdi_mpsse_get_port_pins(priv, low); + if (ret < 0) { + mutex_unlock(&priv->ops_mutex); + return ret; + } + + if (low) + val = priv->gpiol_mask & (BIT(offset) << 3); + else + val = priv->gpioh_mask & BIT(offset - 5); + + mutex_unlock(&priv->ops_mutex); + + return !!val; +} + +static void ftdi_mpsse_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct ft232h_intf_priv *priv = gpiochip_get_data(chip); + bool low; + + mutex_lock(&priv->io_mutex); + if (!priv->intf) { + mutex_unlock(&priv->io_mutex); + return; + } + mutex_unlock(&priv->io_mutex); + + dev_dbg(chip->parent, "%s: offset %d, val %d\n", + __func__, offset, value); + + mutex_lock(&priv->ops_mutex); + + if (offset < 5) { + low = true; + if (value) + priv->gpiol_mask |= (BIT(offset) << 3); + else + priv->gpiol_mask &= ~(BIT(offset) << 3); + } else { + low = false; + if (value) + priv->gpioh_mask |= BIT(offset - 5); + else + priv->gpioh_mask &= ~BIT(offset - 5); + } + + ftdi_mpsse_set_port_pins(priv, low); + + mutex_unlock(&priv->ops_mutex); +} + +static int ftdi_mpsse_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct ft232h_intf_priv *priv = gpiochip_get_data(chip); + bool low; + int ret; + + mutex_lock(&priv->io_mutex); + if (!priv->intf) { + mutex_unlock(&priv->io_mutex); + return -ENODEV; + } + mutex_unlock(&priv->io_mutex); + + dev_dbg(chip->parent, "%s: offset %d\n", __func__, offset); + + mutex_lock(&priv->ops_mutex); + + if (offset < 5) { + low = true; + priv->gpiol_dir &= ~(BIT(offset) << 3); + } else { + low = false; + priv->gpioh_dir &= ~BIT(offset - 5); + } + + ret = ftdi_mpsse_set_port_pins(priv, low); + + mutex_unlock(&priv->ops_mutex); + + return ret; +} + +static int ftdi_mpsse_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct ft232h_intf_priv *priv = gpiochip_get_data(chip); + bool low; + int ret; + + mutex_lock(&priv->io_mutex); + if (!priv->intf) { + mutex_unlock(&priv->io_mutex); + return -ENODEV; + } + mutex_unlock(&priv->io_mutex); + + dev_dbg(chip->parent, "%s: offset %d, val %d\n", + __func__, offset, value); + + mutex_lock(&priv->ops_mutex); + + if (offset < 5) { + low = true; + priv->gpiol_dir |= BIT(offset) << 3; + + if (value) + priv->gpiol_mask |= BIT(offset) << 3; + else + priv->gpiol_mask &= ~(BIT(offset) << 3); + } else { + low = false; + priv->gpioh_dir |= BIT(offset - 5); + + if (value) + priv->gpioh_mask |= BIT(offset - 5); + else + priv->gpioh_mask &= ~BIT(offset - 5); + } + + ret = ftdi_mpsse_set_port_pins(priv, low); + + mutex_unlock(&priv->ops_mutex); + + return ret; +} + +static int ftdi_mpsse_init_pins(struct usb_interface *intf, bool low, + u8 bits, u8 direction) +{ + struct ft232h_intf_priv *priv = usb_get_intfdata(intf); + int ret; + + mutex_lock(&priv->ops_mutex); + + if (low) { + priv->gpiol_mask = bits; + priv->gpiol_dir = direction; + } else { + priv->gpioh_mask = bits; + priv->gpioh_dir = direction; + } + ret = ftdi_mpsse_set_port_pins(priv, low); + + mutex_unlock(&priv->ops_mutex); + + return ret; +} + +static int ftdi_mpsse_cfg_bus_pins(struct usb_interface *intf, + u8 dir_bits, u8 value_bits) +{ + struct ft232h_intf_priv *priv = usb_get_intfdata(intf); + int ret; + + mutex_lock(&priv->ops_mutex); + + priv->gpiol_dir &= ~7; + priv->gpiol_dir |= (dir_bits & 7); + + priv->gpiol_mask &= ~7; + priv->gpiol_mask |= (value_bits & 7); + + ret = ftdi_mpsse_set_port_pins(priv, true); + + mutex_unlock(&priv->ops_mutex); + + return ret; +} + +static int ft232h_intf_add_mpsse_gpio(struct ft232h_intf_priv *priv) +{ + struct device *dev = &priv->intf->dev; + char **names, *label; + int i, ret; + + label = devm_kasprintf(dev, GFP_KERNEL, "ftdi-mpsse-gpio.%d", priv->id); + if (!label) + return -ENOMEM; + + priv->mpsse_gpio.label = label; + priv->mpsse_gpio.parent = dev; + priv->mpsse_gpio.owner = THIS_MODULE; + priv->mpsse_gpio.base = -1; + priv->mpsse_gpio.ngpio = FTDI_MPSSE_GPIOS; + priv->mpsse_gpio.can_sleep = true; + priv->mpsse_gpio.set = ftdi_mpsse_gpio_set; + priv->mpsse_gpio.get = ftdi_mpsse_gpio_get; + priv->mpsse_gpio.direction_input = ftdi_mpsse_gpio_direction_input; + priv->mpsse_gpio.direction_output = ftdi_mpsse_gpio_direction_output; + + names = devm_kcalloc(dev, priv->mpsse_gpio.ngpio, sizeof(char *), + GFP_KERNEL); + if (!names) + return -ENOMEM; + + names[0] = devm_kasprintf(dev, GFP_KERNEL, "mpsse.%d-CS", priv->id); + if (!names[0]) + return -ENOMEM; + + for (i = 1; i < priv->mpsse_gpio.ngpio; i++) { + int offs; + + offs = i < 5 ? 1 : 5; + names[i] = devm_kasprintf(dev, GFP_KERNEL, + "mpsse.%d-GPIO%c%d", priv->id, + i < 5 ? 'L' : 'H', i - offs); + if (!names[i]) + return -ENOMEM; + } + + priv->mpsse_gpio.names = (const char *const *)names; + + ret = ftdi_set_bitmode(priv->intf, 0x00, BITMODE_MPSSE); + if (ret < 0) { + dev_err(dev, "Failed to set MPSSE mode\n"); + return ret; + } + + ret = devm_gpiochip_add_data(dev, &priv->mpsse_gpio, priv); + if (ret < 0) { + dev_err(dev, "Failed to add MPSSE GPIO chip: %d\n", ret); + return ret; + } + + return 0; +} + +static void ftdi_lock(struct usb_interface *intf) +{ + struct ft232h_intf_priv *priv = usb_get_intfdata(intf); + + mutex_lock(&priv->ops_mutex); +} + +static void ftdi_unlock(struct usb_interface *intf) +{ + struct ft232h_intf_priv *priv = usb_get_intfdata(intf); + + mutex_unlock(&priv->ops_mutex); +} + +static const struct ft232h_intf_ops ft232h_intf_ops = { + .ctrl_xfer = ftdi_ctrl_xfer, + .bulk_xfer = ftdi_bulk_xfer, + .read_data = ftdi_read_data, + .write_data = ftdi_write_data, + .lock = ftdi_lock, + .unlock = ftdi_unlock, + .set_bitmode = ftdi_set_bitmode, + .set_baudrate = ftdi_set_baudrate, + .disable_bitbang = ftdi_disable_bitbang, + .init_pins = ftdi_mpsse_init_pins, + .cfg_bus_pins = ftdi_mpsse_cfg_bus_pins, +}; + +/* + * FPGA config interface: FPP via FT245 FIFO + */ +#define FPP_INTF_DEVNAME "ftdi-fifo-fpp-mgr" + +static struct dev_io_desc_data fpga_cfg_fpp_dev_io[2] = { + { "nconfig", 0, GPIO_ACTIVE_LOW }, + { "conf_done", 1, GPIO_ACTIVE_HIGH }, +}; + +static const struct fifo_fpp_mgr_platform_data fpga_cfg_fpp_plat_data = { + .ops = &ft232h_intf_ops, + .io_data = fpga_cfg_fpp_dev_io, + .io_data_len = ARRAY_SIZE(fpga_cfg_fpp_dev_io), + .nconfig_num = 8, + .conf_done_num = 9, +}; + +static int ft232h_intf_fpp_probe(struct usb_interface *intf, + const void *plat_data) +{ + struct ft232h_intf_priv *priv = usb_get_intfdata(intf); + const struct fifo_fpp_mgr_platform_data *pd = plat_data; + struct device *dev = &intf->dev; + struct platform_device *pdev; + struct gpiod_lookup_table *lookup; + char *cfgdone, *ncfg, *ptr; + size_t lookup_size; + int i, ret, gpios = 0; + + dev_dbg(dev, "%s: plat_data %p\n", __func__, pd); + if (!pd) { + dev_err(dev, "%s: Missing platform data\n", __func__); + return -EINVAL; + } + + ret = ft232h_intf_add_cbus_gpio(priv); + if (ret < 0) + return ret; + + lookup_size = sizeof(*lookup) + 3 * sizeof(struct gpiod_lookup); + lookup = devm_kzalloc(dev, lookup_size, GFP_KERNEL); + if (!lookup) + return -ENOMEM; + + lookup->dev_id = devm_kasprintf(dev, GFP_KERNEL, "%s.%d", + FPP_INTF_DEVNAME, priv->id); + if (!lookup->dev_id) + return -ENOMEM; + + ncfg = devm_kasprintf(dev, GFP_KERNEL, "ACBUS%d", pd->nconfig_num); + if (!ncfg) + return -ENOMEM; + + cfgdone = devm_kasprintf(dev, GFP_KERNEL, "ACBUS%d", pd->conf_done_num); + if (!cfgdone) + return -ENOMEM; + + for (i = 0; i < priv->cbus_gpio.ngpio; i++) { + if (!priv->cbus_gpio.names[i]) + continue; + + ptr = strstr(priv->cbus_gpio.names[i], "ACBUS"); + if (!ptr) + continue; + + if (!strncmp(ptr, ncfg, 6)) { + lookup->table[0].chip_hwnum = i; + gpios++; + continue; + } + if (!strncmp(ptr, cfgdone, 6)) { + lookup->table[1].chip_hwnum = i; + gpios++; + } + } + + /* Does GPIO controller provide all needed ACBUS pins? */ + if (gpios < 2) { + dev_err(dev, "Missing control GPIOs\n"); + return -ENODEV; + } + + for (i = 0; i < pd->io_data_len; i++) { + lookup->table[i].chip_label = priv->cbus_gpio.label; + lookup->table[i].idx = 0; + lookup->table[i].con_id = pd->io_data[i].con_id; + lookup->table[i].flags = pd->io_data[i].flags; + } + + priv->lookup_fifo = lookup; + gpiod_add_lookup_table(priv->lookup_fifo); + + pdev = platform_device_register_data(dev, FPP_INTF_DEVNAME, + priv->id, pd, sizeof(*pd)); + if (IS_ERR(pdev)) { + gpiod_remove_lookup_table(priv->lookup_fifo); + return PTR_ERR(pdev); + } + + priv->fifo_pdev = pdev; + + dev_dbg(dev, "%s: fifo pdev %p\n", __func__, pdev); + return 0; +} + +static int ft232h_intf_fpp_remove(struct usb_interface *intf) +{ + struct ft232h_intf_priv *priv = usb_get_intfdata(intf); + struct device *dev = &intf->dev; + + dev_dbg(dev, "%s\n", __func__); + platform_device_unregister(priv->fifo_pdev); + gpiod_remove_lookup_table(priv->lookup_fifo); + return 0; +} + +/* + * FPGA config interface: PS-SPI via MPSSE + */ +#define SPI_INTF_DEVNAME "ftdi-mpsse-spi" + +static struct dev_io_desc_data fpga_cfg_spi_dev_io[] = { + { "confd", 1, GPIO_ACTIVE_HIGH }, + { "nstat", 2, GPIO_ACTIVE_LOW }, + { "nconfig", 3, GPIO_ACTIVE_LOW }, +}; + +static const struct mpsse_spi_dev_data fpga_spi_dev_data[] = { + { + .magic = FTDI_MPSSE_IO_DESC_MAGIC, + .desc = fpga_cfg_spi_dev_io, + .desc_len = ARRAY_SIZE(fpga_cfg_spi_dev_io), + }, +}; + +static struct spi_board_info fpga_cfg_spi_info[] = { + { + .modalias = "fpga-passive-serial", + .mode = SPI_MODE_0 | SPI_LSB_FIRST, + .max_speed_hz = 30000000, + .bus_num = 0, + .chip_select = 0, + .platform_data = fpga_spi_dev_data, + }, +}; + +static const struct mpsse_spi_platform_data fpga_cfg_spi_plat_data = { + .ops = &ft232h_intf_ops, + .spi_info = fpga_cfg_spi_info, + .spi_info_len = ARRAY_SIZE(fpga_cfg_spi_info), +}; + +static struct platform_device *mpsse_dev_register(struct ft232h_intf_priv *priv, + const struct mpsse_spi_platform_data *pd) +{ + struct device *parent = &priv->intf->dev; + struct platform_device *pdev; + struct gpiod_lookup_table *lookup; + size_t lookup_size, tbl_size; + int i, ret; + + pdev = platform_device_alloc(SPI_INTF_DEVNAME, 0); + if (!pdev) + return NULL; + + pdev->dev.parent = parent; + pdev->dev.fwnode = NULL; + priv->spi_pdev = pdev; + + tbl_size = pd->spi_info_len + 1; + lookup_size = sizeof(*lookup) + tbl_size * sizeof(struct gpiod_lookup); + lookup = devm_kzalloc(parent, lookup_size, GFP_KERNEL); + if (!lookup) { + ret = -ENOMEM; + goto err; + } + + for (i = 0; i < pd->spi_info_len; i++) { + dev_dbg(parent, "INFO: %s cs %d\n", + pd->spi_info[i].modalias, pd->spi_info[i].chip_select); + } + + ret = platform_device_add_data(pdev, pd, sizeof(*pd)); + if (ret) + goto err; + + pdev->id = priv->id; + + ret = ft232h_intf_add_mpsse_gpio(priv); + if (ret < 0) + goto err; + + lookup->dev_id = devm_kasprintf(parent, GFP_KERNEL, "%s.%d", + pdev->name, pdev->id); + if (!lookup->dev_id) { + ret = -ENOMEM; + goto err; + } + + for (i = 0; i < pd->spi_info_len; i++) { + lookup->table[i].chip_label = priv->mpsse_gpio.label; + lookup->table[i].chip_hwnum = pd->spi_info[i].chip_select; + lookup->table[i].idx = i; + lookup->table[i].con_id = NULL; + if (pd->spi_info[i].mode & SPI_CS_HIGH) + lookup->table[i].flags = GPIO_ACTIVE_HIGH; + else + lookup->table[i].flags = GPIO_ACTIVE_LOW; + } + + priv->lookup_cs = lookup; + gpiod_add_lookup_table(priv->lookup_cs); + + ret = platform_device_add(pdev); + if (ret < 0) + goto err_add; + + dev_dbg(&pdev->dev, "%s done\n", __func__); + return pdev; + +err_add: + gpiod_remove_lookup_table(priv->lookup_cs); +err: + platform_device_put(pdev); + return ERR_PTR(ret); +} + +static int ft232h_intf_spi_probe(struct usb_interface *intf, + const void *plat_data) +{ + struct ft232h_intf_priv *priv = usb_get_intfdata(intf); + struct device *dev = &intf->dev; + struct platform_device *pdev; + + pdev = mpsse_dev_register(priv, plat_data); + if (IS_ERR(pdev)) { + dev_err(dev, "%s: Can't create MPSSE SPI device %ld\n", + __func__, PTR_ERR(pdev)); + return PTR_ERR(pdev); + } + + priv->spi_pdev = pdev; + return 0; +} + +static int ft232h_intf_spi_remove(struct usb_interface *intf) +{ + struct ft232h_intf_priv *priv = usb_get_intfdata(intf); + struct device *dev = &intf->dev; + + dev_dbg(dev, "%s: spi pdev %p\n", __func__, priv->spi_pdev); + gpiod_remove_lookup_table(priv->lookup_cs); + platform_device_unregister(priv->spi_pdev); + return 0; +} + +static const struct ft232h_intf_info fpga_cfg_spi_intf_info = { + .probe = ft232h_intf_spi_probe, + .remove = ft232h_intf_spi_remove, + .plat_data = &fpga_cfg_spi_plat_data, +}; + +static const struct ft232h_intf_info fpga_cfg_fifo_intf_info = { + .probe = ft232h_intf_fpp_probe, + .remove = ft232h_intf_fpp_remove, + .plat_data = &fpga_cfg_fpp_plat_data, +}; + +static int ft232h_intf_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct ft232h_intf_priv *priv; + struct device *dev = &intf->dev; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + const struct ft232h_intf_info *info; + unsigned int i; + int ret = 0; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + iface_desc = intf->cur_altsetting; + + for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { + endpoint = &iface_desc->endpoint[i].desc; + + if (usb_endpoint_is_bulk_out(endpoint)) + priv->bulk_out = endpoint->bEndpointAddress; + + if (usb_endpoint_is_bulk_in(endpoint)) { + priv->bulk_in = endpoint->bEndpointAddress; + priv->bulk_in_sz = usb_endpoint_maxp(endpoint); + } + } + + priv->usb_dev_id = id; + priv->index = 1; + priv->intf = intf; + priv->info = (struct ft232h_intf_info *)id->driver_info; + + info = priv->info; + if (!info) { + dev_err(dev, "Missing device specific driver info...\n"); + return -ENODEV; + } + + mutex_init(&priv->io_mutex); + mutex_init(&priv->ops_mutex); + usb_set_intfdata(intf, priv); + + priv->bulk_in_buf = devm_kmalloc(dev, priv->bulk_in_sz, GFP_KERNEL); + if (!priv->bulk_in_buf) + return -ENOMEM; + + priv->udev = usb_get_dev(interface_to_usbdev(intf)); + + priv->id = ida_simple_get(&ftdi_devid_ida, 0, 0, GFP_KERNEL); + if (priv->id < 0) + return priv->id; + + if (info->probe) { + ret = info->probe(intf, info->plat_data); + if (ret < 0) + goto err; + return 0; + } + + /* for simple GPIO-only devices */ + ret = -ENODEV; + if (info->use_cbus_gpio_ctrl) + ret = ft232h_intf_add_cbus_gpio(priv); + else if (info->use_mpsse_gpio_ctrl) + ret = ft232h_intf_add_mpsse_gpio(priv); + if (!ret) + return 0; +err: + ida_simple_remove(&ftdi_devid_ida, priv->id); + return ret; +} + +static void ft232h_intf_disconnect(struct usb_interface *intf) +{ + struct ft232h_intf_priv *priv = usb_get_intfdata(intf); + const struct ft232h_intf_info *info; + + info = (struct ft232h_intf_info *)priv->usb_dev_id->driver_info; + if (info && info->remove) + info->remove(intf); + + if (info->use_mpsse_gpio_ctrl) + gpiochip_remove(&priv->mpsse_gpio); + + if (info->use_cbus_gpio_ctrl) + gpiochip_remove(&priv->cbus_gpio); + + mutex_lock(&priv->io_mutex); + priv->intf = NULL; + usb_set_intfdata(intf, NULL); + mutex_unlock(&priv->io_mutex); + + usb_put_dev(priv->udev); + ida_simple_remove(&ftdi_devid_ida, priv->id); +} + +#define FTDI_VID 0x0403 +#define ARRI_FPP_INTF_PRODUCT_ID 0x7148 +#define ARRI_SPI_INTF_PRODUCT_ID 0x7149 + +static struct usb_device_id ft232h_intf_table[] = { + { USB_DEVICE(FTDI_VID, ARRI_FPP_INTF_PRODUCT_ID), + .driver_info = (kernel_ulong_t)&fpga_cfg_fifo_intf_info }, + { USB_DEVICE(FTDI_VID, ARRI_SPI_INTF_PRODUCT_ID), + .driver_info = (kernel_ulong_t)&fpga_cfg_spi_intf_info }, + {} +}; +MODULE_DEVICE_TABLE(usb, ft232h_intf_table); + +static struct usb_driver ft232h_intf_driver = { + .name = KBUILD_MODNAME, + .id_table = ft232h_intf_table, + .probe = ft232h_intf_probe, + .disconnect = ft232h_intf_disconnect, +}; + +module_usb_driver(ft232h_intf_driver); + +MODULE_ALIAS("ft232h-intf"); +MODULE_AUTHOR("Anatolij Gustschin "); +MODULE_DESCRIPTION("FT232H to FPGA interface driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/usb/ft232h-intf.h b/include/linux/usb/ft232h-intf.h new file mode 100644 index 000000000000..7e6857263db2 --- /dev/null +++ b/include/linux/usb/ft232h-intf.h @@ -0,0 +1,206 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Common definitions for FTDI FT232H interface device + * + * Copyright (C) 2017 - 2018 DENX Software Engineering + * Anatolij Gustschin + */ + +#ifndef __LINUX_FT232H_INTF_H +#define __LINUX_FT232H_INTF_H + +/* Used FTDI USB Requests */ +#define FTDI_SIO_RESET_REQUEST 0x00 +#define FTDI_SIO_SET_BAUDRATE_REQUEST 0x03 +#define FTDI_SIO_SET_BITMODE_REQUEST 0x0B +#define FTDI_SIO_READ_PINS_REQUEST 0x0C +#define FTDI_SIO_READ_EEPROM_REQUEST 0x90 + +/* MPSSE Commands */ +#define TX_BYTES_RE_MSB 0x10 /* tx on +ve clk (rising edge) */ +#define TX_BYTES_FE_MSB 0x11 /* tx on -ve clk (falling edge) */ +#define RX_BYTES_RE_MSB 0x20 +#define RX_BYTES_FE_MSB 0x24 +#define TXF_RXR_BYTES_MSB 0x31 /* tx on -ve clk, rx on +ve */ +#define TXR_RXF_BYTES_MSB 0x34 /* tx on +ve clk, rx on -ve */ + +#define TX_BYTES_RE_LSB 0x18 /* tx on +ve clk */ +#define TX_BYTES_FE_LSB 0x19 /* tx on -ve clk */ +#define RX_BYTES_RE_LSB 0x28 +#define RX_BYTES_FE_LSB 0x2C +#define TXF_RXR_BYTES_LSB 0x39 /* tx on -ve clk, rx on +ve */ +#define TXR_RXF_BYTES_LSB 0x3C /* tx on +ve clk, rx on -ve */ + +#define LOOPBACK_ON 0x84 +#define LOOPBACK_OFF 0x85 +#define TCK_DIVISOR 0x86 +#define DIS_DIV_5 0x8A +#define EN_DIV_5 0x8B +#define EN_3_PHASE 0x8C +#define DIS_3_PHASE 0x8D +#define DIS_ADAPTIVE 0x97 + +/* For EEPROM I/O mode */ +#define FTDI_MAX_EEPROM_SIZE 256 +#define FTDI_232H_CBUS_IOMODE 0x08 + +#define FTDI_USB_READ_TIMEOUT 5000 +#define FTDI_USB_WRITE_TIMEOUT 5000 + +/* Total number of MPSSE GPIOs: 4x GPIOL, 8x GPIOH, 1x CS on ADBUS3 */ +#define FTDI_MPSSE_GPIOS 13 + +/* MPSSE bitbang modes (copied from libftdi) */ +enum ftdi_mpsse_mode { + BITMODE_RESET = 0x00, /* switch off bitbang mode */ + BITMODE_BITBANG = 0x01, /* asynchronous bitbang mode */ + BITMODE_MPSSE = 0x02, /* MPSSE mode, on 2232x chips */ + BITMODE_SYNCBB = 0x04, /* synchronous bitbang mode */ + BITMODE_MCU = 0x08, /* MCU Host Bus Emulation mode */ + /* CPU-style fifo mode gets set via EEPROM */ + BITMODE_OPTO = 0x10, /* Fast Opto-Isolated Serial Interface Mode */ + BITMODE_CBUS = 0x20, /* Bitbang on CBUS pins, EEPROM config needed */ + BITMODE_SYNCFF = 0x40, /* Single Channel Synchronous FIFO mode */ + BITMODE_FT1284 = 0x80, /* FT1284 mode, available on 232H chips */ +}; + +struct ctrl_desc { + unsigned int dir_out; + u8 request; + u8 requesttype; + u16 value; + u16 index; + u16 size; + void *data; + int timeout; +}; + +struct bulk_desc { + unsigned int dir_out; + void *data; + int len; + int act_len; + int timeout; +}; + +/* + * struct ft232h_intf_ops - FT232H interface operations for upper drivers + * + * @bulk_xfer: FTDI USB bulk transfer + * @ctrl_xfer: FTDI USB control transfer + * @read_data: read 'len' bytes from FTDI device to the given buffer + * @write_data: write 'len' bytes from the given buffer to the FTDI device + * @lock: lock the interface for an operation sequence. Used when multiple + * command and/or data operations must be executed in a specific order + * (when other intermediate command/data transfers may not interfere) + * @unlock: unlock the previously locked interface + * @set_bitmode: configure FTDI bit mode + * @set_baudrate: configure FTDI baudrate + * @disable_bitbang: turn off bitbang mode + * @init_pins: initialize GPIOL/GPIOH port pins in MPSSE mode + * @cfg_bus_pins: configure MPSSE SPI bus pins + * + * Common FT232H interface USB xfer and device configuration operations used + * in FIFO-FPP, MPSSE-SPI or MPSSE-I2C drivers. Many of them are like FTDI + * protocol functions, which I mainly borrowed from libftdi + */ +struct ft232h_intf_ops { + int (*bulk_xfer)(struct usb_interface *intf, struct bulk_desc *desc); + int (*ctrl_xfer)(struct usb_interface *intf, struct ctrl_desc *desc); + int (*read_data)(struct usb_interface *intf, void *buf, size_t len); + int (*write_data)(struct usb_interface *intf, const char *buf, + size_t len); + void (*lock)(struct usb_interface *intf); + void (*unlock)(struct usb_interface *intf); + int (*set_bitmode)(struct usb_interface *intf, unsigned char bitmask, + unsigned char mode); + int (*set_baudrate)(struct usb_interface *intf, int baudrate); + int (*disable_bitbang)(struct usb_interface *intf); + int (*init_pins)(struct usb_interface *intf, bool low, u8 bits, u8 dir); + int (*cfg_bus_pins)(struct usb_interface *intf, u8 dir_bits, + u8 value_bits); +}; + +/* + * struct dev_io_desc_data - Descriptor of FT232H pin used by attached device + * @con_id: Name of the GPIO pin + * @idx: Index of the pin + * @flags: GPIOD flags of the pin + * + * Description of a GPIO used by device connected to FT232H + */ +struct dev_io_desc_data { + const char *con_id; + unsigned int idx; + unsigned int flags; +}; + +/* + * struct fifo_fpp_mgr_platform_data - FIFO/FPP device platform data + * @ops: USB interface operations used in FPP manager driver + * @io_data: Array with descriptors of used I/O pins + * @io_data_len: Length of io_data array + * @nconfig_num: ACBUS pin number of the NCONFIG pin + * @conf_done_num: ACBUS pin number of the CONF_DONE pin + * + * FIFO/FPP fpga manager specific platform data + */ +struct fifo_fpp_mgr_platform_data { + const struct ft232h_intf_ops *ops; + struct dev_io_desc_data *io_data; + size_t io_data_len; + int nconfig_num; + int conf_done_num; +}; + +#define FTDI_MPSSE_IO_DESC_MAGIC 0x5345494F +/* + * struct mpsse_spi_dev_data - MPSSE SPI device platform data + * @magic: Special # indicating that this is a I/O descriptor struct + * @io_data: Array with descriptors of used I/O pins + * @io_data_len: Length of io_data array + * + * MPSSE SPI slave specific platform data describing additional + * I/O pins (if any) of attached SPI slave. It is supposed to be + * passed via .platform_data of spi_board_info struct. + * To differentiate between MPSSE I/O descriptor data and other + * driver-specific platform data we use FTDI_MPSSE_IO_DESC_MAGIC + * in the header of this struct + */ +struct mpsse_spi_dev_data { + u32 magic; + struct dev_io_desc_data *desc; + size_t desc_len; +}; + +/* + * struct mpsse_spi_platform_data - MPSSE SPI bus platform data + * @ops: USB interface operations used in MPSSE SPI controller driver + * @spi_info: Array with spi_board_info structures of attached SPI slaves + * @spi_info_len: Length of spi_info array + * + * MPSSE SPI bus specific platform data describing attached SPI slaves + * and optionally their additional I/O pins (.platform_data of spi_info) + */ +struct mpsse_spi_platform_data { + const struct ft232h_intf_ops *ops; + struct spi_board_info *spi_info; + size_t spi_info_len; +}; + +/* + * Value HIGH. rate is 12000000 / ((1 + value) * 2) + */ +static inline int div_value(int rate) +{ + int r; + + if (rate >= 6000000) + return 0; + r = 6000000 / rate - 1; + if (r < 0xffff) + return r; + return 0xffff; +} + +#endif /* __LINUX_FT232H_INTF_H */ -- 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,1/3] usb: misc: add driver for FT232H based FPGA configuration devices From: Anatolij Gustschin Message-Id: <20190221202506.17744-2-agust@denx.de> Date: Thu, 21 Feb 2019 21:25:04 +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: QWRkIFVTQiBpbnRlcmZhY2UgZHJpdmVyIGZvciBBUlJJIEZQR0EgY29uZmlndXJhdGlvbiBkZXZp Y2VzIGJhc2VkIG9uCkZUREkgRlQyMzJIIGNoaXAuIERlcGVuZGluZyBvbiBVU0IgUElEIHRoZSBk cml2ZXIgcmVnaXN0ZXJzIGRpZmZlcmVudApwbGF0Zm9ybSBkZXZpY2VzIGRlc2NyaWJpbmcgYW4g RlBHQSBjb25maWd1cmF0aW9uIGludGVyZmFjZS4KCk9uZSBGUEdBIGNvbmZpZ3VyYXRpb24gaW50 ZXJmYWNlIHR5cGUgaXMgdGhlIHVzdWFsIFNQSSBidXMgd2l0aAphZGRpdGlvbmFsIGNvbnRyb2wg YW5kIHN0YXR1cyBHUElPcy4gRm9yIHRoaXMgaW50ZXJmYWNlIHR5cGUgdGhlCkZUREkgTVBTU0Ug bW9kZSBpcyB1dGlsaXplZCB0byBzdXBwb3J0IFNQSSBidXMgYW5kIEdQSU8tTC9IIHBpbnMKZm9y IFNQSSBidXMgY2hpcHNlbGVjdCBhbmQgU1BJIHNsYXZlIGRldmljZSBJL08uIFN1YnNlcXVlbnQg cGF0Y2gKYWRkcyBhbiBNUFNTRSBTUEkgY29udHJvbGxlciBkcml2ZXIgZm9yIFVTQi1TUEkgYnVz IHN1cHBvcnQuClRoZSBhY3R1YWwgRlBHQSBjb25maWd1cmF0aW9uIGRyaXZlciBmb3IgU1BJIGJ1 cyBpcyBhbHJlYWR5CmF2YWlsYWJsZSBpbiB0aGUgRlBHQSBtYW5hZ2VyIGZyYW1ld29yayAoYWx0 ZXJhLXBzLXNwaSBtb2R1bGUpLgoKQW5vdGhlciBGUEdBIGNvbmZpZ3VyYXRpb24gaW50ZXJmYWNl IHR5cGUgaXMgdGhlIEZUMjQ1IEZJRk8KKGNvbm5lY3RlZCB2aWEgQ1BMRCkgd2l0aCBhZGRpdGlv bmFsIGNvbnRyb2wgYW5kIHN0YXR1cyBHUElPcwpvbiBGVDIzMkggQUNCVVMuIFRoaXMgaW50ZXJm YWNlIGlzIHVzZWQgdG8gY29uZmlndXJlIEZQR0FzIHVzaW5nCkFsdGVyYSBmYXN0IHBhc3NpdmUg cGFyYWxsZWwgKEZQUCkgaW50ZXJmYWNlLiBTdWJzZXF1ZW50IHBhdGNoCndpbGwgYWRkIGFuIEZQ UCBGUEdBIG1hbmFnZXIgZHJpdmVyIGZvciBpdC4KClRoZSBGVERJIHByb3RvY29sIGNvZGUgYW5k IHByb3RvdHlwZXMgd2FzIGJvcnJvd2VkIGZyb20gbGliZnRkaS4KClNpZ25lZC1vZmYtYnk6IEFu YXRvbGlqIEd1c3RzY2hpbiA8YWd1c3RAZGVueC5kZT4KLS0tCiBNQUlOVEFJTkVSUyAgICAgICAg ICAgICAgICAgICAgIHwgICAgOCArCiBkcml2ZXJzL3VzYi9taXNjL0tjb25maWcgICAgICAgIHwg ICAxMCArCiBkcml2ZXJzL3VzYi9taXNjL01ha2VmaWxlICAgICAgIHwgICAgMSArCiBkcml2ZXJz L3VzYi9taXNjL2Z0MjMyaC1pbnRmLmMgIHwgMTQ2NyArKysrKysrKysrKysrKysrKysrKysrKysr KysrKysrCiBpbmNsdWRlL2xpbnV4L3VzYi9mdDIzMmgtaW50Zi5oIHwgIDIwNiArKysrKwogNSBm aWxlcyBjaGFuZ2VkLCAxNjkyIGluc2VydGlvbnMoKykKIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2 ZXJzL3VzYi9taXNjL2Z0MjMyaC1pbnRmLmMKIGNyZWF0ZSBtb2RlIDEwMDY0NCBpbmNsdWRlL2xp bnV4L3VzYi9mdDIzMmgtaW50Zi5oCgpkaWZmIC0tZ2l0IGEvTUFJTlRBSU5FUlMgYi9NQUlOVEFJ TkVSUwppbmRleCA4YjUzZWIzZGIyNzEuLjJhNDg5YjYzZDEzOCAxMDA2NDQKLS0tIGEvTUFJTlRB SU5FUlMKKysrIGIvTUFJTlRBSU5FUlMKQEAgLTE1OTY4LDYgKzE1OTY4LDE0IEBAIFM6CU1haW50 YWluZWQKIEY6CURvY3VtZW50YXRpb24vdXNiL2FjbS50eHQKIEY6CWRyaXZlcnMvdXNiL2NsYXNz L2NkYy1hY20uKgogCitVU0IgQVJSSSBGUEdBIENPTkZJR1VSQVRJT04gQURBUFRFUiBEUklWRVIK K006CUFuYXRvbGlqIEd1c3RzY2hpbiA8YWd1c3RAZGVueC5kZT4KK0w6CWxpbnV4LXVzYkB2Z2Vy Lmtlcm5lbC5vcmcKK1M6CU1haW50YWluZWQKK0Y6CWRyaXZlcnMvdXNiL21pc2MvZnQyMzJoLWlu dGYuYworRjoJZHJpdmVycy9zcGkvc3BpLWZ0ZGktbXBzc2UuYworRjoJaW5jbHVkZS9saW51eC91 c2IvZnQyMzJoLWludGYuaAorCiBVU0IgQVI1NTIzIFdJUkVMRVNTIERSSVZFUgogTToJUG9udHVz IEZ1Y2hzIDxwb250dXMuZnVjaHNAZ21haWwuY29tPgogTDoJbGludXgtd2lyZWxlc3NAdmdlci5r ZXJuZWwub3JnCmRpZmYgLS1naXQgYS9kcml2ZXJzL3VzYi9taXNjL0tjb25maWcgYi9kcml2ZXJz L3VzYi9taXNjL0tjb25maWcKaW5kZXggYmUwNGMxMTdmZTgwLi40MzllZmM1NDNiYjMgMTAwNjQ0 Ci0tLSBhL2RyaXZlcnMvdXNiL21pc2MvS2NvbmZpZworKysgYi9kcml2ZXJzL3VzYi9taXNjL0tj b25maWcKQEAgLTI3NiwzICsyNzYsMTMgQEAgY29uZmlnIFVTQl9DSEFPU0tFWQogCiAJICBUbyBj b21waWxlIHRoaXMgZHJpdmVyIGFzIGEgbW9kdWxlLCBjaG9vc2UgTSBoZXJlOiB0aGUKIAkgIG1v ZHVsZSB3aWxsIGJlIGNhbGxlZCBjaGFvc2tleS4KKworY29uZmlnIFVTQl9GVDIzMkhfSU5URgor CXRyaXN0YXRlICJGVERJIEZUMjMySCBGUEdBIGNvbmZpZ3VyYXRpb24gaW50ZXJmYWNlIGRyaXZl ciIKKwlkZXBlbmRzIG9uIEdQSU9MSUIKKwloZWxwCisJICBFbmFibGUgZHJpdmVyIHN1cHBvcnQg Zm9yIHRoZSBGVDIzMkggYmFzZWQgVVNCLUdQSU8vU1BJL0ZJRk8KKwkgIGludGVyZmFjZSBhZGFw dGVyIGZvciBGUEdBIGNvbmZpZ3VyYXRpb24uIEFkZGl0aW9uYWwgZHJpdmVycworCSAgc3VjaCBh cyBzcGktZnRkaS1tcHNzZSwgYWx0ZXJhLXBzLXNwaSwgZnRkaS1maWZvLWZwcCBhbmQKKwkgIGZw Z2EtbWdyIG11c3QgYmUgZW5hYmxlZCBpbiBvcmRlciB0byB1c2UgdGhlIGZ1bmN0aW9uYWxpdHkg b2YKKwkgIHRoZSBkZXZpY2UuCmRpZmYgLS1naXQgYS9kcml2ZXJzL3VzYi9taXNjL01ha2VmaWxl IGIvZHJpdmVycy91c2IvbWlzYy9NYWtlZmlsZQppbmRleCAxMDlmNTRmNWI5YWEuLmFmOTM1ZWZm YjAxOSAxMDA2NDQKLS0tIGEvZHJpdmVycy91c2IvbWlzYy9NYWtlZmlsZQorKysgYi9kcml2ZXJz L3VzYi9taXNjL01ha2VmaWxlCkBAIC0xMCw2ICsxMCw3IEBAIG9iai0kKENPTkZJR19VU0JfQ1lU SEVSTSkJCSs9IGN5dGhlcm0ubwogb2JqLSQoQ09ORklHX1VTQl9FTUkyNikJCQkrPSBlbWkyNi5v CiBvYmotJChDT05GSUdfVVNCX0VNSTYyKQkJCSs9IGVtaTYyLm8KIG9iai0kKENPTkZJR19VU0Jf RVpVU0JfRlgyKQkJKz0gZXp1c2Iubworb2JqLSQoQ09ORklHX1VTQl9GVDIzMkhfSU5URikJCSs9 IGZ0MjMyaC1pbnRmLm8KIG9iai0kKENPTkZJR19VU0JfRlRESV9FTEFOKQkJKz0gZnRkaS1lbGFu Lm8KIG9iai0kKENPTkZJR19VU0JfSURNT1VTRSkJCSs9IGlkbW91c2Uubwogb2JqLSQoQ09ORklH X1VTQl9JT1dBUlJJT1IpCQkrPSBpb3dhcnJpb3IubwpkaWZmIC0tZ2l0IGEvZHJpdmVycy91c2Iv bWlzYy9mdDIzMmgtaW50Zi5jIGIvZHJpdmVycy91c2IvbWlzYy9mdDIzMmgtaW50Zi5jCm5ldyBm aWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAwMDAwMC4uNmY5OTI1N2I5ZmJkCi0tLSAvZGV2 L251bGwKKysrIGIvZHJpdmVycy91c2IvbWlzYy9mdDIzMmgtaW50Zi5jCkBAIC0wLDAgKzEsMTQ2 NyBAQAorLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjAKKy8qCisgKiBGVERJIEZU MjMySCBpbnRlcmZhY2UgZHJpdmVyIGZvciBBUlJJIEZQR0EgY29uZmlndXJhdGlvbgorICoKKyAq IENvcHlyaWdodCAoQykgMjAxNyAtIDIwMTggREVOWCBTb2Z0d2FyZSBFbmdpbmVlcmluZworICog QW5hdG9saWogR3VzdHNjaGluIDxhZ3VzdEBkZW54LmRlPgorICoKKyAqICAgIEZpZ3VyZTogRlQy MzJILCBGUEdBIERldmljZXMgYW5kIERyaXZlcnMgUmVsYXRpb25zaGlwCisgKgorICogICAgICAr LS0tLS0tLS0tLS0tLSsKKyAqICAgICAgfCAgICAgICAgICAgICB8CisgKiAgICAgIHwgIFNUUkFU SVggViAgfFBTLVNQSSAgICAgICAgIEZUMjQ1IEZJRk8gJiBHUElPCisgKiAgICAgIHwgICAgICAg ICAgICAgKy0tLS0tKyAgICArLS0tLS0tLS0tLS0tLS0tLS0tLSsKKyAqICAgICAgfCAgb24gQm9h cmQgMSB8ICAgICArICAgICsgICAgICAgICAgICAgICAgICAgfAorICogICAgICB8ICAgICAgICAg ICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgKy0tLS0rLS0tKworICogICAgICB8ICBQQ0ll ICAgICAgIHwgICBBREJVUyZBQ0JVUyAgICAgICAgICAgfCAgQ1BMRCAgfAorICogICAgICArLS0t Ky0tLS0tLS0tLSsgQ29ubmVjdGlvbiBPcHRpb25zICAgICAgKy0tLS0rLS0tKworICogICAgICAg ICAgXiAgICAgICAgICAoTVBTU0Ugb3IgRklGTyZHUElPKSAgICAgICAgICB8CisgKiAgICAgICAg ICArICAgICAgICAgICAgICAgICAgKyAgICAgICAgICAgICAgKy0tLS0tLSstLS0tLS0tKworICog ICAgIGFsdGVyYS1jdnAgICstLS0tLS0tLS0tLSstLS0tLS0tLS0tKyAgIHwgICAgIEZQUCAgICAg IHwKKyAqICAgICAgICAgICAgICAgICB8ICAgICAgICBGVDIzMkggICAgICAgIHwgICB8ICAgICAg ICAgICAgICB8CisgKiAgICAgICAgICAgICAgICAgfCAgICAgMHgwNDAzOjB4NzE0OCAgICB8ICAg fCAgIEFSUklBIDEwICAgfAorICogICAgICAgICAgICAgICAgIHwgICAgIDB4MDQwMzoweDcxNDkg ICAgfCAgIHwgICAgICAgICAgICAgIHwKKyAqICAgICAgICAgICAgICAgICArLS0tLS0tLS0tLSst LS0tLS0tLS0tLSsgICB8ICBvbiBCb2FyZCAyICB8CisgKiAgICAgICAgICAgICAgICAgICAgICAg ICAgICB8ICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgfAorICogICAgICAgICAgICAgICAg Ky0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSsgIHwgICAgICAgIFBDSWUgIHwKKyAqICAgICAgICBj cmVhdGVzIHwgZnQyMzJoLWludGYgKFVTQiBtaXNjKSB8ICArLS0tLS0tLS0tLSstLS0rCisgKiAg ICAgICBwbGF0Zm9ybSB8ICAgICBidWxrL2N0cmwgeGZlciAgICAgfCAgICAgICAgICAgICBeCisg KiAgICAgICAgZGV2aWNlcyB8QUNCVVMgR1BJTyBDdHJsICgweDcxNDgpfCAgICAgICAgICAgICB8 CisgKiAgICAgICAgIGJlbG93ICB8TVBTU0UgR1BJTyBDdHJsICgweDcxNDkpfCAgICAgICAgICAg ICB8CisgKiAgICAgICAgICAgICAgICArLS0tLS0tLSstLS0tLS0tKy0tLS0tLS0tKyAgICAgICAg ICAgICB8CisgKiAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgfCAgICAgICAgICAgICAg ICAgICAgICB8CisgKiAgICAgICAgICAgZm9yICAgICArLS0tLSsgICAgICAgKy0tLS0tLSsgICAg Zm9yICAgICAgICB8CisgKiAgICAgICAgUElEIDB4NzE0OSB8ICAgICAgICAgICAgICAgICAgIHwg UElEIDB4NzE0OCAgICB8CisgKiAgICAgICAgICstLS0tLS0tLS0rLS0tLS0tLS0rICArLS0tLS0t LSstLS0tLS0tLS0rICAgICB8CisgKiAgICAgICAgIHwgIGZ0ZGktbXBzc2Utc3BpICB8ICB8ICAg ICAgICAgICAgICAgICB8ICAgICB8CisgKiAgICAgICAgIHwgYWx0ZXJhLXBzLXNwaSBpbiB8ICB8 ZnRkaS1maWZvLWZwcC1tZ3J8ICAgICB8CisgKiAgICAgICAgIHwgICBzcGlfYm9hcmRfaW5mbyB8 ICB8ICAgICAgICAgICAgICAgICB8ICAgICB8CisgKiAgICAgICAgICstLS0tLS0tLS0rLS0tLS0t LS0rICArLS0tLS0tLS0rLS0tLS0tLS0rICAgICB8CisgKiAgICAgICAgICAgICAgICAgICBeICAg ICAgICAgICAgICAgICAgICBeICAgICAgICAgICAgICB8CisgKiAgICAgICAgRHJpdmVyczogICB8 ICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICB8CisgKiAgICAgICAgICAgICAgICAg ICArICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICB8CisgKiAgICAgIE1QU1NFIFNQ SSBtYXN0ZXIoc3BpLWZ0ZGktbXBzc2UpICB8ICAgICAgICAgICAgICArCisgKiAgICAgICAgICAg ICAgICAgICBeICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICB8CisgKiAgICAgICAg ICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICArICAgICAgICAgICAgICArCisgKiAgICAg ICAgICAgICBhbHRlcmEtcHMtc3BpICAgICAgICBmdGRpLWZpZm8tZnBwICAgIGFsdGVyYS1jdnAK KyAqICAgICAgICAgICAgICBGUEdBIE1hbmFnZXIgICAgICAgICBGUEdBIE1hbmFnZXIgICBGUEdB IE1hbmFnZXIKKyAqCisgKgorICogV2hlbiB1c2luZyB5b3VyIGN1c3RvbSBVU0IgcHJvZHVjdCBJ RCwgdGhpcyBGVDIzMkggaW50ZXJmYWNlIGRyaXZlcgorICogYWxzbyBhbGxvd3MgdG8gcmVnaXN0 ZXIgdGhlIEdQSU8gY29udHJvbGxlciBmb3IgQ0JVUyBwaW5zIG9yIGZvcgorICogTVBTU0UgR1BJ TyBwaW5zLiBCZWxvdyBhcmUgZXhhbXBsZXMgaG93IHRvIHVzZSB0aGUgZHJpdmVyIGFzIENCVVMt CisgKiBvciBNUFNTRS1HUElPIGNvbnRyb2xsZXIuCisgKgorICogRm9yIENCVVMtR1BJT3MgYWRk IG5ldyBlbnRyeSB3aXRoIHlvdXIgUElEIHRvIGZ0MjMyaF9pbnRmX3RhYmxlW106CisgKiBzdGF0 aWMgY29uc3Qgc3RydWN0IGZ0MjMyaF9pbnRmX2luZm8gZnRkaV9jYnVzX2dwaW9faW50Zl9pbmZv ID0geworICoJLnVzZV9jYnVzX2dwaW9fY3RybCA9IHRydWUsCisgKiB9OworICogeyBVU0JfREVW SUNFKEZURElfVklELCBQSUQpLAorICogICAuZHJpdmVyX2luZm8gPSAoa2VybmVsX3Vsb25nX3Qp JmZ0ZGlfY2J1c19ncGlvX2ludGZfaW5mbyB9LAorICoKKyAqIEZvciBNUFNTRS1HUElPIGFkZCBu ZXcgZW50cnkgd2l0aCB5b3VyIFBJRCB0byBmdDIzMmhfaW50Zl90YWJsZVtdOgorICogc3RhdGlj IGNvbnN0IHN0cnVjdCBmdDIzMmhfaW50Zl9pbmZvIGZ0ZGlfbXBzc2VfZ3Bpb19pbnRmX2luZm8g PSB7CisgKgkudXNlX21wc3NlX2dwaW9fY3RybCA9IHRydWUsCisgKiB9OworICogeyBVU0JfREVW SUNFKEZURElfVklELCBQSUQpLAorICogICAuZHJpdmVyX2luZm8gPSAoa2VybmVsX3Vsb25nX3Qp JmZ0ZGlfbXBzc2VfZ3Bpb19pbnRmX2luZm8gfSwKKyAqCisgKiBXaXRoIGN1c3RvbSBVU0IgcHJv ZHVjdCBJRHMgaXQgaXMgYWxzbyBwb3NzaWJsZSB0byB1c2UgRlQyMzJIIFNQSSBidXMKKyAqIHdp dGggZGlmZmVyZW50IFNQSSBzbGF2ZSBkZXZpY2VzIGF0dGFjaGVkIChlLmcuIFNQSS1OT1IgZmxh c2ggY2hpcHMsCisgKiBzcGlkZXYsIGV0Yy4pLiBFeGFtcGxlIGJlbG93IHNob3dzIGhvdyB0byBh ZGQgYSBidXMgd2l0aCB0d28gU1BJIHNsYXZlCisgKiBkZXZpY2VzIGZvciB5b3VyIFVTQiBQSUQ6 CisgKgorICogc3RhdGljIHN0cnVjdCBzcGlfYm9hcmRfaW5mbyBmdGRpX3NwaV9idXNfaW5mb1td ID0geworICoJeworICoJLm1vZGFsaWFzCT0gIncyNXEzMiIsCisgKgkubW9kZQkJPSBTUElfTU9E RV8wLAorICoJLm1heF9zcGVlZF9oegk9IDYwMDAwMDAwLAorICoJLmJ1c19udW0JPSAwLAorICoJ LmNoaXBfc2VsZWN0CT0gMCwgLy8gVENLL1NLIGF0IEFEQlVTMAorICoJfSwKKyAqCXsKKyAqCS5t b2RhbGlhcwk9ICJzcGlkZXYiLAorICoJLm1vZGUJCT0gU1BJX01PREVfMCB8IFNQSV9MU0JfRklS U1QgfCBTUElfQ1NfSElHSCwKKyAqCS5tYXhfc3BlZWRfaHoJPSAzMDAwMDAwMCwKKyAqCS5idXNf bnVtCT0gMCwKKyAqCS5jaGlwX3NlbGVjdAk9IDUsIC8vIEdQSU9IMCBhdCBBQ0JVUzAKKyAqCX0s CisgKiB9OworICoKKyAqIHN0YXRpYyBjb25zdCBzdHJ1Y3QgbXBzc2Vfc3BpX3BsYXRmb3JtX2Rh dGEgZnRkaV9zcGlfYnVzX3BsYXRfZGF0YSA9IHsKKyAqCS5vcHMJCT0gJmZ0MjMyaF9pbnRmX29w cywKKyAqCS5zcGlfaW5mbwk9IGZ0ZGlfc3BpX2J1c19pbmZvLAorICoJLnNwaV9pbmZvX2xlbgk9 IEFSUkFZX1NJWkUoZnRkaV9zcGlfYnVzX2luZm8pLAorICogfTsKKyAqCisgKiBzdGF0aWMgY29u c3Qgc3RydWN0IGZ0MjMyaF9pbnRmX2luZm8gZnRkaV9zcGlfYnVzX2ludGZfaW5mbyA9IHsKKyAq CS5wcm9iZSAgPSBmdDIzMmhfaW50Zl9zcGlfcHJvYmUsCisgKgkucmVtb3ZlICA9IGZ0MjMyaF9p bnRmX3NwaV9yZW1vdmUsCisgKgkucGxhdF9kYXRhICA9ICZmdGRpX3NwaV9idXNfcGxhdF9kYXRh LAorICogfTsKKyAqIHsgVVNCX0RFVklDRShGVERJX1ZJRCwgWU9VUl9QSUQpLAorICoJLmRyaXZl cl9pbmZvID0gKGtlcm5lbF91bG9uZ190KSZmdGRpX3NwaV9idXNfaW50Zl9pbmZvIH0sCisgKi8K KworI2luY2x1ZGUgPGxpbnV4L2tlcm5lbC5oPgorI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPgor I2luY2x1ZGUgPGxpbnV4L2RldmljZS5oPgorI2luY2x1ZGUgPGxpbnV4L2RlbGF5Lmg+CisjaW5j bHVkZSA8bGludXgvcHJpbnRrLmg+CisjaW5jbHVkZSA8bGludXgvZ3Bpby9kcml2ZXIuaD4KKyNp bmNsdWRlIDxsaW51eC9ncGlvL21hY2hpbmUuaD4KKyNpbmNsdWRlIDxsaW51eC9pZHIuaD4KKyNp bmNsdWRlIDxsaW51eC9tdXRleC5oPgorI2luY2x1ZGUgPGxpbnV4L3BsYXRmb3JtX2RldmljZS5o PgorI2luY2x1ZGUgPGxpbnV4L3NsYWIuaD4KKyNpbmNsdWRlIDxsaW51eC9zcGkvc3BpLmg+Cisj aW5jbHVkZSA8bGludXgvdXNiL2NoOS5oPgorI2luY2x1ZGUgPGxpbnV4L3VzYi5oPgorI2luY2x1 ZGUgPGxpbnV4L3VzYi9mdDIzMmgtaW50Zi5oPgorCitzdHJ1Y3QgZnQyMzJoX2ludGZfcHJpdiB7 CisJc3RydWN0IHVzYl9pbnRlcmZhY2UJKmludGY7CisJc3RydWN0IHVzYl9kZXZpY2UJKnVkZXY7 CisJc3RydWN0IG11dGV4CQlpb19tdXRleDsgLyogc3luYyBJL08gd2l0aCBkaXNjb25uZWN0ICov CisJc3RydWN0IG11dGV4CQlvcHNfbXV0ZXg7CisJaW50CQkJYml0YmFuZ19lbmFibGVkOworCWlu dAkJCWlkOworCWludAkJCWluZGV4OworCXU4CQkJYnVsa19pbjsKKwl1OAkJCWJ1bGtfb3V0Owor CXNpemVfdAkJCWJ1bGtfaW5fc3o7CisJdm9pZAkJCSpidWxrX2luX2J1ZjsKKworCWNvbnN0IHN0 cnVjdCB1c2JfZGV2aWNlX2lkCSp1c2JfZGV2X2lkOworCXN0cnVjdCBmdDIzMmhfaW50Zl9pbmZv CQkqaW5mbzsKKwlzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlCQkqZmlmb19wZGV2OworCXN0cnVjdCBw bGF0Zm9ybV9kZXZpY2UJCSpzcGlfcGRldjsKKwlzdHJ1Y3QgZ3Bpb2RfbG9va3VwX3RhYmxlCSps b29rdXBfZmlmbzsKKwlzdHJ1Y3QgZ3Bpb2RfbG9va3VwX3RhYmxlCSpsb29rdXBfY3M7CisKKwlz dHJ1Y3QgZ3Bpb19jaGlwCWNidXNfZ3BpbzsKKwljb25zdCBjaGFyCQkqY2J1c19ncGlvX25hbWVz WzRdOworCXU4CQkJY2J1c19waW5fb2Zmc2V0c1s0XTsKKwl1OAkJCWNidXNfbWFzazsKKwl1OAkJ CXBpbmJ1Zls0XTsKKwl1OAkJCWVlcHJvbVtGVERJX01BWF9FRVBST01fU0laRV07CisKKwlzdHJ1 Y3QgZ3Bpb19jaGlwCW1wc3NlX2dwaW87CisJdTgJCQlncGlvbF9tYXNrOworCXU4CQkJZ3Bpb2hf bWFzazsKKwl1OAkJCWdwaW9sX2RpcjsKKwl1OAkJCWdwaW9oX2RpcjsKKwl1OAkJCXR4X2J1Zls0 XTsKK307CisKKy8qIERldmljZSBpbmZvIHN0cnVjdCB1c2VkIGZvciBkZXZpY2Ugc3BlY2lmaWMg aW5pdC4gKi8KK3N0cnVjdCBmdDIzMmhfaW50Zl9pbmZvIHsKKwl1bnNpZ25lZCBpbnQgdXNlX2Ni dXNfZ3Bpb19jdHJsOworCXVuc2lnbmVkIGludCB1c2VfbXBzc2VfZ3Bpb19jdHJsOworCWludCAo KnByb2JlKShzdHJ1Y3QgdXNiX2ludGVyZmFjZSAqaW50ZiwgY29uc3Qgdm9pZCAqcGxhdF9kYXRh KTsKKwlpbnQgKCpyZW1vdmUpKHN0cnVjdCB1c2JfaW50ZXJmYWNlICppbnRmKTsKKwljb25zdCB2 b2lkICpwbGF0X2RhdGE7IC8qIG9wdGlvbmFsLCBwYXNzZWQgdG8gcHJvYmUoKSAqLworfTsKKwor c3RhdGljIERFRklORV9JREEoZnRkaV9kZXZpZF9pZGEpOworCisvKiBVc2UgYmF1ZHJhdGUgY2Fs Y3VsYXRpb24gYm9ycm93ZWQgZnJvbSBsaWJmdGRpICovCitzdGF0aWMgdW5zaWduZWQgaW50IGZ0 ZGlfdG9fY2xrYml0cyh1bnNpZ25lZCBpbnQgYmF1ZHJhdGUsIHVuc2lnbmVkIGludCBjbGssCisJ CQkJICAgIHVuc2lnbmVkIGludCBjbGtfZGl2LAorCQkJCSAgICB1bnNpZ25lZCBpbnQgKmVuY29k ZWRfZGl2aXNvcikKK3sKKwlzdGF0aWMgY29uc3QgY2hhciBmcmFjX2NvZGVbOF0gPSB7IDAsIDMs IDIsIDQsIDEsIDUsIDYsIDcgfTsKKwl1bnNpZ25lZCBpbnQgYmVzdF9iYXVkID0gMDsKKwl1bnNp Z25lZCBpbnQgYmVzdF9kaXY7CisKKwlpZiAoYmF1ZHJhdGUgPj0gY2xrIC8gY2xrX2Rpdikgewor CQkqZW5jb2RlZF9kaXZpc29yID0gMDsKKwkJYmVzdF9iYXVkID0gY2xrIC8gY2xrX2RpdjsKKwl9 IGVsc2UgaWYgKGJhdWRyYXRlID49IGNsayAvIChjbGtfZGl2ICsgY2xrX2RpdiAvIDIpKSB7CisJ CSplbmNvZGVkX2Rpdmlzb3IgPSAxOworCQliZXN0X2JhdWQgPSBjbGsgLyAoY2xrX2RpdiArIGNs a19kaXYgLyAyKTsKKwl9IGVsc2UgaWYgKGJhdWRyYXRlID49IGNsayAvICgyICogY2xrX2Rpdikp IHsKKwkJKmVuY29kZWRfZGl2aXNvciA9IDI7CisJCWJlc3RfYmF1ZCA9IGNsayAvICgyICogY2xr X2Rpdik7CisJfSBlbHNlIHsKKwkJLyoKKwkJICogRGl2aWRlIGJ5IDE2IHRvIGhhdmUgMyBmcmFj dGlvbmFsIGJpdHMgYW5kCisJCSAqIG9uZSBiaXQgZm9yIHJvdW5kaW5nCisJCSAqLworCQliZXN0 X2RpdiA9IERJVl9ST1VORF9DTE9TRVNUKGNsayAqIDggLyBjbGtfZGl2LCBiYXVkcmF0ZSk7CisK KwkJaWYgKGJlc3RfZGl2ID4gMHgyMDAwMCkKKwkJCWJlc3RfZGl2ID0gMHgxZmZmZjsKKworCQli ZXN0X2JhdWQgPSBESVZfUk9VTkRfQ0xPU0VTVChjbGsgKiA4IC8gY2xrX2RpdiwgYmVzdF9kaXYp OworCisJCSplbmNvZGVkX2Rpdmlzb3IgPSAoYmVzdF9kaXYgPj4gMykgfAorCQkJCSAgIChmcmFj X2NvZGVbYmVzdF9kaXYgJiAweDddIDw8IDE0KTsKKwl9CisJcmV0dXJuIGJlc3RfYmF1ZDsKK30K KworI2RlZmluZSBIX0NMSwkxMjAwMDAwMDAKKyNkZWZpbmUgQ19DTEsJNDgwMDAwMDAKK3N0YXRp YyBpbnQgZnRkaV9jb252ZXJ0X2JhdWRyYXRlKHN0cnVjdCBmdDIzMmhfaW50Zl9wcml2ICpwcml2 LCBpbnQgYmF1ZCwKKwkJCQkgdTE2ICp2YWx1ZSwgdTE2ICppbmRleCkKK3sKKwl1bnNpZ25lZCBp bnQgZW5jb2RlZF9kaXZpc29yID0gMDsKKwl1bnNpZ25lZCBpbnQgYmVzdF9iYXVkOworCisJaWYg KGJhdWQgPD0gMCkKKwkJcmV0dXJuIC1FSU5WQUw7CisKKwkvKgorCSAqIE9uIEggRGV2aWNlcywg dXNlIDEyMDAwMDAwIGJhdWRyYXRlIHdoZW4gcG9zc2libGUuCisJICogV2UgaGF2ZSBhIDE0IGJp dCBkaXZpc29yLCBhIDEgYml0IGRpdmlzb3Igc3dpdGNoICgxMCBvciAxNiksCisJICogdGhyZWUg ZnJhY3Rpb25hbCBiaXRzIGFuZCBhIDEyMCBNSHogY2xvY2suIEFzc3VtZSBBTl8xMjAKKwkgKiAi U3ViLWludGVnZXIgZGl2aXNvcnMgYmV0d2VlbiAwIGFuZCAyIGFyZSBub3QgYWxsb3dlZCIgaG9s ZHMKKwkgKiBmb3IgRElWLzEwIENMSyB0b28sIHNvIC8xLCAvMS41IGFuZCAvMiBjYW4gYmUgaGFu ZGxlZCB0aGUgc2FtZQorCSAqLworCWlmIChiYXVkICogMTAgPiBIX0NMSyAvIDB4M2ZmZikgewor CQliZXN0X2JhdWQgPSBmdGRpX3RvX2Nsa2JpdHMoYmF1ZCwgSF9DTEssIDEwLCAmZW5jb2RlZF9k aXZpc29yKTsKKwkJZW5jb2RlZF9kaXZpc29yIHw9IDB4MjAwMDA7CS8qIHN3aXRjaCBvbiBDTEsv MTAgKi8KKwl9IGVsc2UgeworCQliZXN0X2JhdWQgPSBmdGRpX3RvX2Nsa2JpdHMoYmF1ZCwgQ19D TEssIDE2LCAmZW5jb2RlZF9kaXZpc29yKTsKKwl9CisKKwlpZiAoIWJlc3RfYmF1ZCkgeworCQlw cl9lcnIoIkludmFsaWQgYmF1ZHJhdGU6ICVkXG4iLCBiYXVkKTsKKwkJcmV0dXJuIC1FSU5WQUw7 CisJfQorCisJLyogQ2hlY2sgd2l0aGluIHRvbGVyYW5jZSAoYWJvdXQgNSUpICovCisJaWYgKChi ZXN0X2JhdWQgKiAyIDwgYmF1ZCkgfHwKKwkgICAgKGJlc3RfYmF1ZCA8IGJhdWQKKwkJPyAoYmVz dF9iYXVkICogMjEgPCBiYXVkICogMjApCisJCTogKGJhdWQgKiAyMSA8IGJlc3RfYmF1ZCAqIDIw KSkpIHsKKwkJcHJfZXJyKCJVbnN1cHBvcnRlZCBiYXVkcmF0ZS5cbiIpOworCQlyZXR1cm4gLUVJ TlZBTDsKKwl9CisKKwkvKiBTcGxpdCBpbnRvICJ2YWx1ZSIgYW5kICJpbmRleCIgdmFsdWVzICov CisJKnZhbHVlID0gKHUxNikoZW5jb2RlZF9kaXZpc29yICYgMHhmZmZmKTsKKwkqaW5kZXggPSAo dTE2KSgoKGVuY29kZWRfZGl2aXNvciA+PiA4KSAmIDB4ZmYwMCkgfCBwcml2LT5pbmRleCk7CisK KwlkZXZfZGJnKCZwcml2LT5pbnRmLT5kZXYsICJiZXN0IGJhdWQgJXUsIHYvaTogJWQsICVkXG4i LAorCQliZXN0X2JhdWQsICp2YWx1ZSwgKmluZGV4KTsKKwlyZXR1cm4gYmVzdF9iYXVkOworfQor CisvKgorICogZnRkaV9jdHJsX3hmZXIgLSBGVERJIGNvbnRyb2wgZW5kcG9pbnQgdHJhbnNmZXIK KyAqIEBpbnRmOiBVU0IgaW50ZXJmYWNlIHBvaW50ZXIKKyAqIEBkZXNjOiBwb2ludGVyIHRvIGRl c2NyaXB0b3Igc3RydWN0IGZvciBjb250cm9sIHRyYW5zZmVyCisgKgorICogUmV0dXJuOgorICog UmV0dXJuOiBJZiBzdWNjZXNzZnVsLCB0aGUgbnVtYmVyIG9mIGJ5dGVzIHRyYW5zZmVycmVkLiBP dGhlcndpc2UsCisgKiBhIG5lZ2F0aXZlIGVycm9yIG51bWJlci4KKyAqLworc3RhdGljIGludCBm dGRpX2N0cmxfeGZlcihzdHJ1Y3QgdXNiX2ludGVyZmFjZSAqaW50Ziwgc3RydWN0IGN0cmxfZGVz YyAqZGVzYykKK3sKKwlzdHJ1Y3QgZnQyMzJoX2ludGZfcHJpdiAqcHJpdiA9IHVzYl9nZXRfaW50 ZmRhdGEoaW50Zik7CisJc3RydWN0IHVzYl9kZXZpY2UgKnVkZXYgPSBwcml2LT51ZGV2OworCXVu c2lnbmVkIGludCBwaXBlOworCWludCByZXQ7CisKKwltdXRleF9sb2NrKCZwcml2LT5pb19tdXRl eCk7CisJaWYgKCFwcml2LT5pbnRmKSB7CisJCXJldCA9IC1FTk9ERVY7CisJCWdvdG8gZXhpdDsK Kwl9CisKKwlpZiAoIWRlc2MtPmRhdGEgJiYgZGVzYy0+c2l6ZSkKKwkJZGVzYy0+ZGF0YSA9IHBy aXYtPmJ1bGtfaW5fYnVmOworCisJaWYgKGRlc2MtPmRpcl9vdXQpCisJCXBpcGUgPSB1c2Jfc25k Y3RybHBpcGUodWRldiwgMCk7CisJZWxzZQorCQlwaXBlID0gdXNiX3JjdmN0cmxwaXBlKHVkZXYs IDApOworCisJcmV0ID0gdXNiX2NvbnRyb2xfbXNnKHVkZXYsIHBpcGUsIGRlc2MtPnJlcXVlc3Qs IGRlc2MtPnJlcXVlc3R0eXBlLAorCQkJICAgICAgZGVzYy0+dmFsdWUsIGRlc2MtPmluZGV4LCBk ZXNjLT5kYXRhLCBkZXNjLT5zaXplLAorCQkJICAgICAgZGVzYy0+dGltZW91dCk7CisJaWYgKHJl dCA8IDApCisJCWRldl9kYmcoJnVkZXYtPmRldiwgImN0cmwgbXNnIGZhaWxlZDogJWRcbiIsIHJl dCk7CitleGl0OgorCW11dGV4X3VubG9jaygmcHJpdi0+aW9fbXV0ZXgpOworCXJldHVybiByZXQ7 Cit9CisKKy8qCisgKiBmdGRpX2J1bGtfeGZlciAtIEZUREkgYnVsayBlbmRwb2ludCB0cmFuc2Zl cgorICogQGludGY6IFVTQiBpbnRlcmZhY2UgcG9pbnRlcgorICogQGRlc2M6IHBvaW50ZXIgdG8g ZGVzY3JpcHRvciBzdHJ1Y3QgZm9yIGJ1bGstaW4gb3IgYnVsay1vdXQgdHJhbnNmZXIKKyAqCisg KiBSZXR1cm46CisgKiBJZiBzdWNjZXNzZnVsLCAwLiBPdGhlcndpc2UgYSBuZWdhdGl2ZSBlcnJv ciBudW1iZXIuIFRoZSBudW1iZXIgb2YKKyAqIGFjdHVhbCBieXRlcyB0cmFuc2ZlcnJlZCB3aWxs IGJlIHN0b3JlZCBpbiB0aGUgQGRlc2MtPmFjdF9sZW4gZmllbGQKKyAqIG9mIHRoZSBkZXNjcmlw dG9yIHN0cnVjdC4KKyAqLworc3RhdGljIGludCBmdGRpX2J1bGtfeGZlcihzdHJ1Y3QgdXNiX2lu dGVyZmFjZSAqaW50Ziwgc3RydWN0IGJ1bGtfZGVzYyAqZGVzYykKK3sKKwlzdHJ1Y3QgZnQyMzJo X2ludGZfcHJpdiAqcHJpdiA9IHVzYl9nZXRfaW50ZmRhdGEoaW50Zik7CisJc3RydWN0IHVzYl9k ZXZpY2UgKnVkZXYgPSBwcml2LT51ZGV2OworCXVuc2lnbmVkIGludCBwaXBlOworCWludCByZXQ7 CisKKwltdXRleF9sb2NrKCZwcml2LT5pb19tdXRleCk7CisJaWYgKCFwcml2LT5pbnRmKSB7CisJ CXJldCA9IC1FTk9ERVY7CisJCWdvdG8gZXhpdDsKKwl9CisKKwlpZiAoZGVzYy0+ZGlyX291dCkK KwkJcGlwZSA9IHVzYl9zbmRidWxrcGlwZSh1ZGV2LCBwcml2LT5idWxrX291dCk7CisJZWxzZQor CQlwaXBlID0gdXNiX3JjdmJ1bGtwaXBlKHVkZXYsIHByaXYtPmJ1bGtfaW4pOworCisJcmV0ID0g dXNiX2J1bGtfbXNnKHVkZXYsIHBpcGUsIGRlc2MtPmRhdGEsIGRlc2MtPmxlbiwKKwkJCSAgICZk ZXNjLT5hY3RfbGVuLCBkZXNjLT50aW1lb3V0KTsKKwlpZiAocmV0KQorCQlkZXZfZGJnKCZ1ZGV2 LT5kZXYsICJidWxrIG1zZyBmYWlsZWQ6ICVkXG4iLCByZXQpOworCitleGl0OgorCW11dGV4X3Vu bG9jaygmcHJpdi0+aW9fbXV0ZXgpOworCXJldHVybiByZXQ7Cit9CisKKy8qCisgKiBmdGRpX3Nl dF9iYXVkcmF0ZSAtIHNldCB0aGUgZGV2aWNlIGJhdWQgcmF0ZQorICogQGludGY6IFVTQiBpbnRl cmZhY2UgcG9pbnRlcgorICogQGJhdWRyYXRlOiBiYXVkIHJhdGUgdmFsdWUgdG8gc2V0CisgKgor ICogUmV0dXJuOiBJZiBzdWNjZXNzZnVsLCAwLiBPdGhlcndpc2UgYSBuZWdhdGl2ZSBlcnJvciBu dW1iZXIuCisgKi8KK3N0YXRpYyBpbnQgZnRkaV9zZXRfYmF1ZHJhdGUoc3RydWN0IHVzYl9pbnRl cmZhY2UgKmludGYsIGludCBiYXVkcmF0ZSkKK3sKKwlzdHJ1Y3QgZnQyMzJoX2ludGZfcHJpdiAq cHJpdiA9IHVzYl9nZXRfaW50ZmRhdGEoaW50Zik7CisJc3RydWN0IGN0cmxfZGVzYyBkZXNjOwor CXUxNiBpbmRleCwgdmFsdWU7CisJaW50IHJldDsKKworCWlmIChwcml2LT5iaXRiYW5nX2VuYWJs ZWQpCisJCWJhdWRyYXRlICo9IDQ7CisKKwlyZXQgPSBmdGRpX2NvbnZlcnRfYmF1ZHJhdGUocHJp diwgYmF1ZHJhdGUsICZ2YWx1ZSwgJmluZGV4KTsKKwlpZiAocmV0IDwgMCkKKwkJcmV0dXJuIHJl dDsKKworCWRlc2MuZGlyX291dCA9IHRydWU7CisJZGVzYy5yZXF1ZXN0ID0gRlRESV9TSU9fU0VU X0JBVURSQVRFX1JFUVVFU1Q7CisJZGVzYy5yZXF1ZXN0dHlwZSA9IFVTQl9UWVBFX1ZFTkRPUiB8 IFVTQl9SRUNJUF9ERVZJQ0UgfCBVU0JfRElSX09VVDsKKwlkZXNjLnZhbHVlID0gdmFsdWU7CisJ ZGVzYy5pbmRleCA9IGluZGV4OworCWRlc2MuZGF0YSA9IE5VTEw7CisJZGVzYy5zaXplID0gMDsK KwlkZXNjLnRpbWVvdXQgPSBVU0JfQ1RSTF9TRVRfVElNRU9VVDsKKworCXJldCA9IGZ0ZGlfY3Ry bF94ZmVyKGludGYsICZkZXNjKTsKKwlpZiAocmV0IDwgMCkgeworCQlkZXZfZGJnKCZpbnRmLT5k ZXYsICJmYWlsZWQgdG8gc2V0IGJhdWRyYXRlOiAlZFxuIiwgcmV0KTsKKwkJcmV0dXJuIHJldDsK Kwl9CisKKwlyZXR1cm4gMDsKK30KKworLyoKKyAqIGZ0ZGlfcmVhZF9kYXRhIC0gcmVhZCBmcm9t IEZUREkgYnVsay1pbiBlbmRwb2ludAorICogQGludGY6IFVTQiBpbnRlcmZhY2UgcG9pbnRlcgor ICogQGJ1ZjogIHBvaW50ZXIgdG8gZGF0YSBidWZmZXIKKyAqIEBsZW46ICBsZW5ndGggaW4gYnl0 ZXMgb2YgdGhlIGRhdGEgdG8gcmVhZAorICoKKyAqIFRoZSB0d28gbW9kZW0gc3RhdHVzIGJ5dGVz IHRyYW5zZmVycmVkIGluIGV2ZXJ5IHJlYWQgd2lsbAorICogYmUgcmVtb3ZlZCBhbmQgd2lsbCBu b3QgYXBwZWFyIGluIHRoZSBkYXRhIGJ1ZmZlci4KKyAqCisgKiBSZXR1cm46CisgKiBJZiBzdWNj ZXNzZnVsLCB0aGUgbnVtYmVyIG9mIGRhdGEgYnl0ZXMgcmVjZWl2ZWQgKGNhbiBiZSAwKS4KKyAq IE90aGVyd2lzZSwgYSBuZWdhdGl2ZSBlcnJvciBudW1iZXIuCisgKi8KK3N0YXRpYyBpbnQgZnRk aV9yZWFkX2RhdGEoc3RydWN0IHVzYl9pbnRlcmZhY2UgKmludGYsIHZvaWQgKmJ1Ziwgc2l6ZV90 IGxlbikKK3sKKwlzdHJ1Y3QgZnQyMzJoX2ludGZfcHJpdiAqcHJpdiA9IHVzYl9nZXRfaW50ZmRh dGEoaW50Zik7CisJc3RydWN0IGJ1bGtfZGVzYyBkZXNjOworCWludCByZXQ7CisKKwlkZXNjLmFj dF9sZW4gPSAwOworCWRlc2MuZGlyX291dCA9IGZhbHNlOworCWRlc2MuZGF0YSA9IHByaXYtPmJ1 bGtfaW5fYnVmOworCS8qIERldmljZSBzZW5kcyAyIGFkZGl0aW9uYWwgc3RhdHVzIGJ5dGVzLCBy ZWFkIGF0IGxlYXN0IGxlbiArIDIgKi8KKwlkZXNjLmxlbiA9IG1pbl90KHNpemVfdCwgbGVuICsg MiwgcHJpdi0+YnVsa19pbl9zeik7CisJZGVzYy50aW1lb3V0ID0gRlRESV9VU0JfUkVBRF9USU1F T1VUOworCisJcmV0ID0gZnRkaV9idWxrX3hmZXIoaW50ZiwgJmRlc2MpOworCWlmIChyZXQpCisJ CXJldHVybiByZXQ7CisKKwkvKiBPbmx5IHN0YXR1cyBieXRlcyBhbmQgbm8gZGF0YT8gKi8KKwlp ZiAoZGVzYy5hY3RfbGVuIDw9IDIpCisJCXJldHVybiAwOworCisJLyogU2tpcCBmaXJzdCB0d28g c3RhdHVzIGJ5dGVzICovCisJcmV0ID0gZGVzYy5hY3RfbGVuIC0gMjsKKwlpZiAocmV0ID4gbGVu KQorCQlyZXQgPSBsZW47CisJbWVtY3B5KGJ1ZiwgZGVzYy5kYXRhICsgMiwgcmV0KTsKKwlyZXR1 cm4gcmV0OworfQorCisvKgorICogZnRkaV93cml0ZV9kYXRhIC0gd3JpdGUgdG8gRlRESSBidWxr LW91dCBlbmRwb2ludAorICogQGludGY6IFVTQiBpbnRlcmZhY2UgcG9pbnRlcgorICogQGJ1Zjog IHBvaW50ZXIgdG8gZGF0YSBidWZmZXIKKyAqIEBsZW46ICBsZW5ndGggaW4gYnl0ZXMgb2YgdGhl IGRhdGEgdG8gc2VuZAorICoKKyAqIFJldHVybjoKKyAqIElmIHN1Y2Nlc3NmdWwsIHRoZSBudW1i ZXIgb2YgYnl0ZXMgdHJhbnNmZXJyZWQuIE90aGVyd2lzZSBhIG5lZ2F0aXZlCisgKiBlcnJvciBu dW1iZXIuCisgKi8KK3N0YXRpYyBpbnQgZnRkaV93cml0ZV9kYXRhKHN0cnVjdCB1c2JfaW50ZXJm YWNlICppbnRmLAorCQkJICAgY29uc3QgY2hhciAqYnVmLCBzaXplX3QgbGVuKQoreworCXN0cnVj dCBidWxrX2Rlc2MgZGVzYzsKKwlpbnQgcmV0OworCisJZGVzYy5hY3RfbGVuID0gMDsKKwlkZXNj LmRpcl9vdXQgPSB0cnVlOworCWRlc2MuZGF0YSA9IChjaGFyICopYnVmOworCWRlc2MubGVuID0g bGVuOworCWRlc2MudGltZW91dCA9IEZURElfVVNCX1dSSVRFX1RJTUVPVVQ7CisKKwlyZXQgPSBm dGRpX2J1bGtfeGZlcihpbnRmLCAmZGVzYyk7CisJaWYgKHJldCA8IDApCisJCXJldHVybiByZXQ7 CisKKwlyZXR1cm4gZGVzYy5hY3RfbGVuOworfQorCisvKgorICogZnRkaV9zZXRfYml0bW9kZSAt IGNvbmZpZ3VyZSBiaXRiYW5nIG1vZGUKKyAqIEBpbnRmOiBVU0IgaW50ZXJmYWNlIHBvaW50ZXIK KyAqIEBiaXRtYXNrOiBsaW5lIGNvbmZpZ3VyYXRpb24gYml0bWFzaworICogQG1vZGU6IGJpdGJh bmcgbW9kZSB0byBzZXQKKyAqCisgKiBSZXR1cm46CisgKiBJZiBzdWNjZXNzZnVsLCAwLiBPdGhl cndpc2UgYSBuZWdhdGl2ZSBlcnJvciBudW1iZXIuCisgKi8KK3N0YXRpYyBpbnQgZnRkaV9zZXRf Yml0bW9kZShzdHJ1Y3QgdXNiX2ludGVyZmFjZSAqaW50ZiwgdW5zaWduZWQgY2hhciBiaXRtYXNr LAorCQkJICAgIHVuc2lnbmVkIGNoYXIgbW9kZSkKK3sKKwlzdHJ1Y3QgZnQyMzJoX2ludGZfcHJp diAqcHJpdiA9IHVzYl9nZXRfaW50ZmRhdGEoaW50Zik7CisJc3RydWN0IGN0cmxfZGVzYyBkZXNj OworCWludCByZXQ7CisKKwlkZXNjLmRpcl9vdXQgPSB0cnVlOworCWRlc2MuZGF0YSA9IE5VTEw7 CisJZGVzYy5yZXF1ZXN0ID0gRlRESV9TSU9fU0VUX0JJVE1PREVfUkVRVUVTVDsKKwlkZXNjLnJl cXVlc3R0eXBlID0gVVNCX1RZUEVfVkVORE9SIHwgVVNCX1JFQ0lQX0RFVklDRSB8IFVTQl9ESVJf T1VUOworCWRlc2MuaW5kZXggPSAxOworCWRlc2MudmFsdWUgPSAobW9kZSA8PCA4KSB8IGJpdG1h c2s7CisJZGVzYy5zaXplID0gMDsKKwlkZXNjLnRpbWVvdXQgPSBVU0JfQ1RSTF9TRVRfVElNRU9V VDsKKworCXJldCA9IGZ0ZGlfY3RybF94ZmVyKGludGYsICZkZXNjKTsKKwlpZiAocmV0IDwgMCkK KwkJcmV0dXJuIHJldDsKKworCXN3aXRjaCAobW9kZSkgeworCWNhc2UgQklUTU9ERV9CSVRCQU5H OgorCWNhc2UgQklUTU9ERV9DQlVTOgorCWNhc2UgQklUTU9ERV9TWU5DQkI6CisJY2FzZSBCSVRN T0RFX1NZTkNGRjoKKwkJcHJpdi0+Yml0YmFuZ19lbmFibGVkID0gMTsKKwkJYnJlYWs7CisJY2Fz ZSBCSVRNT0RFX01QU1NFOgorCWNhc2UgQklUTU9ERV9SRVNFVDoKKwlkZWZhdWx0OgorCQlwcml2 LT5iaXRiYW5nX2VuYWJsZWQgPSAwOworCQlicmVhazsKKwl9CisKKwlyZXR1cm4gMDsKK30KKwor LyoKKyAqIGZ0ZGlfZGlzYWJsZV9iaXRiYW5nIC0gZGlzYWJsZSBiaXRiYW5nIG1vZGUKKyAqIEBp bnRmOiBVU0IgaW50ZXJmYWNlIHBvaW50ZXIKKyAqCisgKiBSZXR1cm46CisgKiBJZiBzdWNjZXNz ZnVsLCAwLiBPdGhlcndpc2UgYSBuZWdhdGl2ZSBlcnJvciBudW1iZXIuCisgKi8KK3N0YXRpYyBp bnQgZnRkaV9kaXNhYmxlX2JpdGJhbmcoc3RydWN0IHVzYl9pbnRlcmZhY2UgKmludGYpCit7CisJ aW50IHJldDsKKworCXJldCA9IGZ0ZGlfc2V0X2JpdG1vZGUoaW50ZiwgMCwgQklUTU9ERV9SRVNF VCk7CisJaWYgKHJldCA8IDApIHsKKwkJZGV2X2RiZygmaW50Zi0+ZGV2LCAiZGlzYWJsZSBiaXRi YW5nIGZhaWxlZDogJWRcbiIsIHJldCk7CisJCXJldHVybiByZXQ7CisJfQorCisJcmV0dXJuIDA7 Cit9CisKK3N0YXRpYyBpbnQgZnRkaV9yZWFkX2VlcHJvbShzdHJ1Y3QgZnQyMzJoX2ludGZfcHJp diAqcHJpdikKK3sKKwlzdHJ1Y3QgY3RybF9kZXNjIGRlc2M7CisJdW5zaWduZWQgaW50IGk7CisJ aW50IHJldDsKKworCWRlc2MuZGlyX291dCA9IGZhbHNlOworCWRlc2MucmVxdWVzdCA9IEZURElf U0lPX1JFQURfRUVQUk9NX1JFUVVFU1Q7CisJZGVzYy5yZXF1ZXN0dHlwZSA9IFVTQl9UWVBFX1ZF TkRPUiB8IFVTQl9SRUNJUF9ERVZJQ0UgfCBVU0JfRElSX0lOOworCWRlc2MudmFsdWUgPSAwOwor CWRlc2Muc2l6ZSA9IDI7CisJZGVzYy50aW1lb3V0ID0gVVNCX0NUUkxfR0VUX1RJTUVPVVQ7CisK Kwlmb3IgKGkgPSAwOyBpIDwgRlRESV9NQVhfRUVQUk9NX1NJWkUgLyAyOyBpKyspIHsKKwkJZGVz Yy5pbmRleCA9IGk7CisJCWRlc2MuZGF0YSA9ICZwcml2LT5lZXByb21baSAqIDJdOworCisJCXJl dCA9IGZ0ZGlfY3RybF94ZmVyKHByaXYtPmludGYsICZkZXNjKTsKKwkJaWYgKHJldCA8IDApIHsK KwkJCWRldl9kYmcoJnByaXYtPmludGYtPmRldiwgIkVFUFJPTSByZWFkIGZhaWxlZDogJWRcbiIs CisJCQkJcmV0KTsKKwkJCXJldHVybiByZXQ7CisJCX0KKwl9CisKKwlwcmludF9oZXhfZHVtcF9k ZWJ1ZygiRUVQUk9NOiAiLCBEVU1QX1BSRUZJWF9PRkZTRVQsIDE2LCAxLAorCQkJICAgICBwcml2 LT5lZXByb20sIHNpemVvZihwcml2LT5lZXByb20pLCAxKTsKKwlyZXR1cm4gMDsKK30KKworLyoK KyAqIEFDQlVTIEdQSU8gZnVuY3Rpb25zCisgKi8KK3N0YXRpYyBjb25zdCBjaGFyICpmdGRpX2Fj YnVzX25hbWVzWzVdID0geworCSJBQ0JVUzUiLCAiQUNCVVM2IiwgTlVMTCwgIkFDQlVTOCIsICJB Q0JVUzkiCit9OworCitzdGF0aWMgaW50IGZ0ZGlfY2J1c19ncGlvX3JlYWRfcGlucyhzdHJ1Y3Qg ZnQyMzJoX2ludGZfcHJpdiAqcHJpdiwKKwkJCQkgICAgdW5zaWduZWQgY2hhciAqcGlucykKK3sK KwlzdHJ1Y3QgZ3Bpb19jaGlwICpjaGlwID0gJnByaXYtPmNidXNfZ3BpbzsKKwlzdHJ1Y3QgY3Ry bF9kZXNjIGRlc2M7CisJaW50IHJldDsKKworCWRlc2MuZGlyX291dCA9IGZhbHNlOworCWRlc2Mu cmVxdWVzdCA9IEZURElfU0lPX1JFQURfUElOU19SRVFVRVNUOworCWRlc2MucmVxdWVzdHR5cGUg PSBVU0JfVFlQRV9WRU5ET1IgfCBVU0JfUkVDSVBfREVWSUNFIHwgVVNCX0RJUl9JTjsKKwlkZXNj LnZhbHVlID0gMDsKKwlkZXNjLmluZGV4ID0gMTsKKwlkZXNjLmRhdGEgPSAmcHJpdi0+cGluYnVm WzBdOworCWRlc2Muc2l6ZSA9IDE7CisJZGVzYy50aW1lb3V0ID0gVVNCX0NUUkxfR0VUX1RJTUVP VVQ7CisKKwlyZXQgPSBmdGRpX2N0cmxfeGZlcihwcml2LT5pbnRmLCAmZGVzYyk7CisJaWYgKHJl dCA8IDApIHsKKwkJZGV2X2RiZyhjaGlwLT5wYXJlbnQsICJmYWlsZWQgdG8gZ2V0IHBpbiB2YWx1 ZXM6ICVkXG4iLCByZXQpOworCQlyZXR1cm4gcmV0OworCX0KKworCSpwaW5zID0gcHJpdi0+cGlu YnVmWzBdOworCXJldHVybiAwOworfQorCitzdGF0aWMgaW5saW5lIHZvaWQgZnRkaV9jYnVzX2lu aXRfZ3Bpb19kYXRhKHN0cnVjdCBmdDIzMmhfaW50Zl9wcml2ICpwcml2LAorCQkJCQkgICAgaW50 IGdwaW9fbnVtLCBpbnQgY2J1c19udW0pCit7CisJc3dpdGNoIChjYnVzX251bSkgeworCWNhc2Ug NToKKwljYXNlIDY6CisJCXByaXYtPmNidXNfcGluX29mZnNldHNbZ3Bpb19udW1dID0gY2J1c19u dW0gLSA1OworCQlicmVhazsKKwljYXNlIDg6CisJY2FzZSA5OgorCQlwcml2LT5jYnVzX3Bpbl9v ZmZzZXRzW2dwaW9fbnVtXSA9IGNidXNfbnVtIC0gNjsKKwkJYnJlYWs7CisJZGVmYXVsdDoKKwkJ cmV0dXJuOworCX0KKworCXByaXYtPmNidXNfZ3Bpb19uYW1lc1tncGlvX251bV0gPSBmdGRpX2Fj YnVzX25hbWVzW2NidXNfbnVtIC0gNV07Cit9CisKK3N0YXRpYyBpbnQgZnRkaV9jYnVzX2dwaW9f Z2V0KHN0cnVjdCBncGlvX2NoaXAgKmNoaXAsIHVuc2lnbmVkIGludCBvZmZzZXQpCit7CisJc3Ry dWN0IGZ0MjMyaF9pbnRmX3ByaXYgKnByaXYgPSBncGlvY2hpcF9nZXRfZGF0YShjaGlwKTsKKwl1 bnNpZ25lZCBpbnQgb2ZmczsKKwlpbnQgcmV0OworCXU4IHBpbnMgPSAwOworCisJcmV0ID0gZnRk aV9jYnVzX2dwaW9fcmVhZF9waW5zKHByaXYsICZwaW5zKTsKKwlpZiAocmV0KQorCQlyZXR1cm4g cmV0OworCisJb2ZmcyA9IHByaXYtPmNidXNfcGluX29mZnNldHNbb2Zmc2V0XTsKKworCXJldHVy biAhIShwaW5zICYgQklUKG9mZnMpKTsKK30KKworc3RhdGljIHZvaWQgZnRkaV9jYnVzX2dwaW9f c2V0KHN0cnVjdCBncGlvX2NoaXAgKmNoaXAsCisJCQkgICAgICAgdW5zaWduZWQgaW50IG9mZnNl dCwgaW50IHZhbHVlKQoreworCXN0cnVjdCBmdDIzMmhfaW50Zl9wcml2ICpwcml2ID0gZ3Bpb2No aXBfZ2V0X2RhdGEoY2hpcCk7CisJdW5zaWduZWQgaW50IG9mZnM7CisJaW50IHJldDsKKworCW9m ZnMgPSBwcml2LT5jYnVzX3Bpbl9vZmZzZXRzW29mZnNldF07CisKKwlpZiAodmFsdWUpCisJCXBy aXYtPmNidXNfbWFzayB8PSBCSVQob2Zmcyk7CisJZWxzZQorCQlwcml2LT5jYnVzX21hc2sgJj0g fkJJVChvZmZzKTsKKworCXJldCA9IGZ0ZGlfc2V0X2JpdG1vZGUocHJpdi0+aW50ZiwgcHJpdi0+ Y2J1c19tYXNrLCBCSVRNT0RFX0NCVVMpOworCWlmIChyZXQgPCAwKQorCQlkZXZfZGJnKGNoaXAt PnBhcmVudCwgInNldHRpbmcgcGluIHZhbHVlIGZhaWxlZDogJWRcbiIsIHJldCk7Cit9CisKK3N0 YXRpYyBpbnQgZnRkaV9jYnVzX2dwaW9fZGlyZWN0aW9uX2lucHV0KHN0cnVjdCBncGlvX2NoaXAg KmNoaXAsCisJCQkJCSAgdW5zaWduZWQgaW50IG9mZnNldCkKK3sKKwlzdHJ1Y3QgZnQyMzJoX2lu dGZfcHJpdiAqcHJpdiA9IGdwaW9jaGlwX2dldF9kYXRhKGNoaXApOworCXVuc2lnbmVkIGludCBv ZmZzOworCisJb2ZmcyA9IHByaXYtPmNidXNfcGluX29mZnNldHNbb2Zmc2V0XTsKKwkvKiBEaXJl Y3Rpb24gYml0cyBhcmUgaW4gdGhlIHVwcGVyIG5pYmJsZSAqLworCXByaXYtPmNidXNfbWFzayAm PSB+KEJJVChvZmZzKSA8PCA0KTsKKworCXJldHVybiBmdGRpX3NldF9iaXRtb2RlKHByaXYtPmlu dGYsIHByaXYtPmNidXNfbWFzaywgQklUTU9ERV9DQlVTKTsKK30KKworc3RhdGljIGludCBmdGRp X2NidXNfZ3Bpb19kaXJlY3Rpb25fb3V0cHV0KHN0cnVjdCBncGlvX2NoaXAgKmNoaXAsCisJCQkJ CSAgIHVuc2lnbmVkIGludCBvZmZzZXQsIGludCB2YWx1ZSkKK3sKKwlzdHJ1Y3QgZnQyMzJoX2lu dGZfcHJpdiAqcHJpdiA9IGdwaW9jaGlwX2dldF9kYXRhKGNoaXApOworCXVuc2lnbmVkIGludCBv ZmZzOworCisJb2ZmcyA9IHByaXYtPmNidXNfcGluX29mZnNldHNbb2Zmc2V0XTsKKwlwcml2LT5j YnVzX21hc2sgfD0gQklUKG9mZnMpIDw8IDQ7CisKKwlpZiAodmFsdWUpCisJCXByaXYtPmNidXNf bWFzayB8PSBCSVQob2Zmcyk7CisJZWxzZQorCQlwcml2LT5jYnVzX21hc2sgJj0gfkJJVChvZmZz KTsKKworCXJldHVybiBmdGRpX3NldF9iaXRtb2RlKHByaXYtPmludGYsIHByaXYtPmNidXNfbWFz aywgQklUTU9ERV9DQlVTKTsKK30KKworc3RhdGljIGludCBmdDIzMmhfaW50Zl9hZGRfY2J1c19n cGlvKHN0cnVjdCBmdDIzMmhfaW50Zl9wcml2ICpwcml2KQoreworCXN0cnVjdCBkZXZpY2UgKmRl diA9ICZwcml2LT5pbnRmLT5kZXY7CisJY2hhciAqKm5hbWVzLCAqbGFiZWw7CisJaW50IG5ncGlv ID0gMDsKKwlpbnQgaSwgcmV0OworCXU4IHZhbDsKKworCXJldCA9IGZ0ZGlfcmVhZF9lZXByb20o cHJpdik7CisJaWYgKHJldCA8IDApCisJCXJldHVybiByZXQ7CisKKwkvKiBDaGVjayBpZiBJL08g bW9kZSBpcyBlbmFibGVkIGZvciBzdXBwb3J0ZWQgcGlucyA1LCA2LCA4LCA5ICovCisJZm9yIChp ID0gNTsgaSA8IDEwOyBpKyspIHsKKwkJdmFsID0gcHJpdi0+ZWVwcm9tWzB4MTggKyBpIC8gMl0g Pj4gKGkgJSAyID8gNCA6IDApOworCQlpZiAoKHZhbCAmIDB4MGYpID09IEZURElfMjMySF9DQlVT X0lPTU9ERSkgeworCQkJZGV2X2RiZyhkZXYsICJncGlvLSVkIEAgQUNCVVMlZFxuIiwKKwkJCQlw cml2LT5jYnVzX2dwaW8ubmdwaW8sIGkpOworCQkJcHJpdi0+Y2J1c19ncGlvLm5ncGlvKys7CisJ CQlmdGRpX2NidXNfaW5pdF9ncGlvX2RhdGEocHJpdiwgbmdwaW8rKywgaSk7CisJCX0KKwl9CisK KwlpZiAoIXByaXYtPmNidXNfZ3Bpby5uZ3BpbykgeworCQlkZXZfd2FybihkZXYsICJJL08gbW9k ZSBkaXNhYmxlZCBpbiBFRVBST01cbiIpOworCQlyZXR1cm4gLUVOT0RFVjsKKwl9CisKKwlsYWJl bCA9IGRldm1fa2FzcHJpbnRmKGRldiwgR0ZQX0tFUk5FTCwgImZ0ZGktY2J1cy1ncGlvLiVkIiwg cHJpdi0+aWQpOworCWlmICghbGFiZWwpCisJCXJldHVybiAtRU5PTUVNOworCisJcHJpdi0+Y2J1 c19ncGlvLmxhYmVsID0gbGFiZWw7CisJcHJpdi0+Y2J1c19ncGlvLnBhcmVudCA9IGRldjsKKwlw cml2LT5jYnVzX2dwaW8ub3duZXIgPSBUSElTX01PRFVMRTsKKwlwcml2LT5jYnVzX2dwaW8uYmFz ZSA9IC0xOworCXByaXYtPmNidXNfZ3Bpby5jYW5fc2xlZXAgPSB0cnVlOworCXByaXYtPmNidXNf Z3Bpby5zZXQgPSBmdGRpX2NidXNfZ3Bpb19zZXQ7CisJcHJpdi0+Y2J1c19ncGlvLmdldCA9IGZ0 ZGlfY2J1c19ncGlvX2dldDsKKwlwcml2LT5jYnVzX2dwaW8uZGlyZWN0aW9uX2lucHV0ID0gZnRk aV9jYnVzX2dwaW9fZGlyZWN0aW9uX2lucHV0OworCXByaXYtPmNidXNfZ3Bpby5kaXJlY3Rpb25f b3V0cHV0ID0gZnRkaV9jYnVzX2dwaW9fZGlyZWN0aW9uX291dHB1dDsKKworCW5hbWVzID0gZGV2 bV9rY2FsbG9jKGRldiwgcHJpdi0+Y2J1c19ncGlvLm5ncGlvLCBzaXplb2YoY2hhciAqKSwKKwkJ CSAgICAgR0ZQX0tFUk5FTCk7CisJaWYgKCFuYW1lcykKKwkJcmV0dXJuIC1FTk9NRU07CisKKwlm b3IgKGkgPSAwOyBpIDwgcHJpdi0+Y2J1c19ncGlvLm5ncGlvOyBpKyspIHsKKwkJaWYgKCFwcml2 LT5jYnVzX2dwaW9fbmFtZXNbaV0pCisJCQljb250aW51ZTsKKwkJbmFtZXNbaV0gPSBkZXZtX2th c3ByaW50ZihkZXYsIEdGUF9LRVJORUwsICJjYnVzLiVkLSVzIiwKKwkJCQkJICBwcml2LT5pZCwg cHJpdi0+Y2J1c19ncGlvX25hbWVzW2ldKTsKKwkJaWYgKCFuYW1lc1tpXSkKKwkJCXJldHVybiAt RU5PTUVNOworCX0KKworCXByaXYtPmNidXNfZ3Bpby5uYW1lcyA9IChjb25zdCBjaGFyICpjb25z dCAqKW5hbWVzOworCisJcmV0ID0gZGV2bV9ncGlvY2hpcF9hZGRfZGF0YShkZXYsICZwcml2LT5j YnVzX2dwaW8sIHByaXYpOworCWlmIChyZXQpIHsKKwkJZGV2X3dhcm4oZGV2LCAiZmFpbGVkIHRv IGFkZCBDQlVTIGdwaW9jaGlwOiAlZFxuIiwgcmV0KTsKKwkJcmV0dXJuIHJldDsKKwl9CisKKwlk ZXZfaW5mbyhkZXYsICJ1c2luZyAlZCBDQlVTIHBpbnNcbiIsIHByaXYtPmNidXNfZ3Bpby5uZ3Bp byk7CisJcmV0dXJuIDA7Cit9CisKKy8qCisgKiBNUFNTRSBDUyBhbmQgR1BJTy1MLy1IIHN1cHBv cnQKKyAqLworI2RlZmluZSBTRVRfQklUU19MT1cJMHg4MAorI2RlZmluZSBHRVRfQklUU19MT1cJ MHg4MQorI2RlZmluZSBTRVRfQklUU19ISUdICTB4ODIKKyNkZWZpbmUgR0VUX0JJVFNfSElHSAkw eDgzCisKK3N0YXRpYyBpbnQgZnRkaV9tcHNzZV9nZXRfcG9ydF9waW5zKHN0cnVjdCBmdDIzMmhf aW50Zl9wcml2ICpwcml2LCBib29sIGxvdykKK3sKKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSAmcHJp di0+aW50Zi0+ZGV2OworCWludCByZXQsIHRvdXQgPSAxMDsKKwl1OCByeGJ1Zls0XTsKKworCWlm IChsb3cpCisJCXByaXYtPnR4X2J1ZlswXSA9IEdFVF9CSVRTX0xPVzsKKwllbHNlCisJCXByaXYt PnR4X2J1ZlswXSA9IEdFVF9CSVRTX0hJR0g7CisKKwlyZXQgPSBmdGRpX3dyaXRlX2RhdGEocHJp di0+aW50ZiwgcHJpdi0+dHhfYnVmLCAxKTsKKwlpZiAocmV0IDwgMCkgeworCQlkZXZfZGJnX3Jh dGVsaW1pdGVkKGRldiwgIldyaXRpbmcgcG9ydCBwaW5zIGNtZCBmYWlsZWQ6ICVkXG4iLAorCQkJ CSAgICByZXQpOworCQlyZXR1cm4gcmV0OworCX0KKworCXJ4YnVmWzBdID0gMDsKKwlkbyB7CisJ CXVzbGVlcF9yYW5nZSg1MDAwLCA1MjAwKTsKKwkJcmV0ID0gZnRkaV9yZWFkX2RhdGEocHJpdi0+ aW50ZiwgcnhidWYsIDEpOworCQl0b3V0LS07CisJCWlmICghdG91dCkgeworCQkJZGV2X2Vycihk ZXYsICJUaW1lb3V0IHdoZW4gZ2V0dGluZyBwb3J0IHBpbnNcbiIpOworCQkJcmV0dXJuIC1FVElN RURPVVQ7CisJCX0KKwl9IHdoaWxlIChyZXQgPT0gMCk7CisKKwlpZiAocmV0IDwgMCkKKwkJcmV0 dXJuIHJldDsKKworCWlmIChyZXQgIT0gMSkKKwkJcmV0dXJuIC1FSU5WQUw7CisKKwlpZiAobG93 KQorCQlwcml2LT5ncGlvbF9tYXNrID0gcnhidWZbMF07CisJZWxzZQorCQlwcml2LT5ncGlvaF9t YXNrID0gcnhidWZbMF07CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGludCBmdGRpX21wc3Nl X3NldF9wb3J0X3BpbnMoc3RydWN0IGZ0MjMyaF9pbnRmX3ByaXYgKnByaXYsIGJvb2wgbG93KQor eworCXN0cnVjdCBkZXZpY2UgKmRldiA9ICZwcml2LT5pbnRmLT5kZXY7CisJaW50IHJldDsKKwor CWlmIChsb3cpIHsKKwkJcHJpdi0+dHhfYnVmWzBdID0gU0VUX0JJVFNfTE9XOworCQlwcml2LT50 eF9idWZbMV0gPSBwcml2LT5ncGlvbF9tYXNrOworCQlwcml2LT50eF9idWZbMl0gPSBwcml2LT5n cGlvbF9kaXI7CisJfSBlbHNlIHsKKwkJcHJpdi0+dHhfYnVmWzBdID0gU0VUX0JJVFNfSElHSDsK KwkJcHJpdi0+dHhfYnVmWzFdID0gcHJpdi0+Z3Bpb2hfbWFzazsKKwkJcHJpdi0+dHhfYnVmWzJd ID0gcHJpdi0+Z3Bpb2hfZGlyOworCX0KKworCXJldCA9IGZ0ZGlfd3JpdGVfZGF0YShwcml2LT5p bnRmLCBwcml2LT50eF9idWYsIDMpOworCWlmIChyZXQgPCAwKSB7CisJCWRldl9kYmdfcmF0ZWxp bWl0ZWQoZGV2LCAiRmFpbGVkIHRvIHNldCBHUElPIHBpbnM6ICVkXG4iLAorCQkJCSAgICByZXQp OworCQlyZXR1cm4gcmV0OworCX0KKworCXJldHVybiAwOworfQorCitzdGF0aWMgaW50IGZ0ZGlf bXBzc2VfZ3Bpb19nZXQoc3RydWN0IGdwaW9fY2hpcCAqY2hpcCwgdW5zaWduZWQgaW50IG9mZnNl dCkKK3sKKwlzdHJ1Y3QgZnQyMzJoX2ludGZfcHJpdiAqcHJpdiA9IGdwaW9jaGlwX2dldF9kYXRh KGNoaXApOworCWludCByZXQsIHZhbDsKKwlib29sIGxvdzsKKworCW11dGV4X2xvY2soJnByaXYt PmlvX211dGV4KTsKKwlpZiAoIXByaXYtPmludGYpIHsKKwkJbXV0ZXhfdW5sb2NrKCZwcml2LT5p b19tdXRleCk7CisJCXJldHVybiAtRU5PREVWOworCX0KKwltdXRleF91bmxvY2soJnByaXYtPmlv X211dGV4KTsKKworCWRldl9kYmcoY2hpcC0+cGFyZW50LCAiJXM6IG9mZnNldCAlZFxuIiwgX19m dW5jX18sIG9mZnNldCk7CisKKwlsb3cgPSBvZmZzZXQgPCA1OworCisJbXV0ZXhfbG9jaygmcHJp di0+b3BzX211dGV4KTsKKworCXJldCA9IGZ0ZGlfbXBzc2VfZ2V0X3BvcnRfcGlucyhwcml2LCBs b3cpOworCWlmIChyZXQgPCAwKSB7CisJCW11dGV4X3VubG9jaygmcHJpdi0+b3BzX211dGV4KTsK KwkJcmV0dXJuIHJldDsKKwl9CisKKwlpZiAobG93KQorCQl2YWwgPSBwcml2LT5ncGlvbF9tYXNr ICYgKEJJVChvZmZzZXQpIDw8IDMpOworCWVsc2UKKwkJdmFsID0gcHJpdi0+Z3Bpb2hfbWFzayAm IEJJVChvZmZzZXQgLSA1KTsKKworCW11dGV4X3VubG9jaygmcHJpdi0+b3BzX211dGV4KTsKKwor CXJldHVybiAhIXZhbDsKK30KKworc3RhdGljIHZvaWQgZnRkaV9tcHNzZV9ncGlvX3NldChzdHJ1 Y3QgZ3Bpb19jaGlwICpjaGlwLCB1bnNpZ25lZCBpbnQgb2Zmc2V0LAorCQkJCWludCB2YWx1ZSkK K3sKKwlzdHJ1Y3QgZnQyMzJoX2ludGZfcHJpdiAqcHJpdiA9IGdwaW9jaGlwX2dldF9kYXRhKGNo aXApOworCWJvb2wgbG93OworCisJbXV0ZXhfbG9jaygmcHJpdi0+aW9fbXV0ZXgpOworCWlmICgh cHJpdi0+aW50ZikgeworCQltdXRleF91bmxvY2soJnByaXYtPmlvX211dGV4KTsKKwkJcmV0dXJu OworCX0KKwltdXRleF91bmxvY2soJnByaXYtPmlvX211dGV4KTsKKworCWRldl9kYmcoY2hpcC0+ cGFyZW50LCAiJXM6IG9mZnNldCAlZCwgdmFsICVkXG4iLAorCQlfX2Z1bmNfXywgb2Zmc2V0LCB2 YWx1ZSk7CisKKwltdXRleF9sb2NrKCZwcml2LT5vcHNfbXV0ZXgpOworCisJaWYgKG9mZnNldCA8 IDUpIHsKKwkJbG93ID0gdHJ1ZTsKKwkJaWYgKHZhbHVlKQorCQkJcHJpdi0+Z3Bpb2xfbWFzayB8 PSAoQklUKG9mZnNldCkgPDwgMyk7CisJCWVsc2UKKwkJCXByaXYtPmdwaW9sX21hc2sgJj0gfihC SVQob2Zmc2V0KSA8PCAzKTsKKwl9IGVsc2UgeworCQlsb3cgPSBmYWxzZTsKKwkJaWYgKHZhbHVl KQorCQkJcHJpdi0+Z3Bpb2hfbWFzayB8PSBCSVQob2Zmc2V0IC0gNSk7CisJCWVsc2UKKwkJCXBy aXYtPmdwaW9oX21hc2sgJj0gfkJJVChvZmZzZXQgLSA1KTsKKwl9CisKKwlmdGRpX21wc3NlX3Nl dF9wb3J0X3BpbnMocHJpdiwgbG93KTsKKworCW11dGV4X3VubG9jaygmcHJpdi0+b3BzX211dGV4 KTsKK30KKworc3RhdGljIGludCBmdGRpX21wc3NlX2dwaW9fZGlyZWN0aW9uX2lucHV0KHN0cnVj dCBncGlvX2NoaXAgKmNoaXAsCisJCQkJCSAgIHVuc2lnbmVkIGludCBvZmZzZXQpCit7CisJc3Ry dWN0IGZ0MjMyaF9pbnRmX3ByaXYgKnByaXYgPSBncGlvY2hpcF9nZXRfZGF0YShjaGlwKTsKKwli b29sIGxvdzsKKwlpbnQgcmV0OworCisJbXV0ZXhfbG9jaygmcHJpdi0+aW9fbXV0ZXgpOworCWlm ICghcHJpdi0+aW50ZikgeworCQltdXRleF91bmxvY2soJnByaXYtPmlvX211dGV4KTsKKwkJcmV0 dXJuIC1FTk9ERVY7CisJfQorCW11dGV4X3VubG9jaygmcHJpdi0+aW9fbXV0ZXgpOworCisJZGV2 X2RiZyhjaGlwLT5wYXJlbnQsICIlczogb2Zmc2V0ICVkXG4iLCBfX2Z1bmNfXywgb2Zmc2V0KTsK KworCW11dGV4X2xvY2soJnByaXYtPm9wc19tdXRleCk7CisKKwlpZiAob2Zmc2V0IDwgNSkgewor CQlsb3cgPSB0cnVlOworCQlwcml2LT5ncGlvbF9kaXIgJj0gfihCSVQob2Zmc2V0KSA8PCAzKTsK Kwl9IGVsc2UgeworCQlsb3cgPSBmYWxzZTsKKwkJcHJpdi0+Z3Bpb2hfZGlyICY9IH5CSVQob2Zm c2V0IC0gNSk7CisJfQorCisJcmV0ID0gZnRkaV9tcHNzZV9zZXRfcG9ydF9waW5zKHByaXYsIGxv dyk7CisKKwltdXRleF91bmxvY2soJnByaXYtPm9wc19tdXRleCk7CisKKwlyZXR1cm4gcmV0Owor fQorCitzdGF0aWMgaW50IGZ0ZGlfbXBzc2VfZ3Bpb19kaXJlY3Rpb25fb3V0cHV0KHN0cnVjdCBn cGlvX2NoaXAgKmNoaXAsCisJCQkJCSAgICB1bnNpZ25lZCBpbnQgb2Zmc2V0LCBpbnQgdmFsdWUp Cit7CisJc3RydWN0IGZ0MjMyaF9pbnRmX3ByaXYgKnByaXYgPSBncGlvY2hpcF9nZXRfZGF0YShj aGlwKTsKKwlib29sIGxvdzsKKwlpbnQgcmV0OworCisJbXV0ZXhfbG9jaygmcHJpdi0+aW9fbXV0 ZXgpOworCWlmICghcHJpdi0+aW50ZikgeworCQltdXRleF91bmxvY2soJnByaXYtPmlvX211dGV4 KTsKKwkJcmV0dXJuIC1FTk9ERVY7CisJfQorCW11dGV4X3VubG9jaygmcHJpdi0+aW9fbXV0ZXgp OworCisJZGV2X2RiZyhjaGlwLT5wYXJlbnQsICIlczogb2Zmc2V0ICVkLCB2YWwgJWRcbiIsCisJ CV9fZnVuY19fLCBvZmZzZXQsIHZhbHVlKTsKKworCW11dGV4X2xvY2soJnByaXYtPm9wc19tdXRl eCk7CisKKwlpZiAob2Zmc2V0IDwgNSkgeworCQlsb3cgPSB0cnVlOworCQlwcml2LT5ncGlvbF9k aXIgfD0gQklUKG9mZnNldCkgPDwgMzsKKworCQlpZiAodmFsdWUpCisJCQlwcml2LT5ncGlvbF9t YXNrIHw9IEJJVChvZmZzZXQpIDw8IDM7CisJCWVsc2UKKwkJCXByaXYtPmdwaW9sX21hc2sgJj0g fihCSVQob2Zmc2V0KSA8PCAzKTsKKwl9IGVsc2UgeworCQlsb3cgPSBmYWxzZTsKKwkJcHJpdi0+ Z3Bpb2hfZGlyIHw9IEJJVChvZmZzZXQgLSA1KTsKKworCQlpZiAodmFsdWUpCisJCQlwcml2LT5n cGlvaF9tYXNrIHw9IEJJVChvZmZzZXQgLSA1KTsKKwkJZWxzZQorCQkJcHJpdi0+Z3Bpb2hfbWFz ayAmPSB+QklUKG9mZnNldCAtIDUpOworCX0KKworCXJldCA9IGZ0ZGlfbXBzc2Vfc2V0X3BvcnRf cGlucyhwcml2LCBsb3cpOworCisJbXV0ZXhfdW5sb2NrKCZwcml2LT5vcHNfbXV0ZXgpOworCisJ cmV0dXJuIHJldDsKK30KKworc3RhdGljIGludCBmdGRpX21wc3NlX2luaXRfcGlucyhzdHJ1Y3Qg dXNiX2ludGVyZmFjZSAqaW50ZiwgYm9vbCBsb3csCisJCQkJdTggYml0cywgdTggZGlyZWN0aW9u KQoreworCXN0cnVjdCBmdDIzMmhfaW50Zl9wcml2ICpwcml2ID0gdXNiX2dldF9pbnRmZGF0YShp bnRmKTsKKwlpbnQgcmV0OworCisJbXV0ZXhfbG9jaygmcHJpdi0+b3BzX211dGV4KTsKKworCWlm IChsb3cpIHsKKwkJcHJpdi0+Z3Bpb2xfbWFzayA9IGJpdHM7CisJCXByaXYtPmdwaW9sX2RpciA9 IGRpcmVjdGlvbjsKKwl9IGVsc2UgeworCQlwcml2LT5ncGlvaF9tYXNrID0gYml0czsKKwkJcHJp di0+Z3Bpb2hfZGlyID0gZGlyZWN0aW9uOworCX0KKwlyZXQgPSBmdGRpX21wc3NlX3NldF9wb3J0 X3BpbnMocHJpdiwgbG93KTsKKworCW11dGV4X3VubG9jaygmcHJpdi0+b3BzX211dGV4KTsKKwor CXJldHVybiByZXQ7Cit9CisKK3N0YXRpYyBpbnQgZnRkaV9tcHNzZV9jZmdfYnVzX3BpbnMoc3Ry dWN0IHVzYl9pbnRlcmZhY2UgKmludGYsCisJCQkJICAgdTggZGlyX2JpdHMsIHU4IHZhbHVlX2Jp dHMpCit7CisJc3RydWN0IGZ0MjMyaF9pbnRmX3ByaXYgKnByaXYgPSB1c2JfZ2V0X2ludGZkYXRh KGludGYpOworCWludCByZXQ7CisKKwltdXRleF9sb2NrKCZwcml2LT5vcHNfbXV0ZXgpOworCisJ cHJpdi0+Z3Bpb2xfZGlyICY9IH43OworCXByaXYtPmdwaW9sX2RpciB8PSAoZGlyX2JpdHMgJiA3 KTsKKworCXByaXYtPmdwaW9sX21hc2sgJj0gfjc7CisJcHJpdi0+Z3Bpb2xfbWFzayB8PSAodmFs dWVfYml0cyAmIDcpOworCisJcmV0ID0gZnRkaV9tcHNzZV9zZXRfcG9ydF9waW5zKHByaXYsIHRy dWUpOworCisJbXV0ZXhfdW5sb2NrKCZwcml2LT5vcHNfbXV0ZXgpOworCisJcmV0dXJuIHJldDsK K30KKworc3RhdGljIGludCBmdDIzMmhfaW50Zl9hZGRfbXBzc2VfZ3BpbyhzdHJ1Y3QgZnQyMzJo X2ludGZfcHJpdiAqcHJpdikKK3sKKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSAmcHJpdi0+aW50Zi0+ ZGV2OworCWNoYXIgKipuYW1lcywgKmxhYmVsOworCWludCBpLCByZXQ7CisKKwlsYWJlbCA9IGRl dm1fa2FzcHJpbnRmKGRldiwgR0ZQX0tFUk5FTCwgImZ0ZGktbXBzc2UtZ3Bpby4lZCIsIHByaXYt PmlkKTsKKwlpZiAoIWxhYmVsKQorCQlyZXR1cm4gLUVOT01FTTsKKworCXByaXYtPm1wc3NlX2dw aW8ubGFiZWwgPSBsYWJlbDsKKwlwcml2LT5tcHNzZV9ncGlvLnBhcmVudCA9IGRldjsKKwlwcml2 LT5tcHNzZV9ncGlvLm93bmVyID0gVEhJU19NT0RVTEU7CisJcHJpdi0+bXBzc2VfZ3Bpby5iYXNl ID0gLTE7CisJcHJpdi0+bXBzc2VfZ3Bpby5uZ3BpbyA9IEZURElfTVBTU0VfR1BJT1M7CisJcHJp di0+bXBzc2VfZ3Bpby5jYW5fc2xlZXAgPSB0cnVlOworCXByaXYtPm1wc3NlX2dwaW8uc2V0ID0g ZnRkaV9tcHNzZV9ncGlvX3NldDsKKwlwcml2LT5tcHNzZV9ncGlvLmdldCA9IGZ0ZGlfbXBzc2Vf Z3Bpb19nZXQ7CisJcHJpdi0+bXBzc2VfZ3Bpby5kaXJlY3Rpb25faW5wdXQgPSBmdGRpX21wc3Nl X2dwaW9fZGlyZWN0aW9uX2lucHV0OworCXByaXYtPm1wc3NlX2dwaW8uZGlyZWN0aW9uX291dHB1 dCA9IGZ0ZGlfbXBzc2VfZ3Bpb19kaXJlY3Rpb25fb3V0cHV0OworCisJbmFtZXMgPSBkZXZtX2tj YWxsb2MoZGV2LCBwcml2LT5tcHNzZV9ncGlvLm5ncGlvLCBzaXplb2YoY2hhciAqKSwKKwkJCSAg ICAgR0ZQX0tFUk5FTCk7CisJaWYgKCFuYW1lcykKKwkJcmV0dXJuIC1FTk9NRU07CisKKwluYW1l c1swXSA9IGRldm1fa2FzcHJpbnRmKGRldiwgR0ZQX0tFUk5FTCwgIm1wc3NlLiVkLUNTIiwgcHJp di0+aWQpOworCWlmICghbmFtZXNbMF0pCisJCXJldHVybiAtRU5PTUVNOworCisJZm9yIChpID0g MTsgaSA8IHByaXYtPm1wc3NlX2dwaW8ubmdwaW87IGkrKykgeworCQlpbnQgb2ZmczsKKworCQlv ZmZzID0gaSA8IDUgPyAxIDogNTsKKwkJbmFtZXNbaV0gPSBkZXZtX2thc3ByaW50ZihkZXYsIEdG UF9LRVJORUwsCisJCQkJCSAgIm1wc3NlLiVkLUdQSU8lYyVkIiwgcHJpdi0+aWQsCisJCQkJCSAg aSA8IDUgPyAnTCcgOiAnSCcsIGkgLSBvZmZzKTsKKwkJaWYgKCFuYW1lc1tpXSkKKwkJCXJldHVy biAtRU5PTUVNOworCX0KKworCXByaXYtPm1wc3NlX2dwaW8ubmFtZXMgPSAoY29uc3QgY2hhciAq Y29uc3QgKiluYW1lczsKKworCXJldCA9IGZ0ZGlfc2V0X2JpdG1vZGUocHJpdi0+aW50ZiwgMHgw MCwgQklUTU9ERV9NUFNTRSk7CisJaWYgKHJldCA8IDApIHsKKwkJZGV2X2VycihkZXYsICJGYWls ZWQgdG8gc2V0IE1QU1NFIG1vZGVcbiIpOworCQlyZXR1cm4gcmV0OworCX0KKworCXJldCA9IGRl dm1fZ3Bpb2NoaXBfYWRkX2RhdGEoZGV2LCAmcHJpdi0+bXBzc2VfZ3BpbywgcHJpdik7CisJaWYg KHJldCA8IDApIHsKKwkJZGV2X2VycihkZXYsICJGYWlsZWQgdG8gYWRkIE1QU1NFIEdQSU8gY2hp cDogJWRcbiIsIHJldCk7CisJCXJldHVybiByZXQ7CisJfQorCisJcmV0dXJuIDA7Cit9CisKK3N0 YXRpYyB2b2lkIGZ0ZGlfbG9jayhzdHJ1Y3QgdXNiX2ludGVyZmFjZSAqaW50ZikKK3sKKwlzdHJ1 Y3QgZnQyMzJoX2ludGZfcHJpdiAqcHJpdiA9IHVzYl9nZXRfaW50ZmRhdGEoaW50Zik7CisKKwlt dXRleF9sb2NrKCZwcml2LT5vcHNfbXV0ZXgpOworfQorCitzdGF0aWMgdm9pZCBmdGRpX3VubG9j ayhzdHJ1Y3QgdXNiX2ludGVyZmFjZSAqaW50ZikKK3sKKwlzdHJ1Y3QgZnQyMzJoX2ludGZfcHJp diAqcHJpdiA9IHVzYl9nZXRfaW50ZmRhdGEoaW50Zik7CisKKwltdXRleF91bmxvY2soJnByaXYt Pm9wc19tdXRleCk7Cit9CisKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgZnQyMzJoX2ludGZfb3BzIGZ0 MjMyaF9pbnRmX29wcyA9IHsKKwkuY3RybF94ZmVyID0gZnRkaV9jdHJsX3hmZXIsCisJLmJ1bGtf eGZlciA9IGZ0ZGlfYnVsa194ZmVyLAorCS5yZWFkX2RhdGEgPSBmdGRpX3JlYWRfZGF0YSwKKwku d3JpdGVfZGF0YSA9IGZ0ZGlfd3JpdGVfZGF0YSwKKwkubG9jayA9IGZ0ZGlfbG9jaywKKwkudW5s b2NrID0gZnRkaV91bmxvY2ssCisJLnNldF9iaXRtb2RlID0gZnRkaV9zZXRfYml0bW9kZSwKKwku c2V0X2JhdWRyYXRlID0gZnRkaV9zZXRfYmF1ZHJhdGUsCisJLmRpc2FibGVfYml0YmFuZyA9IGZ0 ZGlfZGlzYWJsZV9iaXRiYW5nLAorCS5pbml0X3BpbnMgPSBmdGRpX21wc3NlX2luaXRfcGlucywK KwkuY2ZnX2J1c19waW5zID0gZnRkaV9tcHNzZV9jZmdfYnVzX3BpbnMsCit9OworCisvKgorICog RlBHQSBjb25maWcgaW50ZXJmYWNlOiBGUFAgdmlhIEZUMjQ1IEZJRk8KKyAqLworI2RlZmluZSBG UFBfSU5URl9ERVZOQU1FCSJmdGRpLWZpZm8tZnBwLW1nciIKKworc3RhdGljIHN0cnVjdCBkZXZf aW9fZGVzY19kYXRhIGZwZ2FfY2ZnX2ZwcF9kZXZfaW9bMl0gPSB7CisJeyAibmNvbmZpZyIsIDAs IEdQSU9fQUNUSVZFX0xPVyB9LAorCXsgImNvbmZfZG9uZSIsIDEsIEdQSU9fQUNUSVZFX0hJR0gg fSwKK307CisKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgZmlmb19mcHBfbWdyX3BsYXRmb3JtX2RhdGEg ZnBnYV9jZmdfZnBwX3BsYXRfZGF0YSA9IHsKKwkub3BzID0gJmZ0MjMyaF9pbnRmX29wcywKKwku aW9fZGF0YSA9IGZwZ2FfY2ZnX2ZwcF9kZXZfaW8sCisJLmlvX2RhdGFfbGVuID0gQVJSQVlfU0la RShmcGdhX2NmZ19mcHBfZGV2X2lvKSwKKwkubmNvbmZpZ19udW0gPSA4LAorCS5jb25mX2RvbmVf bnVtID0gOSwKK307CisKK3N0YXRpYyBpbnQgZnQyMzJoX2ludGZfZnBwX3Byb2JlKHN0cnVjdCB1 c2JfaW50ZXJmYWNlICppbnRmLAorCQkJCSBjb25zdCB2b2lkICpwbGF0X2RhdGEpCit7CisJc3Ry dWN0IGZ0MjMyaF9pbnRmX3ByaXYgKnByaXYgPSB1c2JfZ2V0X2ludGZkYXRhKGludGYpOworCWNv bnN0IHN0cnVjdCBmaWZvX2ZwcF9tZ3JfcGxhdGZvcm1fZGF0YSAqcGQgPSBwbGF0X2RhdGE7CisJ c3RydWN0IGRldmljZSAqZGV2ID0gJmludGYtPmRldjsKKwlzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNl ICpwZGV2OworCXN0cnVjdCBncGlvZF9sb29rdXBfdGFibGUgKmxvb2t1cDsKKwljaGFyICpjZmdk b25lLCAqbmNmZywgKnB0cjsKKwlzaXplX3QgbG9va3VwX3NpemU7CisJaW50IGksIHJldCwgZ3Bp b3MgPSAwOworCisJZGV2X2RiZyhkZXYsICIlczogcGxhdF9kYXRhICVwXG4iLCBfX2Z1bmNfXywg cGQpOworCWlmICghcGQpIHsKKwkJZGV2X2VycihkZXYsICIlczogTWlzc2luZyBwbGF0Zm9ybSBk YXRhXG4iLCBfX2Z1bmNfXyk7CisJCXJldHVybiAtRUlOVkFMOworCX0KKworCXJldCA9IGZ0MjMy aF9pbnRmX2FkZF9jYnVzX2dwaW8ocHJpdik7CisJaWYgKHJldCA8IDApCisJCXJldHVybiByZXQ7 CisKKwlsb29rdXBfc2l6ZSA9IHNpemVvZigqbG9va3VwKSArIDMgKiBzaXplb2Yoc3RydWN0IGdw aW9kX2xvb2t1cCk7CisJbG9va3VwID0gZGV2bV9remFsbG9jKGRldiwgbG9va3VwX3NpemUsIEdG UF9LRVJORUwpOworCWlmICghbG9va3VwKQorCQlyZXR1cm4gLUVOT01FTTsKKworCWxvb2t1cC0+ ZGV2X2lkID0gZGV2bV9rYXNwcmludGYoZGV2LCBHRlBfS0VSTkVMLCAiJXMuJWQiLAorCQkJCQlG UFBfSU5URl9ERVZOQU1FLCBwcml2LT5pZCk7CisJaWYgKCFsb29rdXAtPmRldl9pZCkKKwkJcmV0 dXJuIC1FTk9NRU07CisKKwluY2ZnID0gZGV2bV9rYXNwcmludGYoZGV2LCBHRlBfS0VSTkVMLCAi QUNCVVMlZCIsIHBkLT5uY29uZmlnX251bSk7CisJaWYgKCFuY2ZnKQorCQlyZXR1cm4gLUVOT01F TTsKKworCWNmZ2RvbmUgPSBkZXZtX2thc3ByaW50ZihkZXYsIEdGUF9LRVJORUwsICJBQ0JVUyVk IiwgcGQtPmNvbmZfZG9uZV9udW0pOworCWlmICghY2ZnZG9uZSkKKwkJcmV0dXJuIC1FTk9NRU07 CisKKwlmb3IgKGkgPSAwOyBpIDwgcHJpdi0+Y2J1c19ncGlvLm5ncGlvOyBpKyspIHsKKwkJaWYg KCFwcml2LT5jYnVzX2dwaW8ubmFtZXNbaV0pCisJCQljb250aW51ZTsKKworCQlwdHIgPSBzdHJz dHIocHJpdi0+Y2J1c19ncGlvLm5hbWVzW2ldLCAiQUNCVVMiKTsKKwkJaWYgKCFwdHIpCisJCQlj b250aW51ZTsKKworCQlpZiAoIXN0cm5jbXAocHRyLCBuY2ZnLCA2KSkgeworCQkJbG9va3VwLT50 YWJsZVswXS5jaGlwX2h3bnVtID0gaTsKKwkJCWdwaW9zKys7CisJCQljb250aW51ZTsKKwkJfQor CQlpZiAoIXN0cm5jbXAocHRyLCBjZmdkb25lLCA2KSkgeworCQkJbG9va3VwLT50YWJsZVsxXS5j aGlwX2h3bnVtID0gaTsKKwkJCWdwaW9zKys7CisJCX0KKwl9CisKKwkvKiBEb2VzIEdQSU8gY29u dHJvbGxlciBwcm92aWRlIGFsbCBuZWVkZWQgQUNCVVMgcGlucz8gKi8KKwlpZiAoZ3Bpb3MgPCAy KSB7CisJCWRldl9lcnIoZGV2LCAiTWlzc2luZyBjb250cm9sIEdQSU9zXG4iKTsKKwkJcmV0dXJu IC1FTk9ERVY7CisJfQorCisJZm9yIChpID0gMDsgaSA8IHBkLT5pb19kYXRhX2xlbjsgaSsrKSB7 CisJCWxvb2t1cC0+dGFibGVbaV0uY2hpcF9sYWJlbCA9IHByaXYtPmNidXNfZ3Bpby5sYWJlbDsK KwkJbG9va3VwLT50YWJsZVtpXS5pZHggPSAwOworCQlsb29rdXAtPnRhYmxlW2ldLmNvbl9pZCA9 IHBkLT5pb19kYXRhW2ldLmNvbl9pZDsKKwkJbG9va3VwLT50YWJsZVtpXS5mbGFncyA9IHBkLT5p b19kYXRhW2ldLmZsYWdzOworCX0KKworCXByaXYtPmxvb2t1cF9maWZvID0gbG9va3VwOworCWdw aW9kX2FkZF9sb29rdXBfdGFibGUocHJpdi0+bG9va3VwX2ZpZm8pOworCisJcGRldiA9IHBsYXRm b3JtX2RldmljZV9yZWdpc3Rlcl9kYXRhKGRldiwgRlBQX0lOVEZfREVWTkFNRSwKKwkJCQkJICAg ICBwcml2LT5pZCwgcGQsIHNpemVvZigqcGQpKTsKKwlpZiAoSVNfRVJSKHBkZXYpKSB7CisJCWdw aW9kX3JlbW92ZV9sb29rdXBfdGFibGUocHJpdi0+bG9va3VwX2ZpZm8pOworCQlyZXR1cm4gUFRS X0VSUihwZGV2KTsKKwl9CisKKwlwcml2LT5maWZvX3BkZXYgPSBwZGV2OworCisJZGV2X2RiZyhk ZXYsICIlczogZmlmbyBwZGV2ICVwXG4iLCBfX2Z1bmNfXywgcGRldik7CisJcmV0dXJuIDA7Cit9 CisKK3N0YXRpYyBpbnQgZnQyMzJoX2ludGZfZnBwX3JlbW92ZShzdHJ1Y3QgdXNiX2ludGVyZmFj ZSAqaW50ZikKK3sKKwlzdHJ1Y3QgZnQyMzJoX2ludGZfcHJpdiAqcHJpdiA9IHVzYl9nZXRfaW50 ZmRhdGEoaW50Zik7CisJc3RydWN0IGRldmljZSAqZGV2ID0gJmludGYtPmRldjsKKworCWRldl9k YmcoZGV2LCAiJXNcbiIsIF9fZnVuY19fKTsKKwlwbGF0Zm9ybV9kZXZpY2VfdW5yZWdpc3Rlcihw cml2LT5maWZvX3BkZXYpOworCWdwaW9kX3JlbW92ZV9sb29rdXBfdGFibGUocHJpdi0+bG9va3Vw X2ZpZm8pOworCXJldHVybiAwOworfQorCisvKgorICogRlBHQSBjb25maWcgaW50ZXJmYWNlOiBQ Uy1TUEkgdmlhIE1QU1NFCisgKi8KKyNkZWZpbmUgU1BJX0lOVEZfREVWTkFNRQkiZnRkaS1tcHNz ZS1zcGkiCisKK3N0YXRpYyBzdHJ1Y3QgZGV2X2lvX2Rlc2NfZGF0YSBmcGdhX2NmZ19zcGlfZGV2 X2lvW10gPSB7CisJeyAiY29uZmQiLCAxLCBHUElPX0FDVElWRV9ISUdIIH0sCisJeyAibnN0YXQi LCAyLCBHUElPX0FDVElWRV9MT1cgfSwKKwl7ICJuY29uZmlnIiwgMywgR1BJT19BQ1RJVkVfTE9X IH0sCit9OworCitzdGF0aWMgY29uc3Qgc3RydWN0IG1wc3NlX3NwaV9kZXZfZGF0YSBmcGdhX3Nw aV9kZXZfZGF0YVtdID0geworCXsKKwkubWFnaWMJCT0gRlRESV9NUFNTRV9JT19ERVNDX01BR0lD LAorCS5kZXNjCQk9IGZwZ2FfY2ZnX3NwaV9kZXZfaW8sCisJLmRlc2NfbGVuCT0gQVJSQVlfU0la RShmcGdhX2NmZ19zcGlfZGV2X2lvKSwKKwl9LAorfTsKKworc3RhdGljIHN0cnVjdCBzcGlfYm9h cmRfaW5mbyBmcGdhX2NmZ19zcGlfaW5mb1tdID0geworCXsKKwkubW9kYWxpYXMJPSAiZnBnYS1w YXNzaXZlLXNlcmlhbCIsCisJLm1vZGUJCT0gU1BJX01PREVfMCB8IFNQSV9MU0JfRklSU1QsCisJ Lm1heF9zcGVlZF9oegk9IDMwMDAwMDAwLAorCS5idXNfbnVtCT0gMCwKKwkuY2hpcF9zZWxlY3QJ PSAwLAorCS5wbGF0Zm9ybV9kYXRhCT0gZnBnYV9zcGlfZGV2X2RhdGEsCisJfSwKK307CisKK3N0 YXRpYyBjb25zdCBzdHJ1Y3QgbXBzc2Vfc3BpX3BsYXRmb3JtX2RhdGEgZnBnYV9jZmdfc3BpX3Bs YXRfZGF0YSA9IHsKKwkub3BzCQk9ICZmdDIzMmhfaW50Zl9vcHMsCisJLnNwaV9pbmZvCT0gZnBn YV9jZmdfc3BpX2luZm8sCisJLnNwaV9pbmZvX2xlbgk9IEFSUkFZX1NJWkUoZnBnYV9jZmdfc3Bp X2luZm8pLAorfTsKKworc3RhdGljIHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKm1wc3NlX2Rldl9y ZWdpc3RlcihzdHJ1Y3QgZnQyMzJoX2ludGZfcHJpdiAqcHJpdiwKKwkJCQljb25zdCBzdHJ1Y3Qg bXBzc2Vfc3BpX3BsYXRmb3JtX2RhdGEgKnBkKQoreworCXN0cnVjdCBkZXZpY2UgKnBhcmVudCA9 ICZwcml2LT5pbnRmLT5kZXY7CisJc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldjsKKwlzdHJ1 Y3QgZ3Bpb2RfbG9va3VwX3RhYmxlICpsb29rdXA7CisJc2l6ZV90IGxvb2t1cF9zaXplLCB0Ymxf c2l6ZTsKKwlpbnQgaSwgcmV0OworCisJcGRldiA9IHBsYXRmb3JtX2RldmljZV9hbGxvYyhTUElf SU5URl9ERVZOQU1FLCAwKTsKKwlpZiAoIXBkZXYpCisJCXJldHVybiBOVUxMOworCisJcGRldi0+ ZGV2LnBhcmVudCA9IHBhcmVudDsKKwlwZGV2LT5kZXYuZndub2RlID0gTlVMTDsKKwlwcml2LT5z cGlfcGRldiA9IHBkZXY7CisKKwl0Ymxfc2l6ZSA9IHBkLT5zcGlfaW5mb19sZW4gKyAxOworCWxv b2t1cF9zaXplID0gc2l6ZW9mKCpsb29rdXApICsgdGJsX3NpemUgKiBzaXplb2Yoc3RydWN0IGdw aW9kX2xvb2t1cCk7CisJbG9va3VwID0gZGV2bV9remFsbG9jKHBhcmVudCwgbG9va3VwX3NpemUs IEdGUF9LRVJORUwpOworCWlmICghbG9va3VwKSB7CisJCXJldCA9IC1FTk9NRU07CisJCWdvdG8g ZXJyOworCX0KKworCWZvciAoaSA9IDA7IGkgPCBwZC0+c3BpX2luZm9fbGVuOyBpKyspIHsKKwkJ ZGV2X2RiZyhwYXJlbnQsICJJTkZPOiAlcyBjcyAlZFxuIiwKKwkJCXBkLT5zcGlfaW5mb1tpXS5t b2RhbGlhcywgcGQtPnNwaV9pbmZvW2ldLmNoaXBfc2VsZWN0KTsKKwl9CisKKwlyZXQgPSBwbGF0 Zm9ybV9kZXZpY2VfYWRkX2RhdGEocGRldiwgcGQsIHNpemVvZigqcGQpKTsKKwlpZiAocmV0KQor CQlnb3RvIGVycjsKKworCXBkZXYtPmlkID0gcHJpdi0+aWQ7CisKKwlyZXQgPSBmdDIzMmhfaW50 Zl9hZGRfbXBzc2VfZ3Bpbyhwcml2KTsKKwlpZiAocmV0IDwgMCkKKwkJZ290byBlcnI7CisKKwls b29rdXAtPmRldl9pZCA9IGRldm1fa2FzcHJpbnRmKHBhcmVudCwgR0ZQX0tFUk5FTCwgIiVzLiVk IiwKKwkJCQkJcGRldi0+bmFtZSwgcGRldi0+aWQpOworCWlmICghbG9va3VwLT5kZXZfaWQpIHsK KwkJcmV0ID0gLUVOT01FTTsKKwkJZ290byBlcnI7CisJfQorCisJZm9yIChpID0gMDsgaSA8IHBk LT5zcGlfaW5mb19sZW47IGkrKykgeworCQlsb29rdXAtPnRhYmxlW2ldLmNoaXBfbGFiZWwgPSBw cml2LT5tcHNzZV9ncGlvLmxhYmVsOworCQlsb29rdXAtPnRhYmxlW2ldLmNoaXBfaHdudW0gPSBw ZC0+c3BpX2luZm9baV0uY2hpcF9zZWxlY3Q7CisJCWxvb2t1cC0+dGFibGVbaV0uaWR4ID0gaTsK KwkJbG9va3VwLT50YWJsZVtpXS5jb25faWQgPSBOVUxMOworCQlpZiAocGQtPnNwaV9pbmZvW2ld Lm1vZGUgJiBTUElfQ1NfSElHSCkKKwkJCWxvb2t1cC0+dGFibGVbaV0uZmxhZ3MgPSBHUElPX0FD VElWRV9ISUdIOworCQllbHNlCisJCQlsb29rdXAtPnRhYmxlW2ldLmZsYWdzID0gR1BJT19BQ1RJ VkVfTE9XOworCX0KKworCXByaXYtPmxvb2t1cF9jcyA9IGxvb2t1cDsKKwlncGlvZF9hZGRfbG9v a3VwX3RhYmxlKHByaXYtPmxvb2t1cF9jcyk7CisKKwlyZXQgPSBwbGF0Zm9ybV9kZXZpY2VfYWRk KHBkZXYpOworCWlmIChyZXQgPCAwKQorCQlnb3RvIGVycl9hZGQ7CisKKwlkZXZfZGJnKCZwZGV2 LT5kZXYsICIlcyBkb25lXG4iLCBfX2Z1bmNfXyk7CisJcmV0dXJuIHBkZXY7CisKK2Vycl9hZGQ6 CisJZ3Bpb2RfcmVtb3ZlX2xvb2t1cF90YWJsZShwcml2LT5sb29rdXBfY3MpOworZXJyOgorCXBs YXRmb3JtX2RldmljZV9wdXQocGRldik7CisJcmV0dXJuIEVSUl9QVFIocmV0KTsKK30KKworc3Rh dGljIGludCBmdDIzMmhfaW50Zl9zcGlfcHJvYmUoc3RydWN0IHVzYl9pbnRlcmZhY2UgKmludGYs CisJCQkJIGNvbnN0IHZvaWQgKnBsYXRfZGF0YSkKK3sKKwlzdHJ1Y3QgZnQyMzJoX2ludGZfcHJp diAqcHJpdiA9IHVzYl9nZXRfaW50ZmRhdGEoaW50Zik7CisJc3RydWN0IGRldmljZSAqZGV2ID0g JmludGYtPmRldjsKKwlzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2OworCisJcGRldiA9IG1w c3NlX2Rldl9yZWdpc3Rlcihwcml2LCBwbGF0X2RhdGEpOworCWlmIChJU19FUlIocGRldikpIHsK KwkJZGV2X2VycihkZXYsICIlczogQ2FuJ3QgY3JlYXRlIE1QU1NFIFNQSSBkZXZpY2UgJWxkXG4i LAorCQkJX19mdW5jX18sIFBUUl9FUlIocGRldikpOworCQlyZXR1cm4gUFRSX0VSUihwZGV2KTsK Kwl9CisKKwlwcml2LT5zcGlfcGRldiA9IHBkZXY7CisJcmV0dXJuIDA7Cit9CisKK3N0YXRpYyBp bnQgZnQyMzJoX2ludGZfc3BpX3JlbW92ZShzdHJ1Y3QgdXNiX2ludGVyZmFjZSAqaW50ZikKK3sK KwlzdHJ1Y3QgZnQyMzJoX2ludGZfcHJpdiAqcHJpdiA9IHVzYl9nZXRfaW50ZmRhdGEoaW50Zik7 CisJc3RydWN0IGRldmljZSAqZGV2ID0gJmludGYtPmRldjsKKworCWRldl9kYmcoZGV2LCAiJXM6 IHNwaSBwZGV2ICVwXG4iLCBfX2Z1bmNfXywgcHJpdi0+c3BpX3BkZXYpOworCWdwaW9kX3JlbW92 ZV9sb29rdXBfdGFibGUocHJpdi0+bG9va3VwX2NzKTsKKwlwbGF0Zm9ybV9kZXZpY2VfdW5yZWdp c3Rlcihwcml2LT5zcGlfcGRldik7CisJcmV0dXJuIDA7Cit9CisKK3N0YXRpYyBjb25zdCBzdHJ1 Y3QgZnQyMzJoX2ludGZfaW5mbyBmcGdhX2NmZ19zcGlfaW50Zl9pbmZvID0geworCS5wcm9iZSAg PSBmdDIzMmhfaW50Zl9zcGlfcHJvYmUsCisJLnJlbW92ZSAgPSBmdDIzMmhfaW50Zl9zcGlfcmVt b3ZlLAorCS5wbGF0X2RhdGEgID0gJmZwZ2FfY2ZnX3NwaV9wbGF0X2RhdGEsCit9OworCitzdGF0 aWMgY29uc3Qgc3RydWN0IGZ0MjMyaF9pbnRmX2luZm8gZnBnYV9jZmdfZmlmb19pbnRmX2luZm8g PSB7CisJLnByb2JlID0gZnQyMzJoX2ludGZfZnBwX3Byb2JlLAorCS5yZW1vdmUgPSBmdDIzMmhf aW50Zl9mcHBfcmVtb3ZlLAorCS5wbGF0X2RhdGEgPSAmZnBnYV9jZmdfZnBwX3BsYXRfZGF0YSwK K307CisKK3N0YXRpYyBpbnQgZnQyMzJoX2ludGZfcHJvYmUoc3RydWN0IHVzYl9pbnRlcmZhY2Ug KmludGYsCisJCQkgICAgIGNvbnN0IHN0cnVjdCB1c2JfZGV2aWNlX2lkICppZCkKK3sKKwlzdHJ1 Y3QgZnQyMzJoX2ludGZfcHJpdiAqcHJpdjsKKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSAmaW50Zi0+ ZGV2OworCXN0cnVjdCB1c2JfaG9zdF9pbnRlcmZhY2UgKmlmYWNlX2Rlc2M7CisJc3RydWN0IHVz Yl9lbmRwb2ludF9kZXNjcmlwdG9yICplbmRwb2ludDsKKwljb25zdCBzdHJ1Y3QgZnQyMzJoX2lu dGZfaW5mbyAqaW5mbzsKKwl1bnNpZ25lZCBpbnQgaTsKKwlpbnQgcmV0ID0gMDsKKworCXByaXYg PSBkZXZtX2t6YWxsb2MoZGV2LCBzaXplb2YoKnByaXYpLCBHRlBfS0VSTkVMKTsKKwlpZiAoIXBy aXYpCisJCXJldHVybiAtRU5PTUVNOworCisJaWZhY2VfZGVzYyA9IGludGYtPmN1cl9hbHRzZXR0 aW5nOworCisJZm9yIChpID0gMDsgaSA8IGlmYWNlX2Rlc2MtPmRlc2MuYk51bUVuZHBvaW50czsg aSsrKSB7CisJCWVuZHBvaW50ID0gJmlmYWNlX2Rlc2MtPmVuZHBvaW50W2ldLmRlc2M7CisKKwkJ aWYgKHVzYl9lbmRwb2ludF9pc19idWxrX291dChlbmRwb2ludCkpCisJCQlwcml2LT5idWxrX291 dCA9IGVuZHBvaW50LT5iRW5kcG9pbnRBZGRyZXNzOworCisJCWlmICh1c2JfZW5kcG9pbnRfaXNf YnVsa19pbihlbmRwb2ludCkpIHsKKwkJCXByaXYtPmJ1bGtfaW4gPSBlbmRwb2ludC0+YkVuZHBv aW50QWRkcmVzczsKKwkJCXByaXYtPmJ1bGtfaW5fc3ogPSB1c2JfZW5kcG9pbnRfbWF4cChlbmRw b2ludCk7CisJCX0KKwl9CisKKwlwcml2LT51c2JfZGV2X2lkID0gaWQ7CisJcHJpdi0+aW5kZXgg PSAxOworCXByaXYtPmludGYgPSBpbnRmOworCXByaXYtPmluZm8gPSAoc3RydWN0IGZ0MjMyaF9p bnRmX2luZm8gKilpZC0+ZHJpdmVyX2luZm87CisKKwlpbmZvID0gcHJpdi0+aW5mbzsKKwlpZiAo IWluZm8pIHsKKwkJZGV2X2VycihkZXYsICJNaXNzaW5nIGRldmljZSBzcGVjaWZpYyBkcml2ZXIg aW5mby4uLlxuIik7CisJCXJldHVybiAtRU5PREVWOworCX0KKworCW11dGV4X2luaXQoJnByaXYt PmlvX211dGV4KTsKKwltdXRleF9pbml0KCZwcml2LT5vcHNfbXV0ZXgpOworCXVzYl9zZXRfaW50 ZmRhdGEoaW50ZiwgcHJpdik7CisKKwlwcml2LT5idWxrX2luX2J1ZiA9IGRldm1fa21hbGxvYyhk ZXYsIHByaXYtPmJ1bGtfaW5fc3osIEdGUF9LRVJORUwpOworCWlmICghcHJpdi0+YnVsa19pbl9i dWYpCisJCXJldHVybiAtRU5PTUVNOworCisJcHJpdi0+dWRldiA9IHVzYl9nZXRfZGV2KGludGVy ZmFjZV90b191c2JkZXYoaW50ZikpOworCisJcHJpdi0+aWQgPSBpZGFfc2ltcGxlX2dldCgmZnRk aV9kZXZpZF9pZGEsIDAsIDAsIEdGUF9LRVJORUwpOworCWlmIChwcml2LT5pZCA8IDApCisJCXJl dHVybiBwcml2LT5pZDsKKworCWlmIChpbmZvLT5wcm9iZSkgeworCQlyZXQgPSBpbmZvLT5wcm9i ZShpbnRmLCBpbmZvLT5wbGF0X2RhdGEpOworCQlpZiAocmV0IDwgMCkKKwkJCWdvdG8gZXJyOwor CQlyZXR1cm4gMDsKKwl9CisKKwkvKiBmb3Igc2ltcGxlIEdQSU8tb25seSBkZXZpY2VzICovCisJ cmV0ID0gLUVOT0RFVjsKKwlpZiAoaW5mby0+dXNlX2NidXNfZ3Bpb19jdHJsKQorCQlyZXQgPSBm dDIzMmhfaW50Zl9hZGRfY2J1c19ncGlvKHByaXYpOworCWVsc2UgaWYgKGluZm8tPnVzZV9tcHNz ZV9ncGlvX2N0cmwpCisJCXJldCA9IGZ0MjMyaF9pbnRmX2FkZF9tcHNzZV9ncGlvKHByaXYpOwor CWlmICghcmV0KQorCQlyZXR1cm4gMDsKK2VycjoKKwlpZGFfc2ltcGxlX3JlbW92ZSgmZnRkaV9k ZXZpZF9pZGEsIHByaXYtPmlkKTsKKwlyZXR1cm4gcmV0OworfQorCitzdGF0aWMgdm9pZCBmdDIz MmhfaW50Zl9kaXNjb25uZWN0KHN0cnVjdCB1c2JfaW50ZXJmYWNlICppbnRmKQoreworCXN0cnVj dCBmdDIzMmhfaW50Zl9wcml2ICpwcml2ID0gdXNiX2dldF9pbnRmZGF0YShpbnRmKTsKKwljb25z dCBzdHJ1Y3QgZnQyMzJoX2ludGZfaW5mbyAqaW5mbzsKKworCWluZm8gPSAoc3RydWN0IGZ0MjMy aF9pbnRmX2luZm8gKilwcml2LT51c2JfZGV2X2lkLT5kcml2ZXJfaW5mbzsKKwlpZiAoaW5mbyAm JiBpbmZvLT5yZW1vdmUpCisJCWluZm8tPnJlbW92ZShpbnRmKTsKKworCWlmIChpbmZvLT51c2Vf bXBzc2VfZ3Bpb19jdHJsKQorCQlncGlvY2hpcF9yZW1vdmUoJnByaXYtPm1wc3NlX2dwaW8pOwor CisJaWYgKGluZm8tPnVzZV9jYnVzX2dwaW9fY3RybCkKKwkJZ3Bpb2NoaXBfcmVtb3ZlKCZwcml2 LT5jYnVzX2dwaW8pOworCisJbXV0ZXhfbG9jaygmcHJpdi0+aW9fbXV0ZXgpOworCXByaXYtPmlu dGYgPSBOVUxMOworCXVzYl9zZXRfaW50ZmRhdGEoaW50ZiwgTlVMTCk7CisJbXV0ZXhfdW5sb2Nr KCZwcml2LT5pb19tdXRleCk7CisKKwl1c2JfcHV0X2Rldihwcml2LT51ZGV2KTsKKwlpZGFfc2lt cGxlX3JlbW92ZSgmZnRkaV9kZXZpZF9pZGEsIHByaXYtPmlkKTsKK30KKworI2RlZmluZSBGVERJ X1ZJRAkJCTB4MDQwMworI2RlZmluZSBBUlJJX0ZQUF9JTlRGX1BST0RVQ1RfSUQJMHg3MTQ4Cisj ZGVmaW5lIEFSUklfU1BJX0lOVEZfUFJPRFVDVF9JRAkweDcxNDkKKworc3RhdGljIHN0cnVjdCB1 c2JfZGV2aWNlX2lkIGZ0MjMyaF9pbnRmX3RhYmxlW10gPSB7CisJeyBVU0JfREVWSUNFKEZURElf VklELCBBUlJJX0ZQUF9JTlRGX1BST0RVQ1RfSUQpLAorCQkuZHJpdmVyX2luZm8gPSAoa2VybmVs X3Vsb25nX3QpJmZwZ2FfY2ZnX2ZpZm9faW50Zl9pbmZvIH0sCisJeyBVU0JfREVWSUNFKEZURElf VklELCBBUlJJX1NQSV9JTlRGX1BST0RVQ1RfSUQpLAorCQkuZHJpdmVyX2luZm8gPSAoa2VybmVs X3Vsb25nX3QpJmZwZ2FfY2ZnX3NwaV9pbnRmX2luZm8gfSwKKwl7fQorfTsKK01PRFVMRV9ERVZJ Q0VfVEFCTEUodXNiLCBmdDIzMmhfaW50Zl90YWJsZSk7CisKK3N0YXRpYyBzdHJ1Y3QgdXNiX2Ry aXZlciBmdDIzMmhfaW50Zl9kcml2ZXIgPSB7CisJLm5hbWUJCT0gS0JVSUxEX01PRE5BTUUsCisJ LmlkX3RhYmxlCT0gZnQyMzJoX2ludGZfdGFibGUsCisJLnByb2JlCQk9IGZ0MjMyaF9pbnRmX3By b2JlLAorCS5kaXNjb25uZWN0CT0gZnQyMzJoX2ludGZfZGlzY29ubmVjdCwKK307CisKK21vZHVs ZV91c2JfZHJpdmVyKGZ0MjMyaF9pbnRmX2RyaXZlcik7CisKK01PRFVMRV9BTElBUygiZnQyMzJo LWludGYiKTsKK01PRFVMRV9BVVRIT1IoIkFuYXRvbGlqIEd1c3RzY2hpbiA8YWd1c3RAZGVueC5k ZT4iKTsKK01PRFVMRV9ERVNDUklQVElPTigiRlQyMzJIIHRvIEZQR0EgaW50ZXJmYWNlIGRyaXZl ciIpOworTU9EVUxFX0xJQ0VOU0UoIkdQTCB2MiIpOwpkaWZmIC0tZ2l0IGEvaW5jbHVkZS9saW51 eC91c2IvZnQyMzJoLWludGYuaCBiL2luY2x1ZGUvbGludXgvdXNiL2Z0MjMyaC1pbnRmLmgKbmV3 IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMDAwMDAwLi43ZTY4NTcyNjNkYjIKLS0tIC9k ZXYvbnVsbAorKysgYi9pbmNsdWRlL2xpbnV4L3VzYi9mdDIzMmgtaW50Zi5oCkBAIC0wLDAgKzEs MjA2IEBACisvKiBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogR1BMLTIuMCAqLworLyoKKyAqIENv bW1vbiBkZWZpbml0aW9ucyBmb3IgRlRESSBGVDIzMkggaW50ZXJmYWNlIGRldmljZQorICoKKyAq IENvcHlyaWdodCAoQykgMjAxNyAtIDIwMTggREVOWCBTb2Z0d2FyZSBFbmdpbmVlcmluZworICog QW5hdG9saWogR3VzdHNjaGluIDxhZ3VzdEBkZW54LmRlPgorICovCisKKyNpZm5kZWYgX19MSU5V WF9GVDIzMkhfSU5URl9ICisjZGVmaW5lIF9fTElOVVhfRlQyMzJIX0lOVEZfSAorCisvKiBVc2Vk IEZUREkgVVNCIFJlcXVlc3RzICovCisjZGVmaW5lIEZURElfU0lPX1JFU0VUX1JFUVVFU1QJCTB4 MDAKKyNkZWZpbmUgRlRESV9TSU9fU0VUX0JBVURSQVRFX1JFUVVFU1QJMHgwMworI2RlZmluZSBG VERJX1NJT19TRVRfQklUTU9ERV9SRVFVRVNUCTB4MEIKKyNkZWZpbmUgRlRESV9TSU9fUkVBRF9Q SU5TX1JFUVVFU1QJMHgwQworI2RlZmluZSBGVERJX1NJT19SRUFEX0VFUFJPTV9SRVFVRVNUCTB4 OTAKKworLyogTVBTU0UgQ29tbWFuZHMgKi8KKyNkZWZpbmUgVFhfQllURVNfUkVfTVNCCQkweDEw IC8qIHR4IG9uICt2ZSBjbGsgKHJpc2luZyBlZGdlKSAqLworI2RlZmluZSBUWF9CWVRFU19GRV9N U0IJCTB4MTEgLyogdHggb24gLXZlIGNsayAoZmFsbGluZyBlZGdlKSAqLworI2RlZmluZSBSWF9C WVRFU19SRV9NU0IJCTB4MjAKKyNkZWZpbmUgUlhfQllURVNfRkVfTVNCCQkweDI0CisjZGVmaW5l IFRYRl9SWFJfQllURVNfTVNCCTB4MzEgLyogdHggb24gLXZlIGNsaywgcnggb24gK3ZlICovCisj ZGVmaW5lIFRYUl9SWEZfQllURVNfTVNCCTB4MzQgLyogdHggb24gK3ZlIGNsaywgcnggb24gLXZl ICovCisKKyNkZWZpbmUgVFhfQllURVNfUkVfTFNCCQkweDE4IC8qIHR4IG9uICt2ZSBjbGsgKi8K KyNkZWZpbmUgVFhfQllURVNfRkVfTFNCCQkweDE5IC8qIHR4IG9uIC12ZSBjbGsgKi8KKyNkZWZp bmUgUlhfQllURVNfUkVfTFNCCQkweDI4CisjZGVmaW5lIFJYX0JZVEVTX0ZFX0xTQgkJMHgyQwor I2RlZmluZSBUWEZfUlhSX0JZVEVTX0xTQgkweDM5IC8qIHR4IG9uIC12ZSBjbGssIHJ4IG9uICt2 ZSAqLworI2RlZmluZSBUWFJfUlhGX0JZVEVTX0xTQgkweDNDIC8qIHR4IG9uICt2ZSBjbGssIHJ4 IG9uIC12ZSAqLworCisjZGVmaW5lIExPT1BCQUNLX09OCQkweDg0CisjZGVmaW5lIExPT1BCQUNL X09GRgkJMHg4NQorI2RlZmluZSBUQ0tfRElWSVNPUgkJMHg4NgorI2RlZmluZSBESVNfRElWXzUJ CTB4OEEKKyNkZWZpbmUgRU5fRElWXzUJCTB4OEIKKyNkZWZpbmUgRU5fM19QSEFTRQkJMHg4Qwor I2RlZmluZSBESVNfM19QSEFTRQkJMHg4RAorI2RlZmluZSBESVNfQURBUFRJVkUJCTB4OTcKKwor LyogRm9yIEVFUFJPTSBJL08gbW9kZSAqLworI2RlZmluZSBGVERJX01BWF9FRVBST01fU0laRQky NTYKKyNkZWZpbmUgRlRESV8yMzJIX0NCVVNfSU9NT0RFCTB4MDgKKworI2RlZmluZSBGVERJX1VT Ql9SRUFEX1RJTUVPVVQJNTAwMAorI2RlZmluZSBGVERJX1VTQl9XUklURV9USU1FT1VUCTUwMDAK KworLyogVG90YWwgbnVtYmVyIG9mIE1QU1NFIEdQSU9zOiA0eCBHUElPTCwgOHggR1BJT0gsIDF4 IENTIG9uIEFEQlVTMyAqLworI2RlZmluZSBGVERJX01QU1NFX0dQSU9TCTEzCisKKy8qIE1QU1NF IGJpdGJhbmcgbW9kZXMgKGNvcGllZCBmcm9tIGxpYmZ0ZGkpICovCitlbnVtIGZ0ZGlfbXBzc2Vf bW9kZSB7CisJQklUTU9ERV9SRVNFVAk9IDB4MDAsCS8qIHN3aXRjaCBvZmYgYml0YmFuZyBtb2Rl ICovCisJQklUTU9ERV9CSVRCQU5HCT0gMHgwMSwJLyogYXN5bmNocm9ub3VzIGJpdGJhbmcgbW9k ZSAqLworCUJJVE1PREVfTVBTU0UJPSAweDAyLAkvKiBNUFNTRSBtb2RlLCBvbiAyMjMyeCBjaGlw cyAqLworCUJJVE1PREVfU1lOQ0JCCT0gMHgwNCwJLyogc3luY2hyb25vdXMgYml0YmFuZyBtb2Rl ICAqLworCUJJVE1PREVfTUNVCT0gMHgwOCwJLyogTUNVIEhvc3QgQnVzIEVtdWxhdGlvbiBtb2Rl ICovCisJCQkJLyogQ1BVLXN0eWxlIGZpZm8gbW9kZSBnZXRzIHNldCB2aWEgRUVQUk9NICovCisJ QklUTU9ERV9PUFRPCT0gMHgxMCwJLyogRmFzdCBPcHRvLUlzb2xhdGVkIFNlcmlhbCBJbnRlcmZh Y2UgTW9kZSAqLworCUJJVE1PREVfQ0JVUwk9IDB4MjAsCS8qIEJpdGJhbmcgb24gQ0JVUyBwaW5z LCBFRVBST00gY29uZmlnIG5lZWRlZCAqLworCUJJVE1PREVfU1lOQ0ZGCT0gMHg0MCwJLyogU2lu Z2xlIENoYW5uZWwgU3luY2hyb25vdXMgRklGTyBtb2RlICovCisJQklUTU9ERV9GVDEyODQJPSAw eDgwLAkvKiBGVDEyODQgbW9kZSwgYXZhaWxhYmxlIG9uIDIzMkggY2hpcHMgKi8KK307CisKK3N0 cnVjdCBjdHJsX2Rlc2MgeworCXVuc2lnbmVkIGludCBkaXJfb3V0OworCXU4IHJlcXVlc3Q7CisJ dTggcmVxdWVzdHR5cGU7CisJdTE2IHZhbHVlOworCXUxNiBpbmRleDsKKwl1MTYgc2l6ZTsKKwl2 b2lkICpkYXRhOworCWludCB0aW1lb3V0OworfTsKKworc3RydWN0IGJ1bGtfZGVzYyB7CisJdW5z aWduZWQgaW50IGRpcl9vdXQ7CisJdm9pZCAqZGF0YTsKKwlpbnQgbGVuOworCWludCBhY3RfbGVu OworCWludCB0aW1lb3V0OworfTsKKworLyoKKyAqIHN0cnVjdCBmdDIzMmhfaW50Zl9vcHMgLSBG VDIzMkggaW50ZXJmYWNlIG9wZXJhdGlvbnMgZm9yIHVwcGVyIGRyaXZlcnMKKyAqCisgKiBAYnVs a194ZmVyOiBGVERJIFVTQiBidWxrIHRyYW5zZmVyCisgKiBAY3RybF94ZmVyOiBGVERJIFVTQiBj b250cm9sIHRyYW5zZmVyCisgKiBAcmVhZF9kYXRhOiByZWFkICdsZW4nIGJ5dGVzIGZyb20gRlRE SSBkZXZpY2UgdG8gdGhlIGdpdmVuIGJ1ZmZlcgorICogQHdyaXRlX2RhdGE6IHdyaXRlICdsZW4n IGJ5dGVzIGZyb20gdGhlIGdpdmVuIGJ1ZmZlciB0byB0aGUgRlRESSBkZXZpY2UKKyAqIEBsb2Nr OiBsb2NrIHRoZSBpbnRlcmZhY2UgZm9yIGFuIG9wZXJhdGlvbiBzZXF1ZW5jZS4gVXNlZCB3aGVu IG11bHRpcGxlCisgKgkgIGNvbW1hbmQgYW5kL29yIGRhdGEgb3BlcmF0aW9ucyBtdXN0IGJlIGV4 ZWN1dGVkIGluIGEgc3BlY2lmaWMgb3JkZXIKKyAqCSAgKHdoZW4gb3RoZXIgaW50ZXJtZWRpYXRl IGNvbW1hbmQvZGF0YSB0cmFuc2ZlcnMgbWF5IG5vdCBpbnRlcmZlcmUpCisgKiBAdW5sb2NrOiB1 bmxvY2sgdGhlIHByZXZpb3VzbHkgbG9ja2VkIGludGVyZmFjZQorICogQHNldF9iaXRtb2RlOiBj b25maWd1cmUgRlRESSBiaXQgbW9kZQorICogQHNldF9iYXVkcmF0ZTogY29uZmlndXJlIEZUREkg YmF1ZHJhdGUKKyAqIEBkaXNhYmxlX2JpdGJhbmc6IHR1cm4gb2ZmIGJpdGJhbmcgbW9kZQorICog QGluaXRfcGluczogaW5pdGlhbGl6ZSBHUElPTC9HUElPSCBwb3J0IHBpbnMgaW4gTVBTU0UgbW9k ZQorICogQGNmZ19idXNfcGluczogY29uZmlndXJlIE1QU1NFIFNQSSBidXMgcGlucworICoKKyAq IENvbW1vbiBGVDIzMkggaW50ZXJmYWNlIFVTQiB4ZmVyIGFuZCBkZXZpY2UgY29uZmlndXJhdGlv biBvcGVyYXRpb25zIHVzZWQKKyAqIGluIEZJRk8tRlBQLCBNUFNTRS1TUEkgb3IgTVBTU0UtSTJD IGRyaXZlcnMuIE1hbnkgb2YgdGhlbSBhcmUgbGlrZSBGVERJCisgKiBwcm90b2NvbCBmdW5jdGlv bnMsIHdoaWNoIEkgbWFpbmx5IGJvcnJvd2VkIGZyb20gbGliZnRkaQorICovCitzdHJ1Y3QgZnQy MzJoX2ludGZfb3BzIHsKKwlpbnQgKCpidWxrX3hmZXIpKHN0cnVjdCB1c2JfaW50ZXJmYWNlICpp bnRmLCBzdHJ1Y3QgYnVsa19kZXNjICpkZXNjKTsKKwlpbnQgKCpjdHJsX3hmZXIpKHN0cnVjdCB1 c2JfaW50ZXJmYWNlICppbnRmLCBzdHJ1Y3QgY3RybF9kZXNjICpkZXNjKTsKKwlpbnQgKCpyZWFk X2RhdGEpKHN0cnVjdCB1c2JfaW50ZXJmYWNlICppbnRmLCB2b2lkICpidWYsIHNpemVfdCBsZW4p OworCWludCAoKndyaXRlX2RhdGEpKHN0cnVjdCB1c2JfaW50ZXJmYWNlICppbnRmLCBjb25zdCBj aGFyICpidWYsCisJCQkgIHNpemVfdCBsZW4pOworCXZvaWQgKCpsb2NrKShzdHJ1Y3QgdXNiX2lu dGVyZmFjZSAqaW50Zik7CisJdm9pZCAoKnVubG9jaykoc3RydWN0IHVzYl9pbnRlcmZhY2UgKmlu dGYpOworCWludCAoKnNldF9iaXRtb2RlKShzdHJ1Y3QgdXNiX2ludGVyZmFjZSAqaW50ZiwgdW5z aWduZWQgY2hhciBiaXRtYXNrLAorCQkJICAgdW5zaWduZWQgY2hhciBtb2RlKTsKKwlpbnQgKCpz ZXRfYmF1ZHJhdGUpKHN0cnVjdCB1c2JfaW50ZXJmYWNlICppbnRmLCBpbnQgYmF1ZHJhdGUpOwor CWludCAoKmRpc2FibGVfYml0YmFuZykoc3RydWN0IHVzYl9pbnRlcmZhY2UgKmludGYpOworCWlu dCAoKmluaXRfcGlucykoc3RydWN0IHVzYl9pbnRlcmZhY2UgKmludGYsIGJvb2wgbG93LCB1OCBi aXRzLCB1OCBkaXIpOworCWludCAoKmNmZ19idXNfcGlucykoc3RydWN0IHVzYl9pbnRlcmZhY2Ug KmludGYsIHU4IGRpcl9iaXRzLAorCQkJICAgIHU4IHZhbHVlX2JpdHMpOworfTsKKworLyoKKyAq IHN0cnVjdCBkZXZfaW9fZGVzY19kYXRhIC0gRGVzY3JpcHRvciBvZiBGVDIzMkggcGluIHVzZWQg YnkgYXR0YWNoZWQgZGV2aWNlCisgKiBAY29uX2lkOiBOYW1lIG9mIHRoZSBHUElPIHBpbgorICog QGlkeDogSW5kZXggb2YgdGhlIHBpbgorICogQGZsYWdzOiBHUElPRCBmbGFncyBvZiB0aGUgcGlu CisgKgorICogRGVzY3JpcHRpb24gb2YgYSBHUElPIHVzZWQgYnkgZGV2aWNlIGNvbm5lY3RlZCB0 byBGVDIzMkgKKyAqLworc3RydWN0IGRldl9pb19kZXNjX2RhdGEgeworCWNvbnN0IGNoYXIgKmNv bl9pZDsKKwl1bnNpZ25lZCBpbnQgaWR4OworCXVuc2lnbmVkIGludCBmbGFnczsKK307CisKKy8q CisgKiBzdHJ1Y3QgZmlmb19mcHBfbWdyX3BsYXRmb3JtX2RhdGEgLSBGSUZPL0ZQUCBkZXZpY2Ug cGxhdGZvcm0gZGF0YQorICogQG9wczogVVNCIGludGVyZmFjZSBvcGVyYXRpb25zIHVzZWQgaW4g RlBQIG1hbmFnZXIgZHJpdmVyCisgKiBAaW9fZGF0YTogQXJyYXkgd2l0aCBkZXNjcmlwdG9ycyBv ZiB1c2VkIEkvTyBwaW5zCisgKiBAaW9fZGF0YV9sZW46IExlbmd0aCBvZiBpb19kYXRhIGFycmF5 CisgKiBAbmNvbmZpZ19udW06IEFDQlVTIHBpbiBudW1iZXIgb2YgdGhlIE5DT05GSUcgcGluCisg KiBAY29uZl9kb25lX251bTogQUNCVVMgcGluIG51bWJlciBvZiB0aGUgQ09ORl9ET05FIHBpbgor ICoKKyAqIEZJRk8vRlBQIGZwZ2EgbWFuYWdlciBzcGVjaWZpYyBwbGF0Zm9ybSBkYXRhCisgKi8K K3N0cnVjdCBmaWZvX2ZwcF9tZ3JfcGxhdGZvcm1fZGF0YSB7CisJY29uc3Qgc3RydWN0IGZ0MjMy aF9pbnRmX29wcyAqb3BzOworCXN0cnVjdCBkZXZfaW9fZGVzY19kYXRhICppb19kYXRhOworCXNp emVfdCBpb19kYXRhX2xlbjsKKwlpbnQgbmNvbmZpZ19udW07CisJaW50IGNvbmZfZG9uZV9udW07 Cit9OworCisjZGVmaW5lIEZURElfTVBTU0VfSU9fREVTQ19NQUdJQwkweDUzNDU0OTRGCisvKgor ICogc3RydWN0IG1wc3NlX3NwaV9kZXZfZGF0YSAtIE1QU1NFIFNQSSBkZXZpY2UgcGxhdGZvcm0g ZGF0YQorICogQG1hZ2ljOiBTcGVjaWFsICMgaW5kaWNhdGluZyB0aGF0IHRoaXMgaXMgYSBJL08g ZGVzY3JpcHRvciBzdHJ1Y3QKKyAqIEBpb19kYXRhOiBBcnJheSB3aXRoIGRlc2NyaXB0b3JzIG9m IHVzZWQgSS9PIHBpbnMKKyAqIEBpb19kYXRhX2xlbjogTGVuZ3RoIG9mIGlvX2RhdGEgYXJyYXkK KyAqCisgKiBNUFNTRSBTUEkgc2xhdmUgc3BlY2lmaWMgcGxhdGZvcm0gZGF0YSBkZXNjcmliaW5n IGFkZGl0aW9uYWwKKyAqIEkvTyBwaW5zIChpZiBhbnkpIG9mIGF0dGFjaGVkIFNQSSBzbGF2ZS4g SXQgaXMgc3VwcG9zZWQgdG8gYmUKKyAqIHBhc3NlZCB2aWEgLnBsYXRmb3JtX2RhdGEgb2Ygc3Bp X2JvYXJkX2luZm8gc3RydWN0LgorICogVG8gZGlmZmVyZW50aWF0ZSBiZXR3ZWVuIE1QU1NFIEkv TyBkZXNjcmlwdG9yIGRhdGEgYW5kIG90aGVyCisgKiBkcml2ZXItc3BlY2lmaWMgcGxhdGZvcm0g ZGF0YSB3ZSB1c2UgRlRESV9NUFNTRV9JT19ERVNDX01BR0lDCisgKiBpbiB0aGUgaGVhZGVyIG9m IHRoaXMgc3RydWN0CisgKi8KK3N0cnVjdCBtcHNzZV9zcGlfZGV2X2RhdGEgeworCXUzMiBtYWdp YzsKKwlzdHJ1Y3QgZGV2X2lvX2Rlc2NfZGF0YSAqZGVzYzsKKwlzaXplX3QgZGVzY19sZW47Cit9 OworCisvKgorICogc3RydWN0IG1wc3NlX3NwaV9wbGF0Zm9ybV9kYXRhIC0gTVBTU0UgU1BJIGJ1 cyBwbGF0Zm9ybSBkYXRhCisgKiBAb3BzOiBVU0IgaW50ZXJmYWNlIG9wZXJhdGlvbnMgdXNlZCBp biBNUFNTRSBTUEkgY29udHJvbGxlciBkcml2ZXIKKyAqIEBzcGlfaW5mbzogQXJyYXkgd2l0aCBz cGlfYm9hcmRfaW5mbyBzdHJ1Y3R1cmVzIG9mIGF0dGFjaGVkIFNQSSBzbGF2ZXMKKyAqIEBzcGlf aW5mb19sZW46IExlbmd0aCBvZiBzcGlfaW5mbyBhcnJheQorICoKKyAqIE1QU1NFIFNQSSBidXMg c3BlY2lmaWMgcGxhdGZvcm0gZGF0YSBkZXNjcmliaW5nIGF0dGFjaGVkIFNQSSBzbGF2ZXMKKyAq IGFuZCBvcHRpb25hbGx5IHRoZWlyIGFkZGl0aW9uYWwgSS9PIHBpbnMgKC5wbGF0Zm9ybV9kYXRh IG9mIHNwaV9pbmZvKQorICovCitzdHJ1Y3QgbXBzc2Vfc3BpX3BsYXRmb3JtX2RhdGEgeworCWNv bnN0IHN0cnVjdCBmdDIzMmhfaW50Zl9vcHMgKm9wczsKKwlzdHJ1Y3Qgc3BpX2JvYXJkX2luZm8g KnNwaV9pbmZvOworCXNpemVfdCBzcGlfaW5mb19sZW47Cit9OworCisvKgorICogVmFsdWUgSElH SC4gcmF0ZSBpcyAxMjAwMDAwMCAvICgoMSArIHZhbHVlKSAqIDIpCisgKi8KK3N0YXRpYyBpbmxp bmUgaW50IGRpdl92YWx1ZShpbnQgcmF0ZSkKK3sKKwlpbnQgcjsKKworCWlmIChyYXRlID49IDYw MDAwMDApCisJCXJldHVybiAwOworCXIgPSA2MDAwMDAwIC8gcmF0ZSAtIDE7CisJaWYgKHIgPCAw eGZmZmYpCisJCXJldHVybiByOworCXJldHVybiAweGZmZmY7Cit9CisKKyNlbmRpZiAvKiBfX0xJ TlVYX0ZUMjMySF9JTlRGX0ggKi8K