From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Return-Path: From: Anatolij Gustschin Subject: [PATCH v2 1/3] usb: misc: add driver for FT232H based FPGA configuration devices Date: Tue, 20 Nov 2018 01:28:19 +0100 Message-Id: <20181120002821.12794-2-agust@denx.de> In-Reply-To: <20181120002821.12794-1-agust@denx.de> References: <20181120002821.12794-1-agust@denx.de> To: linux-usb@vger.kernel.org, linux-spi@vger.kernel.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: gregkh@linuxfoundation.org, broonie@kernel.org, atull@kernel.org, mdf@kernel.org List-ID: Add 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 | 9 + drivers/usb/misc/Makefile | 1 + drivers/usb/misc/ft232h-intf.c | 1464 +++++++++++++++++++++++++++++++ include/linux/usb/ft232h-intf.h | 187 ++++ 5 files changed, 1669 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 b755a89fa325..aaafa11f860f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15388,6 +15388,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 68d2f2cd17dd..41304ac7f0e3 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -275,3 +275,12 @@ 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" + 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..3618d8c7bfdd 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ obj-$(CONFIG_USB_LINK_LAYER_TEST) += lvstest.o +obj-$(CONFIG_USB_FT232H_INTF) += ft232h-intf.o diff --git a/drivers/usb/misc/ft232h-intf.c b/drivers/usb/misc/ft232h-intf.c new file mode 100644 index 000000000000..4f58ef552319 --- /dev/null +++ b/drivers/usb/misc/ft232h-intf.c @@ -0,0 +1,1464 @@ +// 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 int ftdi_to_clkbits(int baudrate, unsigned int clk, int clk_div, + unsigned long *encoded_divisor) +{ + static const char frac_code[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; + int best_baud = 0; + int div, 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 + */ + div = clk * 16 / clk_div / baudrate; + if (div & 1) /* Decide if to round up or down */ + best_div = div / 2 + 1; + else + best_div = div / 2; + if (best_div > 0x20000) + best_div = 0x1ffff; + best_baud = clk * 16 / clk_div / best_div; + if (best_baud & 1) /* Decide if to round up or down */ + best_baud = best_baud / 2 + 1; + else + best_baud = best_baud / 2; + *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 long encoded_divisor = 0; + int best_baud = 0; + + 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 <= 0) { + pr_err("Invalid baudrate: %d\n", best_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 %d, 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 ? true : false; + + 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 = 13; + 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 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, + }, +}; + +static struct dev_io_desc_data fpga_cfg_spi_dev_io[3] = { + { "confd", 1, GPIO_ACTIVE_HIGH }, + { "nstat", 2, GPIO_ACTIVE_LOW }, + { "nconfig", 3, GPIO_ACTIVE_LOW }, +}; + +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), + .io_data = fpga_cfg_spi_dev_io, + .io_data_len = ARRAY_SIZE(fpga_cfg_spi_dev_io), +}; + +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) + devm_gpiochip_remove(&intf->dev, &priv->mpsse_gpio); + + if (info->use_cbus_gpio_ctrl) + devm_gpiochip_remove(&intf->dev, &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..f83fae050968 --- /dev/null +++ b/include/linux/usb/ft232h-intf.h @@ -0,0 +1,187 @@ +/* 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 + +/* 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; +}; + +/* + * 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 + * @io_data: Array with descriptors of used I/O pins + * @io_data_len: Length of io_data array + * + * MPSSE SPI specific platform data describing attached SPI slaves and + * their additional I/O pins + */ +struct mpsse_spi_platform_data { + const struct ft232h_intf_ops *ops; + struct spi_board_info *spi_info; + size_t spi_info_len; + struct dev_io_desc_data *io_data; + size_t io_data_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: [v2,1/3] usb: misc: add driver for FT232H based FPGA configuration devices From: Anatolij Gustschin Message-Id: <20181120002821.12794-2-agust@denx.de> Date: Tue, 20 Nov 2018 01:28:19 +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 ICAgOSArCiBkcml2ZXJzL3VzYi9taXNjL01ha2VmaWxlICAgICAgIHwgICAgMSArCiBkcml2ZXJz L3VzYi9taXNjL2Z0MjMyaC1pbnRmLmMgIHwgMTQ2NCArKysrKysrKysrKysrKysrKysrKysrKysr KysrKysrCiBpbmNsdWRlL2xpbnV4L3VzYi9mdDIzMmgtaW50Zi5oIHwgIDE4NyArKysrCiA1IGZp bGVzIGNoYW5nZWQsIDE2NjkgaW5zZXJ0aW9ucygrKQogY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZl cnMvdXNiL21pc2MvZnQyMzJoLWludGYuYwogY3JlYXRlIG1vZGUgMTAwNjQ0IGluY2x1ZGUvbGlu dXgvdXNiL2Z0MjMyaC1pbnRmLmgKCmRpZmYgLS1naXQgYS9NQUlOVEFJTkVSUyBiL01BSU5UQUlO RVJTCmluZGV4IGI3NTVhODlmYTMyNS4uYWFhZmExMWY4NjBmIDEwMDY0NAotLS0gYS9NQUlOVEFJ TkVSUworKysgYi9NQUlOVEFJTkVSUwpAQCAtMTUzODgsNiArMTUzODgsMTQgQEAgUzoJTWFpbnRh aW5lZAogRjoJRG9jdW1lbnRhdGlvbi91c2IvYWNtLnR4dAogRjoJZHJpdmVycy91c2IvY2xhc3Mv Y2RjLWFjbS4qCiAKK1VTQiBBUlJJIEZQR0EgQ09ORklHVVJBVElPTiBBREFQVEVSIERSSVZFUgor TToJQW5hdG9saWogR3VzdHNjaGluIDxhZ3VzdEBkZW54LmRlPgorTDoJbGludXgtdXNiQHZnZXIu a2VybmVsLm9yZworUzoJTWFpbnRhaW5lZAorRjoJZHJpdmVycy91c2IvbWlzYy9mdDIzMmgtaW50 Zi5jCitGOglkcml2ZXJzL3NwaS9zcGktZnRkaS1tcHNzZS5jCitGOglpbmNsdWRlL2xpbnV4L3Vz Yi9mdDIzMmgtaW50Zi5oCisKIFVTQiBBUjU1MjMgV0lSRUxFU1MgRFJJVkVSCiBNOglQb250dXMg RnVjaHMgPHBvbnR1cy5mdWNoc0BnbWFpbC5jb20+CiBMOglsaW51eC13aXJlbGVzc0B2Z2VyLmtl cm5lbC5vcmcKZGlmZiAtLWdpdCBhL2RyaXZlcnMvdXNiL21pc2MvS2NvbmZpZyBiL2RyaXZlcnMv dXNiL21pc2MvS2NvbmZpZwppbmRleCA2OGQyZjJjZDE3ZGQuLjQxMzA0YWM3ZjBlMyAxMDA2NDQK LS0tIGEvZHJpdmVycy91c2IvbWlzYy9LY29uZmlnCisrKyBiL2RyaXZlcnMvdXNiL21pc2MvS2Nv bmZpZwpAQCAtMjc1LDMgKzI3NSwxMiBAQCBjb25maWcgVVNCX0NIQU9TS0VZCiAKIAkgIFRvIGNv bXBpbGUgdGhpcyBkcml2ZXIgYXMgYSBtb2R1bGUsIGNob29zZSBNIGhlcmU6IHRoZQogCSAgbW9k dWxlIHdpbGwgYmUgY2FsbGVkIGNoYW9za2V5LgorCitjb25maWcgVVNCX0ZUMjMySF9JTlRGCisJ dHJpc3RhdGUgIkZUREkgRlQyMzJIIEZQR0EgY29uZmlndXJhdGlvbiBpbnRlcmZhY2UgZHJpdmVy IgorCWhlbHAKKwkgIEVuYWJsZSBkcml2ZXIgc3VwcG9ydCBmb3IgdGhlIEZUMjMySCBiYXNlZCBV U0ItR1BJTy9TUEkvRklGTworCSAgaW50ZXJmYWNlIGFkYXB0ZXIgZm9yIEZQR0EgY29uZmlndXJh dGlvbi4gQWRkaXRpb25hbCBkcml2ZXJzCisJICBzdWNoIGFzIHNwaS1mdGRpLW1wc3NlLCBhbHRl cmEtcHMtc3BpLCBmdGRpLWZpZm8tZnBwIGFuZAorCSAgZnBnYS1tZ3IgbXVzdCBiZSBlbmFibGVk IGluIG9yZGVyIHRvIHVzZSB0aGUgZnVuY3Rpb25hbGl0eSBvZgorCSAgdGhlIGRldmljZS4KZGlm ZiAtLWdpdCBhL2RyaXZlcnMvdXNiL21pc2MvTWFrZWZpbGUgYi9kcml2ZXJzL3VzYi9taXNjL01h a2VmaWxlCmluZGV4IDEwOWY1NGY1YjlhYS4uMzYxOGQ4YzdiZmRkIDEwMDY0NAotLS0gYS9kcml2 ZXJzL3VzYi9taXNjL01ha2VmaWxlCisrKyBiL2RyaXZlcnMvdXNiL21pc2MvTWFrZWZpbGUKQEAg LTMxLDMgKzMxLDQgQEAgb2JqLSQoQ09ORklHX1VTQl9DSEFPU0tFWSkJCSs9IGNoYW9za2V5Lm8K IAogb2JqLSQoQ09ORklHX1VTQl9TSVNVU0JWR0EpCQkrPSBzaXN1c2J2Z2EvCiBvYmotJChDT05G SUdfVVNCX0xJTktfTEFZRVJfVEVTVCkJKz0gbHZzdGVzdC5vCitvYmotJChDT05GSUdfVVNCX0ZU MjMySF9JTlRGKQkJKz0gZnQyMzJoLWludGYubwpkaWZmIC0tZ2l0IGEvZHJpdmVycy91c2IvbWlz Yy9mdDIzMmgtaW50Zi5jIGIvZHJpdmVycy91c2IvbWlzYy9mdDIzMmgtaW50Zi5jCm5ldyBmaWxl IG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAwMDAwMC4uNGY1OGVmNTUyMzE5Ci0tLSAvZGV2L251 bGwKKysrIGIvZHJpdmVycy91c2IvbWlzYy9mdDIzMmgtaW50Zi5jCkBAIC0wLDAgKzEsMTQ2NCBA QAorLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjAKKy8qCisgKiBGVERJIEZUMjMy SCBpbnRlcmZhY2UgZHJpdmVyIGZvciBBUlJJIEZQR0EgY29uZmlndXJhdGlvbgorICoKKyAqIENv cHlyaWdodCAoQykgMjAxNyAtIDIwMTggREVOWCBTb2Z0d2FyZSBFbmdpbmVlcmluZworICogQW5h dG9saWogR3VzdHNjaGluIDxhZ3VzdEBkZW54LmRlPgorICoKKyAqICAgIEZpZ3VyZTogRlQyMzJI LCBGUEdBIERldmljZXMgYW5kIERyaXZlcnMgUmVsYXRpb25zaGlwCisgKgorICogICAgICArLS0t LS0tLS0tLS0tLSsKKyAqICAgICAgfCAgICAgICAgICAgICB8CisgKiAgICAgIHwgIFNUUkFUSVgg ViAgfFBTLVNQSSAgICAgICAgIEZUMjQ1IEZJRk8gJiBHUElPCisgKiAgICAgIHwgICAgICAgICAg ICAgKy0tLS0tKyAgICArLS0tLS0tLS0tLS0tLS0tLS0tLSsKKyAqICAgICAgfCAgb24gQm9hcmQg MSB8ICAgICArICAgICsgICAgICAgICAgICAgICAgICAgfAorICogICAgICB8ICAgICAgICAgICAg IHwgICAgICAgICAgICAgICAgICAgICAgICAgKy0tLS0rLS0tKworICogICAgICB8ICBQQ0llICAg ICAgIHwgICBBREJVUyZBQ0JVUyAgICAgICAgICAgfCAgQ1BMRCAgfAorICogICAgICArLS0tKy0t LS0tLS0tLSsgQ29ubmVjdGlvbiBPcHRpb25zICAgICAgKy0tLS0rLS0tKworICogICAgICAgICAg XiAgICAgICAgICAoTVBTU0Ugb3IgRklGTyZHUElPKSAgICAgICAgICB8CisgKiAgICAgICAgICAr ICAgICAgICAgICAgICAgICAgKyAgICAgICAgICAgICAgKy0tLS0tLSstLS0tLS0tKworICogICAg IGFsdGVyYS1jdnAgICstLS0tLS0tLS0tLSstLS0tLS0tLS0tKyAgIHwgICAgIEZQUCAgICAgIHwK KyAqICAgICAgICAgICAgICAgICB8ICAgICAgICBGVDIzMkggICAgICAgIHwgICB8ICAgICAgICAg ICAgICB8CisgKiAgICAgICAgICAgICAgICAgfCAgICAgMHgwNDAzOjB4NzE0OCAgICB8ICAgfCAg IEFSUklBIDEwICAgfAorICogICAgICAgICAgICAgICAgIHwgICAgIDB4MDQwMzoweDcxNDkgICAg fCAgIHwgICAgICAgICAgICAgIHwKKyAqICAgICAgICAgICAgICAgICArLS0tLS0tLS0tLSstLS0t LS0tLS0tLSsgICB8ICBvbiBCb2FyZCAyICB8CisgKiAgICAgICAgICAgICAgICAgICAgICAgICAg ICB8ICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgfAorICogICAgICAgICAgICAgICAgKy0t LS0tLS0tLS0tKy0tLS0tLS0tLS0tLSsgIHwgICAgICAgIFBDSWUgIHwKKyAqICAgICAgICBjcmVh dGVzIHwgZnQyMzJoLWludGYgKFVTQiBtaXNjKSB8ICArLS0tLS0tLS0tLSstLS0rCisgKiAgICAg ICBwbGF0Zm9ybSB8ICAgICBidWxrL2N0cmwgeGZlciAgICAgfCAgICAgICAgICAgICBeCisgKiAg ICAgICAgZGV2aWNlcyB8QUNCVVMgR1BJTyBDdHJsICgweDcxNDgpfCAgICAgICAgICAgICB8Cisg KiAgICAgICAgIGJlbG93ICB8TVBTU0UgR1BJTyBDdHJsICgweDcxNDkpfCAgICAgICAgICAgICB8 CisgKiAgICAgICAgICAgICAgICArLS0tLS0tLSstLS0tLS0tKy0tLS0tLS0tKyAgICAgICAgICAg ICB8CisgKiAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgfCAgICAgICAgICAgICAgICAg ICAgICB8CisgKiAgICAgICAgICAgZm9yICAgICArLS0tLSsgICAgICAgKy0tLS0tLSsgICAgZm9y ICAgICAgICB8CisgKiAgICAgICAgUElEIDB4NzE0OSB8ICAgICAgICAgICAgICAgICAgIHwgUElE IDB4NzE0OCAgICB8CisgKiAgICAgICAgICstLS0tLS0tLS0rLS0tLS0tLS0rICArLS0tLS0tLSst LS0tLS0tLS0rICAgICB8CisgKiAgICAgICAgIHwgIGZ0ZGktbXBzc2Utc3BpICB8ICB8ICAgICAg ICAgICAgICAgICB8ICAgICB8CisgKiAgICAgICAgIHwgYWx0ZXJhLXBzLXNwaSBpbiB8ICB8ZnRk aS1maWZvLWZwcC1tZ3J8ICAgICB8CisgKiAgICAgICAgIHwgICBzcGlfYm9hcmRfaW5mbyB8ICB8 ICAgICAgICAgICAgICAgICB8ICAgICB8CisgKiAgICAgICAgICstLS0tLS0tLS0rLS0tLS0tLS0r ICArLS0tLS0tLS0rLS0tLS0tLS0rICAgICB8CisgKiAgICAgICAgICAgICAgICAgICBeICAgICAg ICAgICAgICAgICAgICBeICAgICAgICAgICAgICB8CisgKiAgICAgICAgRHJpdmVyczogICB8ICAg ICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICB8CisgKiAgICAgICAgICAgICAgICAgICAr ICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICB8CisgKiAgICAgIE1QU1NFIFNQSSBt YXN0ZXIoc3BpLWZ0ZGktbXBzc2UpICB8ICAgICAgICAgICAgICArCisgKiAgICAgICAgICAgICAg ICAgICBeICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICB8CisgKiAgICAgICAgICAg ICAgICAgICB8ICAgICAgICAgICAgICAgICAgICArICAgICAgICAgICAgICArCisgKiAgICAgICAg ICAgICBhbHRlcmEtcHMtc3BpICAgICAgICBmdGRpLWZpZm8tZnBwICAgIGFsdGVyYS1jdnAKKyAq ICAgICAgICAgICAgICBGUEdBIE1hbmFnZXIgICAgICAgICBGUEdBIE1hbmFnZXIgICBGUEdBIE1h bmFnZXIKKyAqCisgKgorICogV2hlbiB1c2luZyB5b3VyIGN1c3RvbSBVU0IgcHJvZHVjdCBJRCwg dGhpcyBGVDIzMkggaW50ZXJmYWNlIGRyaXZlcgorICogYWxzbyBhbGxvd3MgdG8gcmVnaXN0ZXIg dGhlIEdQSU8gY29udHJvbGxlciBmb3IgQ0JVUyBwaW5zIG9yIGZvcgorICogTVBTU0UgR1BJTyBw aW5zLiBCZWxvdyBhcmUgZXhhbXBsZXMgaG93IHRvIHVzZSB0aGUgZHJpdmVyIGFzIENCVVMtCisg KiBvciBNUFNTRS1HUElPIGNvbnRyb2xsZXIuCisgKgorICogRm9yIENCVVMtR1BJT3MgYWRkIG5l dyBlbnRyeSB3aXRoIHlvdXIgUElEIHRvIGZ0MjMyaF9pbnRmX3RhYmxlW106CisgKiBzdGF0aWMg Y29uc3Qgc3RydWN0IGZ0MjMyaF9pbnRmX2luZm8gZnRkaV9jYnVzX2dwaW9faW50Zl9pbmZvID0g eworICoJLnVzZV9jYnVzX2dwaW9fY3RybCA9IHRydWUsCisgKiB9OworICogeyBVU0JfREVWSUNF KEZURElfVklELCBQSUQpLAorICogICAuZHJpdmVyX2luZm8gPSAoa2VybmVsX3Vsb25nX3QpJmZ0 ZGlfY2J1c19ncGlvX2ludGZfaW5mbyB9LAorICoKKyAqIEZvciBNUFNTRS1HUElPIGFkZCBuZXcg ZW50cnkgd2l0aCB5b3VyIFBJRCB0byBmdDIzMmhfaW50Zl90YWJsZVtdOgorICogc3RhdGljIGNv bnN0IHN0cnVjdCBmdDIzMmhfaW50Zl9pbmZvIGZ0ZGlfbXBzc2VfZ3Bpb19pbnRmX2luZm8gPSB7 CisgKgkudXNlX21wc3NlX2dwaW9fY3RybCA9IHRydWUsCisgKiB9OworICogeyBVU0JfREVWSUNF KEZURElfVklELCBQSUQpLAorICogICAuZHJpdmVyX2luZm8gPSAoa2VybmVsX3Vsb25nX3QpJmZ0 ZGlfbXBzc2VfZ3Bpb19pbnRmX2luZm8gfSwKKyAqCisgKiBXaXRoIGN1c3RvbSBVU0IgcHJvZHVj dCBJRHMgaXQgaXMgYWxzbyBwb3NzaWJsZSB0byB1c2UgRlQyMzJIIFNQSSBidXMKKyAqIHdpdGgg ZGlmZmVyZW50IFNQSSBzbGF2ZSBkZXZpY2VzIGF0dGFjaGVkIChlLmcuIFNQSS1OT1IgZmxhc2gg Y2hpcHMsCisgKiBzcGlkZXYsIGV0Yy4pLiBFeGFtcGxlIGJlbG93IHNob3dzIGhvdyB0byBhZGQg YSBidXMgd2l0aCB0d28gU1BJIHNsYXZlCisgKiBkZXZpY2VzIGZvciB5b3VyIFVTQiBQSUQ6Cisg KgorICogc3RhdGljIHN0cnVjdCBzcGlfYm9hcmRfaW5mbyBmdGRpX3NwaV9idXNfaW5mb1tdID0g eworICoJeworICoJLm1vZGFsaWFzCT0gIncyNXEzMiIsCisgKgkubW9kZQkJPSBTUElfTU9ERV8w LAorICoJLm1heF9zcGVlZF9oegk9IDYwMDAwMDAwLAorICoJLmJ1c19udW0JPSAwLAorICoJLmNo aXBfc2VsZWN0CT0gMCwgLy8gVENLL1NLIGF0IEFEQlVTMAorICoJfSwKKyAqCXsKKyAqCS5tb2Rh bGlhcwk9ICJzcGlkZXYiLAorICoJLm1vZGUJCT0gU1BJX01PREVfMCB8IFNQSV9MU0JfRklSU1Qg fCBTUElfQ1NfSElHSCwKKyAqCS5tYXhfc3BlZWRfaHoJPSAzMDAwMDAwMCwKKyAqCS5idXNfbnVt CT0gMCwKKyAqCS5jaGlwX3NlbGVjdAk9IDUsIC8vIEdQSU9IMCBhdCBBQ0JVUzAKKyAqCX0sCisg KiB9OworICoKKyAqIHN0YXRpYyBjb25zdCBzdHJ1Y3QgbXBzc2Vfc3BpX3BsYXRmb3JtX2RhdGEg ZnRkaV9zcGlfYnVzX3BsYXRfZGF0YSA9IHsKKyAqCS5vcHMJCT0gJmZ0MjMyaF9pbnRmX29wcywK KyAqCS5zcGlfaW5mbwk9IGZ0ZGlfc3BpX2J1c19pbmZvLAorICoJLnNwaV9pbmZvX2xlbgk9IEFS UkFZX1NJWkUoZnRkaV9zcGlfYnVzX2luZm8pLAorICogfTsKKyAqCisgKiBzdGF0aWMgY29uc3Qg c3RydWN0IGZ0MjMyaF9pbnRmX2luZm8gZnRkaV9zcGlfYnVzX2ludGZfaW5mbyA9IHsKKyAqCS5w cm9iZSAgPSBmdDIzMmhfaW50Zl9zcGlfcHJvYmUsCisgKgkucmVtb3ZlICA9IGZ0MjMyaF9pbnRm X3NwaV9yZW1vdmUsCisgKgkucGxhdF9kYXRhICA9ICZmdGRpX3NwaV9idXNfcGxhdF9kYXRhLAor ICogfTsKKyAqIHsgVVNCX0RFVklDRShGVERJX1ZJRCwgWU9VUl9QSUQpLAorICoJLmRyaXZlcl9p bmZvID0gKGtlcm5lbF91bG9uZ190KSZmdGRpX3NwaV9idXNfaW50Zl9pbmZvIH0sCisgKi8KKwor I2luY2x1ZGUgPGxpbnV4L2tlcm5lbC5oPgorI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPgorI2lu Y2x1ZGUgPGxpbnV4L2RldmljZS5oPgorI2luY2x1ZGUgPGxpbnV4L2RlbGF5Lmg+CisjaW5jbHVk ZSA8bGludXgvcHJpbnRrLmg+CisjaW5jbHVkZSA8bGludXgvZ3Bpby9kcml2ZXIuaD4KKyNpbmNs dWRlIDxsaW51eC9ncGlvL21hY2hpbmUuaD4KKyNpbmNsdWRlIDxsaW51eC9pZHIuaD4KKyNpbmNs dWRlIDxsaW51eC9tdXRleC5oPgorI2luY2x1ZGUgPGxpbnV4L3BsYXRmb3JtX2RldmljZS5oPgor I2luY2x1ZGUgPGxpbnV4L3NsYWIuaD4KKyNpbmNsdWRlIDxsaW51eC9zcGkvc3BpLmg+CisjaW5j bHVkZSA8bGludXgvdXNiL2NoOS5oPgorI2luY2x1ZGUgPGxpbnV4L3VzYi5oPgorI2luY2x1ZGUg PGxpbnV4L3VzYi9mdDIzMmgtaW50Zi5oPgorCitzdHJ1Y3QgZnQyMzJoX2ludGZfcHJpdiB7CisJ c3RydWN0IHVzYl9pbnRlcmZhY2UJKmludGY7CisJc3RydWN0IHVzYl9kZXZpY2UJKnVkZXY7CisJ c3RydWN0IG11dGV4CQlpb19tdXRleDsgLyogc3luYyBJL08gd2l0aCBkaXNjb25uZWN0ICovCisJ c3RydWN0IG11dGV4CQlvcHNfbXV0ZXg7CisJaW50CQkJYml0YmFuZ19lbmFibGVkOworCWludAkJ CWlkOworCWludAkJCWluZGV4OworCXU4CQkJYnVsa19pbjsKKwl1OAkJCWJ1bGtfb3V0OworCXNp emVfdAkJCWJ1bGtfaW5fc3o7CisJdm9pZAkJCSpidWxrX2luX2J1ZjsKKworCWNvbnN0IHN0cnVj dCB1c2JfZGV2aWNlX2lkCSp1c2JfZGV2X2lkOworCXN0cnVjdCBmdDIzMmhfaW50Zl9pbmZvCQkq aW5mbzsKKwlzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlCQkqZmlmb19wZGV2OworCXN0cnVjdCBwbGF0 Zm9ybV9kZXZpY2UJCSpzcGlfcGRldjsKKwlzdHJ1Y3QgZ3Bpb2RfbG9va3VwX3RhYmxlCSpsb29r dXBfZmlmbzsKKwlzdHJ1Y3QgZ3Bpb2RfbG9va3VwX3RhYmxlCSpsb29rdXBfY3M7CisKKwlzdHJ1 Y3QgZ3Bpb19jaGlwCWNidXNfZ3BpbzsKKwljb25zdCBjaGFyCQkqY2J1c19ncGlvX25hbWVzWzRd OworCXU4CQkJY2J1c19waW5fb2Zmc2V0c1s0XTsKKwl1OAkJCWNidXNfbWFzazsKKwl1OAkJCXBp bmJ1Zls0XTsKKwl1OAkJCWVlcHJvbVtGVERJX01BWF9FRVBST01fU0laRV07CisKKwlzdHJ1Y3Qg Z3Bpb19jaGlwCW1wc3NlX2dwaW87CisJdTgJCQlncGlvbF9tYXNrOworCXU4CQkJZ3Bpb2hfbWFz azsKKwl1OAkJCWdwaW9sX2RpcjsKKwl1OAkJCWdwaW9oX2RpcjsKKwl1OAkJCXR4X2J1Zls0XTsK K307CisKKy8qIERldmljZSBpbmZvIHN0cnVjdCB1c2VkIGZvciBkZXZpY2Ugc3BlY2lmaWMgaW5p dC4gKi8KK3N0cnVjdCBmdDIzMmhfaW50Zl9pbmZvIHsKKwl1bnNpZ25lZCBpbnQgdXNlX2NidXNf Z3Bpb19jdHJsOworCXVuc2lnbmVkIGludCB1c2VfbXBzc2VfZ3Bpb19jdHJsOworCWludCAoKnBy b2JlKShzdHJ1Y3QgdXNiX2ludGVyZmFjZSAqaW50ZiwgY29uc3Qgdm9pZCAqcGxhdF9kYXRhKTsK KwlpbnQgKCpyZW1vdmUpKHN0cnVjdCB1c2JfaW50ZXJmYWNlICppbnRmKTsKKwljb25zdCB2b2lk ICpwbGF0X2RhdGE7IC8qIG9wdGlvbmFsLCBwYXNzZWQgdG8gcHJvYmUoKSAqLworfTsKKworc3Rh dGljIERFRklORV9JREEoZnRkaV9kZXZpZF9pZGEpOworCisvKiBVc2UgYmF1ZHJhdGUgY2FsY3Vs YXRpb24gYm9ycm93ZWQgZnJvbSBsaWJmdGRpICovCitzdGF0aWMgaW50IGZ0ZGlfdG9fY2xrYml0 cyhpbnQgYmF1ZHJhdGUsIHVuc2lnbmVkIGludCBjbGssIGludCBjbGtfZGl2LAorCQkJICAgdW5z aWduZWQgbG9uZyAqZW5jb2RlZF9kaXZpc29yKQoreworCXN0YXRpYyBjb25zdCBjaGFyIGZyYWNf Y29kZVs4XSA9IHsgMCwgMywgMiwgNCwgMSwgNSwgNiwgNyB9OworCWludCBiZXN0X2JhdWQgPSAw OworCWludCBkaXYsIGJlc3RfZGl2OworCisJaWYgKGJhdWRyYXRlID49IGNsayAvIGNsa19kaXYp IHsKKwkJKmVuY29kZWRfZGl2aXNvciA9IDA7CisJCWJlc3RfYmF1ZCA9IGNsayAvIGNsa19kaXY7 CisJfSBlbHNlIGlmIChiYXVkcmF0ZSA+PSBjbGsgLyAoY2xrX2RpdiArIGNsa19kaXYgLyAyKSkg eworCQkqZW5jb2RlZF9kaXZpc29yID0gMTsKKwkJYmVzdF9iYXVkID0gY2xrIC8gKGNsa19kaXYg KyBjbGtfZGl2IC8gMik7CisJfSBlbHNlIGlmIChiYXVkcmF0ZSA+PSBjbGsgLyAoMiAqIGNsa19k aXYpKSB7CisJCSplbmNvZGVkX2Rpdmlzb3IgPSAyOworCQliZXN0X2JhdWQgPSBjbGsgLyAoMiAq IGNsa19kaXYpOworCX0gZWxzZSB7CisJCS8qCisJCSAqIERpdmlkZSBieSAxNiB0byBoYXZlIDMg ZnJhY3Rpb25hbCBiaXRzIGFuZAorCQkgKiBvbmUgYml0IGZvciByb3VuZGluZworCQkgKi8KKwkJ ZGl2ID0gY2xrICogMTYgLyBjbGtfZGl2IC8gYmF1ZHJhdGU7CisJCWlmIChkaXYgJiAxKQkvKiBE ZWNpZGUgaWYgdG8gcm91bmQgdXAgb3IgZG93biAqLworCQkJYmVzdF9kaXYgPSBkaXYgLyAyICsg MTsKKwkJZWxzZQorCQkJYmVzdF9kaXYgPSBkaXYgLyAyOworCQlpZiAoYmVzdF9kaXYgPiAweDIw MDAwKQorCQkJYmVzdF9kaXYgPSAweDFmZmZmOworCQliZXN0X2JhdWQgPSBjbGsgKiAxNiAvIGNs a19kaXYgLyBiZXN0X2RpdjsKKwkJaWYgKGJlc3RfYmF1ZCAmIDEpCS8qIERlY2lkZSBpZiB0byBy b3VuZCB1cCBvciBkb3duICovCisJCQliZXN0X2JhdWQgPSBiZXN0X2JhdWQgLyAyICsgMTsKKwkJ ZWxzZQorCQkJYmVzdF9iYXVkID0gYmVzdF9iYXVkIC8gMjsKKwkJKmVuY29kZWRfZGl2aXNvciA9 IChiZXN0X2RpdiA+PiAzKSB8CisJCQkJICAgKGZyYWNfY29kZVtiZXN0X2RpdiAmIDB4N10gPDwg MTQpOworCX0KKwlyZXR1cm4gYmVzdF9iYXVkOworfQorCisjZGVmaW5lIEhfQ0xLCTEyMDAwMDAw MAorI2RlZmluZSBDX0NMSwk0ODAwMDAwMAorc3RhdGljIGludCBmdGRpX2NvbnZlcnRfYmF1ZHJh dGUoc3RydWN0IGZ0MjMyaF9pbnRmX3ByaXYgKnByaXYsIGludCBiYXVkLAorCQkJCSB1MTYgKnZh bHVlLCB1MTYgKmluZGV4KQoreworCXVuc2lnbmVkIGxvbmcgZW5jb2RlZF9kaXZpc29yID0gMDsK KwlpbnQgYmVzdF9iYXVkID0gMDsKKworCWlmIChiYXVkIDw9IDApCisJCXJldHVybiAtRUlOVkFM OworCisJLyoKKwkgKiBPbiBIIERldmljZXMsIHVzZSAxMjAwMDAwMCBiYXVkcmF0ZSB3aGVuIHBv c3NpYmxlLgorCSAqIFdlIGhhdmUgYSAxNCBiaXQgZGl2aXNvciwgYSAxIGJpdCBkaXZpc29yIHN3 aXRjaCAoMTAgb3IgMTYpLAorCSAqIHRocmVlIGZyYWN0aW9uYWwgYml0cyBhbmQgYSAxMjAgTUh6 IGNsb2NrLiBBc3N1bWUgQU5fMTIwCisJICogIlN1Yi1pbnRlZ2VyIGRpdmlzb3JzIGJldHdlZW4g MCBhbmQgMiBhcmUgbm90IGFsbG93ZWQiIGhvbGRzCisJICogZm9yIERJVi8xMCBDTEsgdG9vLCBz byAvMSwgLzEuNSBhbmQgLzIgY2FuIGJlIGhhbmRsZWQgdGhlIHNhbWUKKwkgKi8KKwlpZiAoYmF1 ZCAqIDEwID4gSF9DTEsgLyAweDNmZmYpIHsKKwkJYmVzdF9iYXVkID0gZnRkaV90b19jbGtiaXRz KGJhdWQsIEhfQ0xLLCAxMCwgJmVuY29kZWRfZGl2aXNvcik7CisJCWVuY29kZWRfZGl2aXNvciB8 PSAweDIwMDAwOwkvKiBzd2l0Y2ggb24gQ0xLLzEwICovCisJfSBlbHNlIHsKKwkJYmVzdF9iYXVk ID0gZnRkaV90b19jbGtiaXRzKGJhdWQsIENfQ0xLLCAxNiwgJmVuY29kZWRfZGl2aXNvcik7CisJ fQorCisJaWYgKGJlc3RfYmF1ZCA8PSAwKSB7CisJCXByX2VycigiSW52YWxpZCBiYXVkcmF0ZTog JWRcbiIsIGJlc3RfYmF1ZCk7CisJCXJldHVybiAtRUlOVkFMOworCX0KKworCS8qIENoZWNrIHdp dGhpbiB0b2xlcmFuY2UgKGFib3V0IDUlKSAqLworCWlmICgoYmVzdF9iYXVkICogMiA8IGJhdWQp IHx8CisJICAgIChiZXN0X2JhdWQgPCBiYXVkCisJCT8gKGJlc3RfYmF1ZCAqIDIxIDwgYmF1ZCAq IDIwKQorCQk6IChiYXVkICogMjEgPCBiZXN0X2JhdWQgKiAyMCkpKSB7CisJCXByX2VycigiVW5z dXBwb3J0ZWQgYmF1ZHJhdGUuXG4iKTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCisJLyogU3Bs aXQgaW50byAidmFsdWUiIGFuZCAiaW5kZXgiIHZhbHVlcyAqLworCSp2YWx1ZSA9ICh1MTYpKGVu Y29kZWRfZGl2aXNvciAmIDB4ZmZmZik7CisJKmluZGV4ID0gKHUxNikoKChlbmNvZGVkX2Rpdmlz b3IgPj4gOCkgJiAweGZmMDApIHwgcHJpdi0+aW5kZXgpOworCisJZGV2X2RiZygmcHJpdi0+aW50 Zi0+ZGV2LCAiYmVzdCBiYXVkICVkLCB2L2k6ICVkLCAlZFxuIiwKKwkJYmVzdF9iYXVkLCAqdmFs dWUsICppbmRleCk7CisJcmV0dXJuIGJlc3RfYmF1ZDsKK30KKworLyoKKyAqIGZ0ZGlfY3RybF94 ZmVyIC0gRlRESSBjb250cm9sIGVuZHBvaW50IHRyYW5zZmVyCisgKiBAaW50ZjogVVNCIGludGVy ZmFjZSBwb2ludGVyCisgKiBAZGVzYzogcG9pbnRlciB0byBkZXNjcmlwdG9yIHN0cnVjdCBmb3Ig Y29udHJvbCB0cmFuc2ZlcgorICoKKyAqIFJldHVybjoKKyAqIFJldHVybjogSWYgc3VjY2Vzc2Z1 bCwgdGhlIG51bWJlciBvZiBieXRlcyB0cmFuc2ZlcnJlZC4gT3RoZXJ3aXNlLAorICogYSBuZWdh dGl2ZSBlcnJvciBudW1iZXIuCisgKi8KK3N0YXRpYyBpbnQgZnRkaV9jdHJsX3hmZXIoc3RydWN0 IHVzYl9pbnRlcmZhY2UgKmludGYsIHN0cnVjdCBjdHJsX2Rlc2MgKmRlc2MpCit7CisJc3RydWN0 IGZ0MjMyaF9pbnRmX3ByaXYgKnByaXYgPSB1c2JfZ2V0X2ludGZkYXRhKGludGYpOworCXN0cnVj dCB1c2JfZGV2aWNlICp1ZGV2ID0gcHJpdi0+dWRldjsKKwl1bnNpZ25lZCBpbnQgcGlwZTsKKwlp bnQgcmV0OworCisJbXV0ZXhfbG9jaygmcHJpdi0+aW9fbXV0ZXgpOworCWlmICghcHJpdi0+aW50 ZikgeworCQlyZXQgPSAtRU5PREVWOworCQlnb3RvIGV4aXQ7CisJfQorCisJaWYgKCFkZXNjLT5k YXRhICYmIGRlc2MtPnNpemUpCisJCWRlc2MtPmRhdGEgPSBwcml2LT5idWxrX2luX2J1ZjsKKwor CWlmIChkZXNjLT5kaXJfb3V0KQorCQlwaXBlID0gdXNiX3NuZGN0cmxwaXBlKHVkZXYsIDApOwor CWVsc2UKKwkJcGlwZSA9IHVzYl9yY3ZjdHJscGlwZSh1ZGV2LCAwKTsKKworCXJldCA9IHVzYl9j b250cm9sX21zZyh1ZGV2LCBwaXBlLCBkZXNjLT5yZXF1ZXN0LCBkZXNjLT5yZXF1ZXN0dHlwZSwK KwkJCSAgICAgIGRlc2MtPnZhbHVlLCBkZXNjLT5pbmRleCwgZGVzYy0+ZGF0YSwgZGVzYy0+c2l6 ZSwKKwkJCSAgICAgIGRlc2MtPnRpbWVvdXQpOworCWlmIChyZXQgPCAwKQorCQlkZXZfZGJnKCZ1 ZGV2LT5kZXYsICJjdHJsIG1zZyBmYWlsZWQ6ICVkXG4iLCByZXQpOworZXhpdDoKKwltdXRleF91 bmxvY2soJnByaXYtPmlvX211dGV4KTsKKwlyZXR1cm4gcmV0OworfQorCisvKgorICogZnRkaV9i dWxrX3hmZXIgLSBGVERJIGJ1bGsgZW5kcG9pbnQgdHJhbnNmZXIKKyAqIEBpbnRmOiBVU0IgaW50 ZXJmYWNlIHBvaW50ZXIKKyAqIEBkZXNjOiBwb2ludGVyIHRvIGRlc2NyaXB0b3Igc3RydWN0IGZv ciBidWxrLWluIG9yIGJ1bGstb3V0IHRyYW5zZmVyCisgKgorICogUmV0dXJuOgorICogSWYgc3Vj Y2Vzc2Z1bCwgMC4gT3RoZXJ3aXNlIGEgbmVnYXRpdmUgZXJyb3IgbnVtYmVyLiBUaGUgbnVtYmVy IG9mCisgKiBhY3R1YWwgYnl0ZXMgdHJhbnNmZXJyZWQgd2lsbCBiZSBzdG9yZWQgaW4gdGhlIEBk ZXNjLT5hY3RfbGVuIGZpZWxkCisgKiBvZiB0aGUgZGVzY3JpcHRvciBzdHJ1Y3QuCisgKi8KK3N0 YXRpYyBpbnQgZnRkaV9idWxrX3hmZXIoc3RydWN0IHVzYl9pbnRlcmZhY2UgKmludGYsIHN0cnVj dCBidWxrX2Rlc2MgKmRlc2MpCit7CisJc3RydWN0IGZ0MjMyaF9pbnRmX3ByaXYgKnByaXYgPSB1 c2JfZ2V0X2ludGZkYXRhKGludGYpOworCXN0cnVjdCB1c2JfZGV2aWNlICp1ZGV2ID0gcHJpdi0+ dWRldjsKKwl1bnNpZ25lZCBpbnQgcGlwZTsKKwlpbnQgcmV0OworCisJbXV0ZXhfbG9jaygmcHJp di0+aW9fbXV0ZXgpOworCWlmICghcHJpdi0+aW50ZikgeworCQlyZXQgPSAtRU5PREVWOworCQln b3RvIGV4aXQ7CisJfQorCisJaWYgKGRlc2MtPmRpcl9vdXQpCisJCXBpcGUgPSB1c2Jfc25kYnVs a3BpcGUodWRldiwgcHJpdi0+YnVsa19vdXQpOworCWVsc2UKKwkJcGlwZSA9IHVzYl9yY3ZidWxr cGlwZSh1ZGV2LCBwcml2LT5idWxrX2luKTsKKworCXJldCA9IHVzYl9idWxrX21zZyh1ZGV2LCBw aXBlLCBkZXNjLT5kYXRhLCBkZXNjLT5sZW4sCisJCQkgICAmZGVzYy0+YWN0X2xlbiwgZGVzYy0+ dGltZW91dCk7CisJaWYgKHJldCkKKwkJZGV2X2RiZygmdWRldi0+ZGV2LCAiYnVsayBtc2cgZmFp bGVkOiAlZFxuIiwgcmV0KTsKKworZXhpdDoKKwltdXRleF91bmxvY2soJnByaXYtPmlvX211dGV4 KTsKKwlyZXR1cm4gcmV0OworfQorCisvKgorICogZnRkaV9zZXRfYmF1ZHJhdGUgLSBzZXQgdGhl IGRldmljZSBiYXVkIHJhdGUKKyAqIEBpbnRmOiBVU0IgaW50ZXJmYWNlIHBvaW50ZXIKKyAqIEBi YXVkcmF0ZTogYmF1ZCByYXRlIHZhbHVlIHRvIHNldAorICoKKyAqIFJldHVybjogSWYgc3VjY2Vz c2Z1bCwgMC4gT3RoZXJ3aXNlIGEgbmVnYXRpdmUgZXJyb3IgbnVtYmVyLgorICovCitzdGF0aWMg aW50IGZ0ZGlfc2V0X2JhdWRyYXRlKHN0cnVjdCB1c2JfaW50ZXJmYWNlICppbnRmLCBpbnQgYmF1 ZHJhdGUpCit7CisJc3RydWN0IGZ0MjMyaF9pbnRmX3ByaXYgKnByaXYgPSB1c2JfZ2V0X2ludGZk YXRhKGludGYpOworCXN0cnVjdCBjdHJsX2Rlc2MgZGVzYzsKKwl1MTYgaW5kZXgsIHZhbHVlOwor CWludCByZXQ7CisKKwlpZiAocHJpdi0+Yml0YmFuZ19lbmFibGVkKQorCQliYXVkcmF0ZSAqPSA0 OworCisJcmV0ID0gZnRkaV9jb252ZXJ0X2JhdWRyYXRlKHByaXYsIGJhdWRyYXRlLCAmdmFsdWUs ICZpbmRleCk7CisJaWYgKHJldCA8IDApCisJCXJldHVybiByZXQ7CisKKwlkZXNjLmRpcl9vdXQg PSB0cnVlOworCWRlc2MucmVxdWVzdCA9IEZURElfU0lPX1NFVF9CQVVEUkFURV9SRVFVRVNUOwor CWRlc2MucmVxdWVzdHR5cGUgPSBVU0JfVFlQRV9WRU5ET1IgfCBVU0JfUkVDSVBfREVWSUNFIHwg VVNCX0RJUl9PVVQ7CisJZGVzYy52YWx1ZSA9IHZhbHVlOworCWRlc2MuaW5kZXggPSBpbmRleDsK KwlkZXNjLmRhdGEgPSBOVUxMOworCWRlc2Muc2l6ZSA9IDA7CisJZGVzYy50aW1lb3V0ID0gVVNC X0NUUkxfU0VUX1RJTUVPVVQ7CisKKwlyZXQgPSBmdGRpX2N0cmxfeGZlcihpbnRmLCAmZGVzYyk7 CisJaWYgKHJldCA8IDApIHsKKwkJZGV2X2RiZygmaW50Zi0+ZGV2LCAiZmFpbGVkIHRvIHNldCBi YXVkcmF0ZTogJWRcbiIsIHJldCk7CisJCXJldHVybiByZXQ7CisJfQorCisJcmV0dXJuIDA7Cit9 CisKKy8qCisgKiBmdGRpX3JlYWRfZGF0YSAtIHJlYWQgZnJvbSBGVERJIGJ1bGstaW4gZW5kcG9p bnQKKyAqIEBpbnRmOiBVU0IgaW50ZXJmYWNlIHBvaW50ZXIKKyAqIEBidWY6ICBwb2ludGVyIHRv IGRhdGEgYnVmZmVyCisgKiBAbGVuOiAgbGVuZ3RoIGluIGJ5dGVzIG9mIHRoZSBkYXRhIHRvIHJl YWQKKyAqCisgKiBUaGUgdHdvIG1vZGVtIHN0YXR1cyBieXRlcyB0cmFuc2ZlcnJlZCBpbiBldmVy eSByZWFkIHdpbGwKKyAqIGJlIHJlbW92ZWQgYW5kIHdpbGwgbm90IGFwcGVhciBpbiB0aGUgZGF0 YSBidWZmZXIuCisgKgorICogUmV0dXJuOgorICogSWYgc3VjY2Vzc2Z1bCwgdGhlIG51bWJlciBv ZiBkYXRhIGJ5dGVzIHJlY2VpdmVkIChjYW4gYmUgMCkuCisgKiBPdGhlcndpc2UsIGEgbmVnYXRp dmUgZXJyb3IgbnVtYmVyLgorICovCitzdGF0aWMgaW50IGZ0ZGlfcmVhZF9kYXRhKHN0cnVjdCB1 c2JfaW50ZXJmYWNlICppbnRmLCB2b2lkICpidWYsIHNpemVfdCBsZW4pCit7CisJc3RydWN0IGZ0 MjMyaF9pbnRmX3ByaXYgKnByaXYgPSB1c2JfZ2V0X2ludGZkYXRhKGludGYpOworCXN0cnVjdCBi dWxrX2Rlc2MgZGVzYzsKKwlpbnQgcmV0OworCisJZGVzYy5hY3RfbGVuID0gMDsKKwlkZXNjLmRp cl9vdXQgPSBmYWxzZTsKKwlkZXNjLmRhdGEgPSBwcml2LT5idWxrX2luX2J1ZjsKKwkvKiBEZXZp Y2Ugc2VuZHMgMiBhZGRpdGlvbmFsIHN0YXR1cyBieXRlcywgcmVhZCBhdCBsZWFzdCBsZW4gKyAy ICovCisJZGVzYy5sZW4gPSBtaW5fdChzaXplX3QsIGxlbiArIDIsIHByaXYtPmJ1bGtfaW5fc3op OworCWRlc2MudGltZW91dCA9IEZURElfVVNCX1JFQURfVElNRU9VVDsKKworCXJldCA9IGZ0ZGlf YnVsa194ZmVyKGludGYsICZkZXNjKTsKKwlpZiAocmV0KQorCQlyZXR1cm4gcmV0OworCisJLyog T25seSBzdGF0dXMgYnl0ZXMgYW5kIG5vIGRhdGE/ICovCisJaWYgKGRlc2MuYWN0X2xlbiA8PSAy KQorCQlyZXR1cm4gMDsKKworCS8qIFNraXAgZmlyc3QgdHdvIHN0YXR1cyBieXRlcyAqLworCXJl dCA9IGRlc2MuYWN0X2xlbiAtIDI7CisJaWYgKHJldCA+IGxlbikKKwkJcmV0ID0gbGVuOworCW1l bWNweShidWYsIGRlc2MuZGF0YSArIDIsIHJldCk7CisJcmV0dXJuIHJldDsKK30KKworLyoKKyAq IGZ0ZGlfd3JpdGVfZGF0YSAtIHdyaXRlIHRvIEZUREkgYnVsay1vdXQgZW5kcG9pbnQKKyAqIEBp bnRmOiBVU0IgaW50ZXJmYWNlIHBvaW50ZXIKKyAqIEBidWY6ICBwb2ludGVyIHRvIGRhdGEgYnVm ZmVyCisgKiBAbGVuOiAgbGVuZ3RoIGluIGJ5dGVzIG9mIHRoZSBkYXRhIHRvIHNlbmQKKyAqCisg KiBSZXR1cm46CisgKiBJZiBzdWNjZXNzZnVsLCB0aGUgbnVtYmVyIG9mIGJ5dGVzIHRyYW5zZmVy cmVkLiBPdGhlcndpc2UgYSBuZWdhdGl2ZQorICogZXJyb3IgbnVtYmVyLgorICovCitzdGF0aWMg aW50IGZ0ZGlfd3JpdGVfZGF0YShzdHJ1Y3QgdXNiX2ludGVyZmFjZSAqaW50ZiwKKwkJCSAgIGNv bnN0IGNoYXIgKmJ1Ziwgc2l6ZV90IGxlbikKK3sKKwlzdHJ1Y3QgYnVsa19kZXNjIGRlc2M7CisJ aW50IHJldDsKKworCWRlc2MuYWN0X2xlbiA9IDA7CisJZGVzYy5kaXJfb3V0ID0gdHJ1ZTsKKwlk ZXNjLmRhdGEgPSAoY2hhciAqKWJ1ZjsKKwlkZXNjLmxlbiA9IGxlbjsKKwlkZXNjLnRpbWVvdXQg PSBGVERJX1VTQl9XUklURV9USU1FT1VUOworCisJcmV0ID0gZnRkaV9idWxrX3hmZXIoaW50Ziwg JmRlc2MpOworCWlmIChyZXQgPCAwKQorCQlyZXR1cm4gcmV0OworCisJcmV0dXJuIGRlc2MuYWN0 X2xlbjsKK30KKworLyoKKyAqIGZ0ZGlfc2V0X2JpdG1vZGUgLSBjb25maWd1cmUgYml0YmFuZyBt b2RlCisgKiBAaW50ZjogVVNCIGludGVyZmFjZSBwb2ludGVyCisgKiBAYml0bWFzazogbGluZSBj b25maWd1cmF0aW9uIGJpdG1hc2sKKyAqIEBtb2RlOiBiaXRiYW5nIG1vZGUgdG8gc2V0CisgKgor ICogUmV0dXJuOgorICogSWYgc3VjY2Vzc2Z1bCwgMC4gT3RoZXJ3aXNlIGEgbmVnYXRpdmUgZXJy b3IgbnVtYmVyLgorICovCitzdGF0aWMgaW50IGZ0ZGlfc2V0X2JpdG1vZGUoc3RydWN0IHVzYl9p bnRlcmZhY2UgKmludGYsIHVuc2lnbmVkIGNoYXIgYml0bWFzaywKKwkJCSAgICB1bnNpZ25lZCBj aGFyIG1vZGUpCit7CisJc3RydWN0IGZ0MjMyaF9pbnRmX3ByaXYgKnByaXYgPSB1c2JfZ2V0X2lu dGZkYXRhKGludGYpOworCXN0cnVjdCBjdHJsX2Rlc2MgZGVzYzsKKwlpbnQgcmV0OworCisJZGVz Yy5kaXJfb3V0ID0gdHJ1ZTsKKwlkZXNjLmRhdGEgPSBOVUxMOworCWRlc2MucmVxdWVzdCA9IEZU RElfU0lPX1NFVF9CSVRNT0RFX1JFUVVFU1Q7CisJZGVzYy5yZXF1ZXN0dHlwZSA9IFVTQl9UWVBF X1ZFTkRPUiB8IFVTQl9SRUNJUF9ERVZJQ0UgfCBVU0JfRElSX09VVDsKKwlkZXNjLmluZGV4ID0g MTsKKwlkZXNjLnZhbHVlID0gKG1vZGUgPDwgOCkgfCBiaXRtYXNrOworCWRlc2Muc2l6ZSA9IDA7 CisJZGVzYy50aW1lb3V0ID0gVVNCX0NUUkxfU0VUX1RJTUVPVVQ7CisKKwlyZXQgPSBmdGRpX2N0 cmxfeGZlcihpbnRmLCAmZGVzYyk7CisJaWYgKHJldCA8IDApCisJCXJldHVybiByZXQ7CisKKwlz d2l0Y2ggKG1vZGUpIHsKKwljYXNlIEJJVE1PREVfQklUQkFORzoKKwljYXNlIEJJVE1PREVfQ0JV UzoKKwljYXNlIEJJVE1PREVfU1lOQ0JCOgorCWNhc2UgQklUTU9ERV9TWU5DRkY6CisJCXByaXYt PmJpdGJhbmdfZW5hYmxlZCA9IDE7CisJCWJyZWFrOworCWNhc2UgQklUTU9ERV9NUFNTRToKKwlj YXNlIEJJVE1PREVfUkVTRVQ6CisJZGVmYXVsdDoKKwkJcHJpdi0+Yml0YmFuZ19lbmFibGVkID0g MDsKKwkJYnJlYWs7CisJfQorCisJcmV0dXJuIDA7Cit9CisKKy8qCisgKiBmdGRpX2Rpc2FibGVf Yml0YmFuZyAtIGRpc2FibGUgYml0YmFuZyBtb2RlCisgKiBAaW50ZjogVVNCIGludGVyZmFjZSBw b2ludGVyCisgKgorICogUmV0dXJuOgorICogSWYgc3VjY2Vzc2Z1bCwgMC4gT3RoZXJ3aXNlIGEg bmVnYXRpdmUgZXJyb3IgbnVtYmVyLgorICovCitzdGF0aWMgaW50IGZ0ZGlfZGlzYWJsZV9iaXRi YW5nKHN0cnVjdCB1c2JfaW50ZXJmYWNlICppbnRmKQoreworCWludCByZXQ7CisKKwlyZXQgPSBm dGRpX3NldF9iaXRtb2RlKGludGYsIDAsIEJJVE1PREVfUkVTRVQpOworCWlmIChyZXQgPCAwKSB7 CisJCWRldl9kYmcoJmludGYtPmRldiwgImRpc2FibGUgYml0YmFuZyBmYWlsZWQ6ICVkXG4iLCBy ZXQpOworCQlyZXR1cm4gcmV0OworCX0KKworCXJldHVybiAwOworfQorCitzdGF0aWMgaW50IGZ0 ZGlfcmVhZF9lZXByb20oc3RydWN0IGZ0MjMyaF9pbnRmX3ByaXYgKnByaXYpCit7CisJc3RydWN0 IGN0cmxfZGVzYyBkZXNjOworCXVuc2lnbmVkIGludCBpOworCWludCByZXQ7CisKKwlkZXNjLmRp cl9vdXQgPSBmYWxzZTsKKwlkZXNjLnJlcXVlc3QgPSBGVERJX1NJT19SRUFEX0VFUFJPTV9SRVFV RVNUOworCWRlc2MucmVxdWVzdHR5cGUgPSBVU0JfVFlQRV9WRU5ET1IgfCBVU0JfUkVDSVBfREVW SUNFIHwgVVNCX0RJUl9JTjsKKwlkZXNjLnZhbHVlID0gMDsKKwlkZXNjLnNpemUgPSAyOworCWRl c2MudGltZW91dCA9IFVTQl9DVFJMX0dFVF9USU1FT1VUOworCisJZm9yIChpID0gMDsgaSA8IEZU RElfTUFYX0VFUFJPTV9TSVpFIC8gMjsgaSsrKSB7CisJCWRlc2MuaW5kZXggPSBpOworCQlkZXNj LmRhdGEgPSAmcHJpdi0+ZWVwcm9tW2kgKiAyXTsKKworCQlyZXQgPSBmdGRpX2N0cmxfeGZlcihw cml2LT5pbnRmLCAmZGVzYyk7CisJCWlmIChyZXQgPCAwKSB7CisJCQlkZXZfZGJnKCZwcml2LT5p bnRmLT5kZXYsICJFRVBST00gcmVhZCBmYWlsZWQ6ICVkXG4iLAorCQkJCXJldCk7CisJCQlyZXR1 cm4gcmV0OworCQl9CisJfQorCisJcHJpbnRfaGV4X2R1bXBfZGVidWcoIkVFUFJPTTogIiwgRFVN UF9QUkVGSVhfT0ZGU0VULCAxNiwgMSwKKwkJCSAgICAgcHJpdi0+ZWVwcm9tLCBzaXplb2YocHJp di0+ZWVwcm9tKSwgMSk7CisJcmV0dXJuIDA7Cit9CisKKy8qCisgKiBBQ0JVUyBHUElPIGZ1bmN0 aW9ucworICovCitzdGF0aWMgY29uc3QgY2hhciAqZnRkaV9hY2J1c19uYW1lc1s1XSA9IHsKKwki QUNCVVM1IiwgIkFDQlVTNiIsIE5VTEwsICJBQ0JVUzgiLCAiQUNCVVM5IgorfTsKKworc3RhdGlj IGludCBmdGRpX2NidXNfZ3Bpb19yZWFkX3BpbnMoc3RydWN0IGZ0MjMyaF9pbnRmX3ByaXYgKnBy aXYsCisJCQkJICAgIHVuc2lnbmVkIGNoYXIgKnBpbnMpCit7CisJc3RydWN0IGdwaW9fY2hpcCAq Y2hpcCA9ICZwcml2LT5jYnVzX2dwaW87CisJc3RydWN0IGN0cmxfZGVzYyBkZXNjOworCWludCBy ZXQ7CisKKwlkZXNjLmRpcl9vdXQgPSBmYWxzZTsKKwlkZXNjLnJlcXVlc3QgPSBGVERJX1NJT19S RUFEX1BJTlNfUkVRVUVTVDsKKwlkZXNjLnJlcXVlc3R0eXBlID0gVVNCX1RZUEVfVkVORE9SIHwg VVNCX1JFQ0lQX0RFVklDRSB8IFVTQl9ESVJfSU47CisJZGVzYy52YWx1ZSA9IDA7CisJZGVzYy5p bmRleCA9IDE7CisJZGVzYy5kYXRhID0gJnByaXYtPnBpbmJ1ZlswXTsKKwlkZXNjLnNpemUgPSAx OworCWRlc2MudGltZW91dCA9IFVTQl9DVFJMX0dFVF9USU1FT1VUOworCisJcmV0ID0gZnRkaV9j dHJsX3hmZXIocHJpdi0+aW50ZiwgJmRlc2MpOworCWlmIChyZXQgPCAwKSB7CisJCWRldl9kYmco Y2hpcC0+cGFyZW50LCAiZmFpbGVkIHRvIGdldCBwaW4gdmFsdWVzOiAlZFxuIiwgcmV0KTsKKwkJ cmV0dXJuIHJldDsKKwl9CisKKwkqcGlucyA9IHByaXYtPnBpbmJ1ZlswXTsKKwlyZXR1cm4gMDsK K30KKworc3RhdGljIGlubGluZSB2b2lkIGZ0ZGlfY2J1c19pbml0X2dwaW9fZGF0YShzdHJ1Y3Qg ZnQyMzJoX2ludGZfcHJpdiAqcHJpdiwKKwkJCQkJICAgIGludCBncGlvX251bSwgaW50IGNidXNf bnVtKQoreworCXN3aXRjaCAoY2J1c19udW0pIHsKKwljYXNlIDU6CisJY2FzZSA2OgorCQlwcml2 LT5jYnVzX3Bpbl9vZmZzZXRzW2dwaW9fbnVtXSA9IGNidXNfbnVtIC0gNTsKKwkJYnJlYWs7CisJ Y2FzZSA4OgorCWNhc2UgOToKKwkJcHJpdi0+Y2J1c19waW5fb2Zmc2V0c1tncGlvX251bV0gPSBj YnVzX251bSAtIDY7CisJCWJyZWFrOworCWRlZmF1bHQ6CisJCXJldHVybjsKKwl9CisKKwlwcml2 LT5jYnVzX2dwaW9fbmFtZXNbZ3Bpb19udW1dID0gZnRkaV9hY2J1c19uYW1lc1tjYnVzX251bSAt IDVdOworfQorCitzdGF0aWMgaW50IGZ0ZGlfY2J1c19ncGlvX2dldChzdHJ1Y3QgZ3Bpb19jaGlw ICpjaGlwLCB1bnNpZ25lZCBpbnQgb2Zmc2V0KQoreworCXN0cnVjdCBmdDIzMmhfaW50Zl9wcml2 ICpwcml2ID0gZ3Bpb2NoaXBfZ2V0X2RhdGEoY2hpcCk7CisJdW5zaWduZWQgaW50IG9mZnM7CisJ aW50IHJldDsKKwl1OCBwaW5zID0gMDsKKworCXJldCA9IGZ0ZGlfY2J1c19ncGlvX3JlYWRfcGlu cyhwcml2LCAmcGlucyk7CisJaWYgKHJldCkKKwkJcmV0dXJuIHJldDsKKworCW9mZnMgPSBwcml2 LT5jYnVzX3Bpbl9vZmZzZXRzW29mZnNldF07CisKKwlyZXR1cm4gISEocGlucyAmIEJJVChvZmZz KSk7Cit9CisKK3N0YXRpYyB2b2lkIGZ0ZGlfY2J1c19ncGlvX3NldChzdHJ1Y3QgZ3Bpb19jaGlw ICpjaGlwLAorCQkJICAgICAgIHVuc2lnbmVkIGludCBvZmZzZXQsIGludCB2YWx1ZSkKK3sKKwlz dHJ1Y3QgZnQyMzJoX2ludGZfcHJpdiAqcHJpdiA9IGdwaW9jaGlwX2dldF9kYXRhKGNoaXApOwor CXVuc2lnbmVkIGludCBvZmZzOworCWludCByZXQ7CisKKwlvZmZzID0gcHJpdi0+Y2J1c19waW5f b2Zmc2V0c1tvZmZzZXRdOworCisJaWYgKHZhbHVlKQorCQlwcml2LT5jYnVzX21hc2sgfD0gQklU KG9mZnMpOworCWVsc2UKKwkJcHJpdi0+Y2J1c19tYXNrICY9IH5CSVQob2Zmcyk7CisKKwlyZXQg PSBmdGRpX3NldF9iaXRtb2RlKHByaXYtPmludGYsIHByaXYtPmNidXNfbWFzaywgQklUTU9ERV9D QlVTKTsKKwlpZiAocmV0IDwgMCkKKwkJZGV2X2RiZyhjaGlwLT5wYXJlbnQsICJzZXR0aW5nIHBp biB2YWx1ZSBmYWlsZWQ6ICVkXG4iLCByZXQpOworfQorCitzdGF0aWMgaW50IGZ0ZGlfY2J1c19n cGlvX2RpcmVjdGlvbl9pbnB1dChzdHJ1Y3QgZ3Bpb19jaGlwICpjaGlwLAorCQkJCQkgIHVuc2ln bmVkIGludCBvZmZzZXQpCit7CisJc3RydWN0IGZ0MjMyaF9pbnRmX3ByaXYgKnByaXYgPSBncGlv Y2hpcF9nZXRfZGF0YShjaGlwKTsKKwl1bnNpZ25lZCBpbnQgb2ZmczsKKworCW9mZnMgPSBwcml2 LT5jYnVzX3Bpbl9vZmZzZXRzW29mZnNldF07CisJLyogRGlyZWN0aW9uIGJpdHMgYXJlIGluIHRo ZSB1cHBlciBuaWJibGUgKi8KKwlwcml2LT5jYnVzX21hc2sgJj0gfihCSVQob2ZmcykgPDwgNCk7 CisKKwlyZXR1cm4gZnRkaV9zZXRfYml0bW9kZShwcml2LT5pbnRmLCBwcml2LT5jYnVzX21hc2ss IEJJVE1PREVfQ0JVUyk7Cit9CisKK3N0YXRpYyBpbnQgZnRkaV9jYnVzX2dwaW9fZGlyZWN0aW9u X291dHB1dChzdHJ1Y3QgZ3Bpb19jaGlwICpjaGlwLAorCQkJCQkgICB1bnNpZ25lZCBpbnQgb2Zm c2V0LCBpbnQgdmFsdWUpCit7CisJc3RydWN0IGZ0MjMyaF9pbnRmX3ByaXYgKnByaXYgPSBncGlv Y2hpcF9nZXRfZGF0YShjaGlwKTsKKwl1bnNpZ25lZCBpbnQgb2ZmczsKKworCW9mZnMgPSBwcml2 LT5jYnVzX3Bpbl9vZmZzZXRzW29mZnNldF07CisJcHJpdi0+Y2J1c19tYXNrIHw9IEJJVChvZmZz KSA8PCA0OworCisJaWYgKHZhbHVlKQorCQlwcml2LT5jYnVzX21hc2sgfD0gQklUKG9mZnMpOwor CWVsc2UKKwkJcHJpdi0+Y2J1c19tYXNrICY9IH5CSVQob2Zmcyk7CisKKwlyZXR1cm4gZnRkaV9z ZXRfYml0bW9kZShwcml2LT5pbnRmLCBwcml2LT5jYnVzX21hc2ssIEJJVE1PREVfQ0JVUyk7Cit9 CisKK3N0YXRpYyBpbnQgZnQyMzJoX2ludGZfYWRkX2NidXNfZ3BpbyhzdHJ1Y3QgZnQyMzJoX2lu dGZfcHJpdiAqcHJpdikKK3sKKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSAmcHJpdi0+aW50Zi0+ZGV2 OworCWNoYXIgKipuYW1lcywgKmxhYmVsOworCWludCBuZ3BpbyA9IDA7CisJaW50IGksIHJldDsK Kwl1OCB2YWw7CisKKwlyZXQgPSBmdGRpX3JlYWRfZWVwcm9tKHByaXYpOworCWlmIChyZXQgPCAw KQorCQlyZXR1cm4gcmV0OworCisJLyogQ2hlY2sgaWYgSS9PIG1vZGUgaXMgZW5hYmxlZCBmb3Ig c3VwcG9ydGVkIHBpbnMgNSwgNiwgOCwgOSAqLworCWZvciAoaSA9IDU7IGkgPCAxMDsgaSsrKSB7 CisJCXZhbCA9IHByaXYtPmVlcHJvbVsweDE4ICsgaSAvIDJdID4+IChpICUgMiA/IDQgOiAwKTsK KwkJaWYgKCh2YWwgJiAweDBmKSA9PSBGVERJXzIzMkhfQ0JVU19JT01PREUpIHsKKwkJCWRldl9k YmcoZGV2LCAiZ3Bpby0lZCBAIEFDQlVTJWRcbiIsCisJCQkJcHJpdi0+Y2J1c19ncGlvLm5ncGlv LCBpKTsKKwkJCXByaXYtPmNidXNfZ3Bpby5uZ3BpbysrOworCQkJZnRkaV9jYnVzX2luaXRfZ3Bp b19kYXRhKHByaXYsIG5ncGlvKyssIGkpOworCQl9CisJfQorCisJaWYgKCFwcml2LT5jYnVzX2dw aW8ubmdwaW8pIHsKKwkJZGV2X3dhcm4oZGV2LCAiSS9PIG1vZGUgZGlzYWJsZWQgaW4gRUVQUk9N XG4iKTsKKwkJcmV0dXJuIC1FTk9ERVY7CisJfQorCisJbGFiZWwgPSBkZXZtX2thc3ByaW50Zihk ZXYsIEdGUF9LRVJORUwsICJmdGRpLWNidXMtZ3Bpby4lZCIsIHByaXYtPmlkKTsKKwlpZiAoIWxh YmVsKQorCQlyZXR1cm4gLUVOT01FTTsKKworCXByaXYtPmNidXNfZ3Bpby5sYWJlbCA9IGxhYmVs OworCXByaXYtPmNidXNfZ3Bpby5wYXJlbnQgPSBkZXY7CisJcHJpdi0+Y2J1c19ncGlvLm93bmVy ID0gVEhJU19NT0RVTEU7CisJcHJpdi0+Y2J1c19ncGlvLmJhc2UgPSAtMTsKKwlwcml2LT5jYnVz X2dwaW8uY2FuX3NsZWVwID0gdHJ1ZTsKKwlwcml2LT5jYnVzX2dwaW8uc2V0ID0gZnRkaV9jYnVz X2dwaW9fc2V0OworCXByaXYtPmNidXNfZ3Bpby5nZXQgPSBmdGRpX2NidXNfZ3Bpb19nZXQ7CisJ cHJpdi0+Y2J1c19ncGlvLmRpcmVjdGlvbl9pbnB1dCA9IGZ0ZGlfY2J1c19ncGlvX2RpcmVjdGlv bl9pbnB1dDsKKwlwcml2LT5jYnVzX2dwaW8uZGlyZWN0aW9uX291dHB1dCA9IGZ0ZGlfY2J1c19n cGlvX2RpcmVjdGlvbl9vdXRwdXQ7CisKKwluYW1lcyA9IGRldm1fa2NhbGxvYyhkZXYsIHByaXYt PmNidXNfZ3Bpby5uZ3Bpbywgc2l6ZW9mKGNoYXIgKiksCisJCQkgICAgIEdGUF9LRVJORUwpOwor CWlmICghbmFtZXMpCisJCXJldHVybiAtRU5PTUVNOworCisJZm9yIChpID0gMDsgaSA8IHByaXYt PmNidXNfZ3Bpby5uZ3BpbzsgaSsrKSB7CisJCWlmICghcHJpdi0+Y2J1c19ncGlvX25hbWVzW2ld KQorCQkJY29udGludWU7CisJCW5hbWVzW2ldID0gZGV2bV9rYXNwcmludGYoZGV2LCBHRlBfS0VS TkVMLCAiY2J1cy4lZC0lcyIsCisJCQkJCSAgcHJpdi0+aWQsIHByaXYtPmNidXNfZ3Bpb19uYW1l c1tpXSk7CisJCWlmICghbmFtZXNbaV0pCisJCQlyZXR1cm4gLUVOT01FTTsKKwl9CisKKwlwcml2 LT5jYnVzX2dwaW8ubmFtZXMgPSAoY29uc3QgY2hhciAqY29uc3QgKiluYW1lczsKKworCXJldCA9 IGRldm1fZ3Bpb2NoaXBfYWRkX2RhdGEoZGV2LCAmcHJpdi0+Y2J1c19ncGlvLCBwcml2KTsKKwlp ZiAocmV0KSB7CisJCWRldl93YXJuKGRldiwgImZhaWxlZCB0byBhZGQgQ0JVUyBncGlvY2hpcDog JWRcbiIsIHJldCk7CisJCXJldHVybiByZXQ7CisJfQorCisJZGV2X2luZm8oZGV2LCAidXNpbmcg JWQgQ0JVUyBwaW5zXG4iLCBwcml2LT5jYnVzX2dwaW8ubmdwaW8pOworCXJldHVybiAwOworfQor CisvKgorICogTVBTU0UgQ1MgYW5kIEdQSU8tTC8tSCBzdXBwb3J0CisgKi8KKyNkZWZpbmUgU0VU X0JJVFNfTE9XCTB4ODAKKyNkZWZpbmUgR0VUX0JJVFNfTE9XCTB4ODEKKyNkZWZpbmUgU0VUX0JJ VFNfSElHSAkweDgyCisjZGVmaW5lIEdFVF9CSVRTX0hJR0gJMHg4MworCitzdGF0aWMgaW50IGZ0 ZGlfbXBzc2VfZ2V0X3BvcnRfcGlucyhzdHJ1Y3QgZnQyMzJoX2ludGZfcHJpdiAqcHJpdiwgYm9v bCBsb3cpCit7CisJc3RydWN0IGRldmljZSAqZGV2ID0gJnByaXYtPmludGYtPmRldjsKKwlpbnQg cmV0LCB0b3V0ID0gMTA7CisJdTggcnhidWZbNF07CisKKwlpZiAobG93KQorCQlwcml2LT50eF9i dWZbMF0gPSBHRVRfQklUU19MT1c7CisJZWxzZQorCQlwcml2LT50eF9idWZbMF0gPSBHRVRfQklU U19ISUdIOworCisJcmV0ID0gZnRkaV93cml0ZV9kYXRhKHByaXYtPmludGYsIHByaXYtPnR4X2J1 ZiwgMSk7CisJaWYgKHJldCA8IDApIHsKKwkJZGV2X2RiZ19yYXRlbGltaXRlZChkZXYsICJXcml0 aW5nIHBvcnQgcGlucyBjbWQgZmFpbGVkOiAlZFxuIiwKKwkJCQkgICAgcmV0KTsKKwkJcmV0dXJu IHJldDsKKwl9CisKKwlyeGJ1ZlswXSA9IDA7CisJZG8geworCQl1c2xlZXBfcmFuZ2UoNTAwMCwg NTIwMCk7CisJCXJldCA9IGZ0ZGlfcmVhZF9kYXRhKHByaXYtPmludGYsIHJ4YnVmLCAxKTsKKwkJ dG91dC0tOworCQlpZiAoIXRvdXQpIHsKKwkJCWRldl9lcnIoZGV2LCAiVGltZW91dCB3aGVuIGdl dHRpbmcgcG9ydCBwaW5zXG4iKTsKKwkJCXJldHVybiAtRVRJTUVET1VUOworCQl9CisJfSB3aGls ZSAocmV0ID09IDApOworCisJaWYgKHJldCA8IDApCisJCXJldHVybiByZXQ7CisKKwlpZiAocmV0 ICE9IDEpCisJCXJldHVybiAtRUlOVkFMOworCisJaWYgKGxvdykKKwkJcHJpdi0+Z3Bpb2xfbWFz ayA9IHJ4YnVmWzBdOworCWVsc2UKKwkJcHJpdi0+Z3Bpb2hfbWFzayA9IHJ4YnVmWzBdOworCisJ cmV0dXJuIDA7Cit9CisKK3N0YXRpYyBpbnQgZnRkaV9tcHNzZV9zZXRfcG9ydF9waW5zKHN0cnVj dCBmdDIzMmhfaW50Zl9wcml2ICpwcml2LCBib29sIGxvdykKK3sKKwlzdHJ1Y3QgZGV2aWNlICpk ZXYgPSAmcHJpdi0+aW50Zi0+ZGV2OworCWludCByZXQ7CisKKwlpZiAobG93KSB7CisJCXByaXYt PnR4X2J1ZlswXSA9IFNFVF9CSVRTX0xPVzsKKwkJcHJpdi0+dHhfYnVmWzFdID0gcHJpdi0+Z3Bp b2xfbWFzazsKKwkJcHJpdi0+dHhfYnVmWzJdID0gcHJpdi0+Z3Bpb2xfZGlyOworCX0gZWxzZSB7 CisJCXByaXYtPnR4X2J1ZlswXSA9IFNFVF9CSVRTX0hJR0g7CisJCXByaXYtPnR4X2J1ZlsxXSA9 IHByaXYtPmdwaW9oX21hc2s7CisJCXByaXYtPnR4X2J1ZlsyXSA9IHByaXYtPmdwaW9oX2RpcjsK Kwl9CisKKwlyZXQgPSBmdGRpX3dyaXRlX2RhdGEocHJpdi0+aW50ZiwgcHJpdi0+dHhfYnVmLCAz KTsKKwlpZiAocmV0IDwgMCkgeworCQlkZXZfZGJnX3JhdGVsaW1pdGVkKGRldiwgIkZhaWxlZCB0 byBzZXQgR1BJTyBwaW5zOiAlZFxuIiwKKwkJCQkgICAgcmV0KTsKKwkJcmV0dXJuIHJldDsKKwl9 CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGludCBmdGRpX21wc3NlX2dwaW9fZ2V0KHN0cnVj dCBncGlvX2NoaXAgKmNoaXAsIHVuc2lnbmVkIGludCBvZmZzZXQpCit7CisJc3RydWN0IGZ0MjMy aF9pbnRmX3ByaXYgKnByaXYgPSBncGlvY2hpcF9nZXRfZGF0YShjaGlwKTsKKwlpbnQgcmV0LCB2 YWw7CisJYm9vbCBsb3c7CisKKwltdXRleF9sb2NrKCZwcml2LT5pb19tdXRleCk7CisJaWYgKCFw cml2LT5pbnRmKSB7CisJCW11dGV4X3VubG9jaygmcHJpdi0+aW9fbXV0ZXgpOworCQlyZXR1cm4g LUVOT0RFVjsKKwl9CisJbXV0ZXhfdW5sb2NrKCZwcml2LT5pb19tdXRleCk7CisKKwlkZXZfZGJn KGNoaXAtPnBhcmVudCwgIiVzOiBvZmZzZXQgJWRcbiIsIF9fZnVuY19fLCBvZmZzZXQpOworCisJ bG93ID0gb2Zmc2V0IDwgNSA/IHRydWUgOiBmYWxzZTsKKworCW11dGV4X2xvY2soJnByaXYtPm9w c19tdXRleCk7CisKKwlyZXQgPSBmdGRpX21wc3NlX2dldF9wb3J0X3BpbnMocHJpdiwgbG93KTsK KwlpZiAocmV0IDwgMCkgeworCQltdXRleF91bmxvY2soJnByaXYtPm9wc19tdXRleCk7CisJCXJl dHVybiByZXQ7CisJfQorCisJaWYgKGxvdykKKwkJdmFsID0gcHJpdi0+Z3Bpb2xfbWFzayAmIChC SVQob2Zmc2V0KSA8PCAzKTsKKwllbHNlCisJCXZhbCA9IHByaXYtPmdwaW9oX21hc2sgJiBCSVQo b2Zmc2V0IC0gNSk7CisKKwltdXRleF91bmxvY2soJnByaXYtPm9wc19tdXRleCk7CisKKwlyZXR1 cm4gISF2YWw7Cit9CisKK3N0YXRpYyB2b2lkIGZ0ZGlfbXBzc2VfZ3Bpb19zZXQoc3RydWN0IGdw aW9fY2hpcCAqY2hpcCwgdW5zaWduZWQgaW50IG9mZnNldCwKKwkJCQlpbnQgdmFsdWUpCit7CisJ c3RydWN0IGZ0MjMyaF9pbnRmX3ByaXYgKnByaXYgPSBncGlvY2hpcF9nZXRfZGF0YShjaGlwKTsK Kwlib29sIGxvdzsKKworCW11dGV4X2xvY2soJnByaXYtPmlvX211dGV4KTsKKwlpZiAoIXByaXYt PmludGYpIHsKKwkJbXV0ZXhfdW5sb2NrKCZwcml2LT5pb19tdXRleCk7CisJCXJldHVybjsKKwl9 CisJbXV0ZXhfdW5sb2NrKCZwcml2LT5pb19tdXRleCk7CisKKwlkZXZfZGJnKGNoaXAtPnBhcmVu dCwgIiVzOiBvZmZzZXQgJWQsIHZhbCAlZFxuIiwKKwkJX19mdW5jX18sIG9mZnNldCwgdmFsdWUp OworCisJbXV0ZXhfbG9jaygmcHJpdi0+b3BzX211dGV4KTsKKworCWlmIChvZmZzZXQgPCA1KSB7 CisJCWxvdyA9IHRydWU7CisJCWlmICh2YWx1ZSkKKwkJCXByaXYtPmdwaW9sX21hc2sgfD0gKEJJ VChvZmZzZXQpIDw8IDMpOworCQllbHNlCisJCQlwcml2LT5ncGlvbF9tYXNrICY9IH4oQklUKG9m ZnNldCkgPDwgMyk7CisJfSBlbHNlIHsKKwkJbG93ID0gZmFsc2U7CisJCWlmICh2YWx1ZSkKKwkJ CXByaXYtPmdwaW9oX21hc2sgfD0gQklUKG9mZnNldCAtIDUpOworCQllbHNlCisJCQlwcml2LT5n cGlvaF9tYXNrICY9IH5CSVQob2Zmc2V0IC0gNSk7CisJfQorCisJZnRkaV9tcHNzZV9zZXRfcG9y dF9waW5zKHByaXYsIGxvdyk7CisKKwltdXRleF91bmxvY2soJnByaXYtPm9wc19tdXRleCk7Cit9 CisKK3N0YXRpYyBpbnQgZnRkaV9tcHNzZV9ncGlvX2RpcmVjdGlvbl9pbnB1dChzdHJ1Y3QgZ3Bp b19jaGlwICpjaGlwLAorCQkJCQkgICB1bnNpZ25lZCBpbnQgb2Zmc2V0KQoreworCXN0cnVjdCBm dDIzMmhfaW50Zl9wcml2ICpwcml2ID0gZ3Bpb2NoaXBfZ2V0X2RhdGEoY2hpcCk7CisJYm9vbCBs b3c7CisJaW50IHJldDsKKworCW11dGV4X2xvY2soJnByaXYtPmlvX211dGV4KTsKKwlpZiAoIXBy aXYtPmludGYpIHsKKwkJbXV0ZXhfdW5sb2NrKCZwcml2LT5pb19tdXRleCk7CisJCXJldHVybiAt RU5PREVWOworCX0KKwltdXRleF91bmxvY2soJnByaXYtPmlvX211dGV4KTsKKworCWRldl9kYmco Y2hpcC0+cGFyZW50LCAiJXM6IG9mZnNldCAlZFxuIiwgX19mdW5jX18sIG9mZnNldCk7CisKKwlt dXRleF9sb2NrKCZwcml2LT5vcHNfbXV0ZXgpOworCisJaWYgKG9mZnNldCA8IDUpIHsKKwkJbG93 ID0gdHJ1ZTsKKwkJcHJpdi0+Z3Bpb2xfZGlyICY9IH4oQklUKG9mZnNldCkgPDwgMyk7CisJfSBl bHNlIHsKKwkJbG93ID0gZmFsc2U7CisJCXByaXYtPmdwaW9oX2RpciAmPSB+QklUKG9mZnNldCAt IDUpOworCX0KKworCXJldCA9IGZ0ZGlfbXBzc2Vfc2V0X3BvcnRfcGlucyhwcml2LCBsb3cpOwor CisJbXV0ZXhfdW5sb2NrKCZwcml2LT5vcHNfbXV0ZXgpOworCisJcmV0dXJuIHJldDsKK30KKwor c3RhdGljIGludCBmdGRpX21wc3NlX2dwaW9fZGlyZWN0aW9uX291dHB1dChzdHJ1Y3QgZ3Bpb19j aGlwICpjaGlwLAorCQkJCQkgICAgdW5zaWduZWQgaW50IG9mZnNldCwgaW50IHZhbHVlKQorewor CXN0cnVjdCBmdDIzMmhfaW50Zl9wcml2ICpwcml2ID0gZ3Bpb2NoaXBfZ2V0X2RhdGEoY2hpcCk7 CisJYm9vbCBsb3c7CisJaW50IHJldDsKKworCW11dGV4X2xvY2soJnByaXYtPmlvX211dGV4KTsK KwlpZiAoIXByaXYtPmludGYpIHsKKwkJbXV0ZXhfdW5sb2NrKCZwcml2LT5pb19tdXRleCk7CisJ CXJldHVybiAtRU5PREVWOworCX0KKwltdXRleF91bmxvY2soJnByaXYtPmlvX211dGV4KTsKKwor CWRldl9kYmcoY2hpcC0+cGFyZW50LCAiJXM6IG9mZnNldCAlZCwgdmFsICVkXG4iLAorCQlfX2Z1 bmNfXywgb2Zmc2V0LCB2YWx1ZSk7CisKKwltdXRleF9sb2NrKCZwcml2LT5vcHNfbXV0ZXgpOwor CisJaWYgKG9mZnNldCA8IDUpIHsKKwkJbG93ID0gdHJ1ZTsKKwkJcHJpdi0+Z3Bpb2xfZGlyIHw9 IEJJVChvZmZzZXQpIDw8IDM7CisKKwkJaWYgKHZhbHVlKQorCQkJcHJpdi0+Z3Bpb2xfbWFzayB8 PSBCSVQob2Zmc2V0KSA8PCAzOworCQllbHNlCisJCQlwcml2LT5ncGlvbF9tYXNrICY9IH4oQklU KG9mZnNldCkgPDwgMyk7CisJfSBlbHNlIHsKKwkJbG93ID0gZmFsc2U7CisJCXByaXYtPmdwaW9o X2RpciB8PSBCSVQob2Zmc2V0IC0gNSk7CisKKwkJaWYgKHZhbHVlKQorCQkJcHJpdi0+Z3Bpb2hf bWFzayB8PSBCSVQob2Zmc2V0IC0gNSk7CisJCWVsc2UKKwkJCXByaXYtPmdwaW9oX21hc2sgJj0g fkJJVChvZmZzZXQgLSA1KTsKKwl9CisKKwlyZXQgPSBmdGRpX21wc3NlX3NldF9wb3J0X3BpbnMo cHJpdiwgbG93KTsKKworCW11dGV4X3VubG9jaygmcHJpdi0+b3BzX211dGV4KTsKKworCXJldHVy biByZXQ7Cit9CisKK3N0YXRpYyBpbnQgZnRkaV9tcHNzZV9pbml0X3BpbnMoc3RydWN0IHVzYl9p bnRlcmZhY2UgKmludGYsIGJvb2wgbG93LAorCQkJCXU4IGJpdHMsIHU4IGRpcmVjdGlvbikKK3sK KwlzdHJ1Y3QgZnQyMzJoX2ludGZfcHJpdiAqcHJpdiA9IHVzYl9nZXRfaW50ZmRhdGEoaW50Zik7 CisJaW50IHJldDsKKworCW11dGV4X2xvY2soJnByaXYtPm9wc19tdXRleCk7CisKKwlpZiAobG93 KSB7CisJCXByaXYtPmdwaW9sX21hc2sgPSBiaXRzOworCQlwcml2LT5ncGlvbF9kaXIgPSBkaXJl Y3Rpb247CisJfSBlbHNlIHsKKwkJcHJpdi0+Z3Bpb2hfbWFzayA9IGJpdHM7CisJCXByaXYtPmdw aW9oX2RpciA9IGRpcmVjdGlvbjsKKwl9CisJcmV0ID0gZnRkaV9tcHNzZV9zZXRfcG9ydF9waW5z KHByaXYsIGxvdyk7CisKKwltdXRleF91bmxvY2soJnByaXYtPm9wc19tdXRleCk7CisKKwlyZXR1 cm4gcmV0OworfQorCitzdGF0aWMgaW50IGZ0ZGlfbXBzc2VfY2ZnX2J1c19waW5zKHN0cnVjdCB1 c2JfaW50ZXJmYWNlICppbnRmLAorCQkJCSAgIHU4IGRpcl9iaXRzLCB1OCB2YWx1ZV9iaXRzKQor eworCXN0cnVjdCBmdDIzMmhfaW50Zl9wcml2ICpwcml2ID0gdXNiX2dldF9pbnRmZGF0YShpbnRm KTsKKwlpbnQgcmV0OworCisJbXV0ZXhfbG9jaygmcHJpdi0+b3BzX211dGV4KTsKKworCXByaXYt PmdwaW9sX2RpciAmPSB+NzsKKwlwcml2LT5ncGlvbF9kaXIgfD0gKGRpcl9iaXRzICYgNyk7CisK Kwlwcml2LT5ncGlvbF9tYXNrICY9IH43OworCXByaXYtPmdwaW9sX21hc2sgfD0gKHZhbHVlX2Jp dHMgJiA3KTsKKworCXJldCA9IGZ0ZGlfbXBzc2Vfc2V0X3BvcnRfcGlucyhwcml2LCB0cnVlKTsK KworCW11dGV4X3VubG9jaygmcHJpdi0+b3BzX211dGV4KTsKKworCXJldHVybiByZXQ7Cit9CisK K3N0YXRpYyBpbnQgZnQyMzJoX2ludGZfYWRkX21wc3NlX2dwaW8oc3RydWN0IGZ0MjMyaF9pbnRm X3ByaXYgKnByaXYpCit7CisJc3RydWN0IGRldmljZSAqZGV2ID0gJnByaXYtPmludGYtPmRldjsK KwljaGFyICoqbmFtZXMsICpsYWJlbDsKKwlpbnQgaSwgcmV0OworCisJbGFiZWwgPSBkZXZtX2th c3ByaW50ZihkZXYsIEdGUF9LRVJORUwsICJmdGRpLW1wc3NlLWdwaW8uJWQiLCBwcml2LT5pZCk7 CisJaWYgKCFsYWJlbCkKKwkJcmV0dXJuIC1FTk9NRU07CisKKwlwcml2LT5tcHNzZV9ncGlvLmxh YmVsID0gbGFiZWw7CisJcHJpdi0+bXBzc2VfZ3Bpby5wYXJlbnQgPSBkZXY7CisJcHJpdi0+bXBz c2VfZ3Bpby5vd25lciA9IFRISVNfTU9EVUxFOworCXByaXYtPm1wc3NlX2dwaW8uYmFzZSA9IC0x OworCXByaXYtPm1wc3NlX2dwaW8ubmdwaW8gPSAxMzsKKwlwcml2LT5tcHNzZV9ncGlvLmNhbl9z bGVlcCA9IHRydWU7CisJcHJpdi0+bXBzc2VfZ3Bpby5zZXQgPSBmdGRpX21wc3NlX2dwaW9fc2V0 OworCXByaXYtPm1wc3NlX2dwaW8uZ2V0ID0gZnRkaV9tcHNzZV9ncGlvX2dldDsKKwlwcml2LT5t cHNzZV9ncGlvLmRpcmVjdGlvbl9pbnB1dCA9IGZ0ZGlfbXBzc2VfZ3Bpb19kaXJlY3Rpb25faW5w dXQ7CisJcHJpdi0+bXBzc2VfZ3Bpby5kaXJlY3Rpb25fb3V0cHV0ID0gZnRkaV9tcHNzZV9ncGlv X2RpcmVjdGlvbl9vdXRwdXQ7CisKKwluYW1lcyA9IGRldm1fa2NhbGxvYyhkZXYsIHByaXYtPm1w c3NlX2dwaW8ubmdwaW8sIHNpemVvZihjaGFyICopLAorCQkJICAgICBHRlBfS0VSTkVMKTsKKwlp ZiAoIW5hbWVzKQorCQlyZXR1cm4gLUVOT01FTTsKKworCW5hbWVzWzBdID0gZGV2bV9rYXNwcmlu dGYoZGV2LCBHRlBfS0VSTkVMLCAibXBzc2UuJWQtQ1MiLCBwcml2LT5pZCk7CisJaWYgKCFuYW1l c1swXSkKKwkJcmV0dXJuIC1FTk9NRU07CisKKwlmb3IgKGkgPSAxOyBpIDwgcHJpdi0+bXBzc2Vf Z3Bpby5uZ3BpbzsgaSsrKSB7CisJCWludCBvZmZzOworCisJCW9mZnMgPSBpIDwgNSA/IDEgOiA1 OworCQluYW1lc1tpXSA9IGRldm1fa2FzcHJpbnRmKGRldiwgR0ZQX0tFUk5FTCwKKwkJCQkJICAi bXBzc2UuJWQtR1BJTyVjJWQiLCBwcml2LT5pZCwKKwkJCQkJICBpIDwgNSA/ICdMJyA6ICdIJywg aSAtIG9mZnMpOworCQlpZiAoIW5hbWVzW2ldKQorCQkJcmV0dXJuIC1FTk9NRU07CisJfQorCisJ cHJpdi0+bXBzc2VfZ3Bpby5uYW1lcyA9IChjb25zdCBjaGFyICpjb25zdCAqKW5hbWVzOworCisJ cmV0ID0gZnRkaV9zZXRfYml0bW9kZShwcml2LT5pbnRmLCAweDAwLCBCSVRNT0RFX01QU1NFKTsK KwlpZiAocmV0IDwgMCkgeworCQlkZXZfZXJyKGRldiwgIkZhaWxlZCB0byBzZXQgTVBTU0UgbW9k ZVxuIik7CisJCXJldHVybiByZXQ7CisJfQorCisJcmV0ID0gZGV2bV9ncGlvY2hpcF9hZGRfZGF0 YShkZXYsICZwcml2LT5tcHNzZV9ncGlvLCBwcml2KTsKKwlpZiAocmV0IDwgMCkgeworCQlkZXZf ZXJyKGRldiwgIkZhaWxlZCB0byBhZGQgTVBTU0UgR1BJTyBjaGlwOiAlZFxuIiwgcmV0KTsKKwkJ cmV0dXJuIHJldDsKKwl9CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIHZvaWQgZnRkaV9sb2Nr KHN0cnVjdCB1c2JfaW50ZXJmYWNlICppbnRmKQoreworCXN0cnVjdCBmdDIzMmhfaW50Zl9wcml2 ICpwcml2ID0gdXNiX2dldF9pbnRmZGF0YShpbnRmKTsKKworCW11dGV4X2xvY2soJnByaXYtPm9w c19tdXRleCk7Cit9CisKK3N0YXRpYyB2b2lkIGZ0ZGlfdW5sb2NrKHN0cnVjdCB1c2JfaW50ZXJm YWNlICppbnRmKQoreworCXN0cnVjdCBmdDIzMmhfaW50Zl9wcml2ICpwcml2ID0gdXNiX2dldF9p bnRmZGF0YShpbnRmKTsKKworCW11dGV4X3VubG9jaygmcHJpdi0+b3BzX211dGV4KTsKK30KKwor c3RhdGljIGNvbnN0IHN0cnVjdCBmdDIzMmhfaW50Zl9vcHMgZnQyMzJoX2ludGZfb3BzID0gewor CS5jdHJsX3hmZXIgPSBmdGRpX2N0cmxfeGZlciwKKwkuYnVsa194ZmVyID0gZnRkaV9idWxrX3hm ZXIsCisJLnJlYWRfZGF0YSA9IGZ0ZGlfcmVhZF9kYXRhLAorCS53cml0ZV9kYXRhID0gZnRkaV93 cml0ZV9kYXRhLAorCS5sb2NrID0gZnRkaV9sb2NrLAorCS51bmxvY2sgPSBmdGRpX3VubG9jaywK Kwkuc2V0X2JpdG1vZGUgPSBmdGRpX3NldF9iaXRtb2RlLAorCS5zZXRfYmF1ZHJhdGUgPSBmdGRp X3NldF9iYXVkcmF0ZSwKKwkuZGlzYWJsZV9iaXRiYW5nID0gZnRkaV9kaXNhYmxlX2JpdGJhbmcs CisJLmluaXRfcGlucyA9IGZ0ZGlfbXBzc2VfaW5pdF9waW5zLAorCS5jZmdfYnVzX3BpbnMgPSBm dGRpX21wc3NlX2NmZ19idXNfcGlucywKK307CisKKy8qCisgKiBGUEdBIGNvbmZpZyBpbnRlcmZh Y2U6IEZQUCB2aWEgRlQyNDUgRklGTworICovCisjZGVmaW5lIEZQUF9JTlRGX0RFVk5BTUUJImZ0 ZGktZmlmby1mcHAtbWdyIgorCitzdGF0aWMgc3RydWN0IGRldl9pb19kZXNjX2RhdGEgZnBnYV9j ZmdfZnBwX2Rldl9pb1syXSA9IHsKKwl7ICJuY29uZmlnIiwgMCwgR1BJT19BQ1RJVkVfTE9XIH0s CisJeyAiY29uZl9kb25lIiwgMSwgR1BJT19BQ1RJVkVfSElHSCB9LAorfTsKKworc3RhdGljIGNv bnN0IHN0cnVjdCBmaWZvX2ZwcF9tZ3JfcGxhdGZvcm1fZGF0YSBmcGdhX2NmZ19mcHBfcGxhdF9k YXRhID0geworCS5vcHMgPSAmZnQyMzJoX2ludGZfb3BzLAorCS5pb19kYXRhID0gZnBnYV9jZmdf ZnBwX2Rldl9pbywKKwkuaW9fZGF0YV9sZW4gPSBBUlJBWV9TSVpFKGZwZ2FfY2ZnX2ZwcF9kZXZf aW8pLAorCS5uY29uZmlnX251bSA9IDgsCisJLmNvbmZfZG9uZV9udW0gPSA5LAorfTsKKworc3Rh dGljIGludCBmdDIzMmhfaW50Zl9mcHBfcHJvYmUoc3RydWN0IHVzYl9pbnRlcmZhY2UgKmludGYs CisJCQkJIGNvbnN0IHZvaWQgKnBsYXRfZGF0YSkKK3sKKwlzdHJ1Y3QgZnQyMzJoX2ludGZfcHJp diAqcHJpdiA9IHVzYl9nZXRfaW50ZmRhdGEoaW50Zik7CisJY29uc3Qgc3RydWN0IGZpZm9fZnBw X21ncl9wbGF0Zm9ybV9kYXRhICpwZCA9IHBsYXRfZGF0YTsKKwlzdHJ1Y3QgZGV2aWNlICpkZXYg PSAmaW50Zi0+ZGV2OworCXN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXY7CisJc3RydWN0IGdw aW9kX2xvb2t1cF90YWJsZSAqbG9va3VwOworCWNoYXIgKmNmZ2RvbmUsICpuY2ZnLCAqcHRyOwor CXNpemVfdCBsb29rdXBfc2l6ZTsKKwlpbnQgaSwgcmV0LCBncGlvcyA9IDA7CisKKwlkZXZfZGJn KGRldiwgIiVzOiBwbGF0X2RhdGEgJXBcbiIsIF9fZnVuY19fLCBwZCk7CisJaWYgKCFwZCkgewor CQlkZXZfZXJyKGRldiwgIiVzOiBNaXNzaW5nIHBsYXRmb3JtIGRhdGFcbiIsIF9fZnVuY19fKTsK KwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCisJcmV0ID0gZnQyMzJoX2ludGZfYWRkX2NidXNfZ3Bp byhwcml2KTsKKwlpZiAocmV0IDwgMCkKKwkJcmV0dXJuIHJldDsKKworCWxvb2t1cF9zaXplID0g c2l6ZW9mKCpsb29rdXApICsgMyAqIHNpemVvZihzdHJ1Y3QgZ3Bpb2RfbG9va3VwKTsKKwlsb29r dXAgPSBkZXZtX2t6YWxsb2MoZGV2LCBsb29rdXBfc2l6ZSwgR0ZQX0tFUk5FTCk7CisJaWYgKCFs b29rdXApCisJCXJldHVybiAtRU5PTUVNOworCisJbG9va3VwLT5kZXZfaWQgPSBkZXZtX2thc3By aW50ZihkZXYsIEdGUF9LRVJORUwsICIlcy4lZCIsCisJCQkJCUZQUF9JTlRGX0RFVk5BTUUsIHBy aXYtPmlkKTsKKwlpZiAoIWxvb2t1cC0+ZGV2X2lkKQorCQlyZXR1cm4gLUVOT01FTTsKKworCW5j ZmcgPSBkZXZtX2thc3ByaW50ZihkZXYsIEdGUF9LRVJORUwsICJBQ0JVUyVkIiwgcGQtPm5jb25m aWdfbnVtKTsKKwlpZiAoIW5jZmcpCisJCXJldHVybiAtRU5PTUVNOworCisJY2ZnZG9uZSA9IGRl dm1fa2FzcHJpbnRmKGRldiwgR0ZQX0tFUk5FTCwgIkFDQlVTJWQiLCBwZC0+Y29uZl9kb25lX251 bSk7CisJaWYgKCFjZmdkb25lKQorCQlyZXR1cm4gLUVOT01FTTsKKworCWZvciAoaSA9IDA7IGkg PCBwcml2LT5jYnVzX2dwaW8ubmdwaW87IGkrKykgeworCQlpZiAoIXByaXYtPmNidXNfZ3Bpby5u YW1lc1tpXSkKKwkJCWNvbnRpbnVlOworCisJCXB0ciA9IHN0cnN0cihwcml2LT5jYnVzX2dwaW8u bmFtZXNbaV0sICJBQ0JVUyIpOworCQlpZiAoIXB0cikKKwkJCWNvbnRpbnVlOworCisJCWlmICgh c3RybmNtcChwdHIsIG5jZmcsIDYpKSB7CisJCQlsb29rdXAtPnRhYmxlWzBdLmNoaXBfaHdudW0g PSBpOworCQkJZ3Bpb3MrKzsKKwkJCWNvbnRpbnVlOworCQl9CisJCWlmICghc3RybmNtcChwdHIs IGNmZ2RvbmUsIDYpKSB7CisJCQlsb29rdXAtPnRhYmxlWzFdLmNoaXBfaHdudW0gPSBpOworCQkJ Z3Bpb3MrKzsKKwkJfQorCX0KKworCS8qIERvZXMgR1BJTyBjb250cm9sbGVyIHByb3ZpZGUgYWxs IG5lZWRlZCBBQ0JVUyBwaW5zPyAqLworCWlmIChncGlvcyA8IDIpIHsKKwkJZGV2X2VycihkZXYs ICJNaXNzaW5nIGNvbnRyb2wgR1BJT3NcbiIpOworCQlyZXR1cm4gLUVOT0RFVjsKKwl9CisKKwlm b3IgKGkgPSAwOyBpIDwgcGQtPmlvX2RhdGFfbGVuOyBpKyspIHsKKwkJbG9va3VwLT50YWJsZVtp XS5jaGlwX2xhYmVsID0gcHJpdi0+Y2J1c19ncGlvLmxhYmVsOworCQlsb29rdXAtPnRhYmxlW2ld LmlkeCA9IDA7CisJCWxvb2t1cC0+dGFibGVbaV0uY29uX2lkID0gcGQtPmlvX2RhdGFbaV0uY29u X2lkOworCQlsb29rdXAtPnRhYmxlW2ldLmZsYWdzID0gcGQtPmlvX2RhdGFbaV0uZmxhZ3M7CisJ fQorCisJcHJpdi0+bG9va3VwX2ZpZm8gPSBsb29rdXA7CisJZ3Bpb2RfYWRkX2xvb2t1cF90YWJs ZShwcml2LT5sb29rdXBfZmlmbyk7CisKKwlwZGV2ID0gcGxhdGZvcm1fZGV2aWNlX3JlZ2lzdGVy X2RhdGEoZGV2LCBGUFBfSU5URl9ERVZOQU1FLAorCQkJCQkgICAgIHByaXYtPmlkLCBwZCwgc2l6 ZW9mKCpwZCkpOworCWlmIChJU19FUlIocGRldikpIHsKKwkJZ3Bpb2RfcmVtb3ZlX2xvb2t1cF90 YWJsZShwcml2LT5sb29rdXBfZmlmbyk7CisJCXJldHVybiBQVFJfRVJSKHBkZXYpOworCX0KKwor CXByaXYtPmZpZm9fcGRldiA9IHBkZXY7CisKKwlkZXZfZGJnKGRldiwgIiVzOiBmaWZvIHBkZXYg JXBcbiIsIF9fZnVuY19fLCBwZGV2KTsKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGludCBmdDIz MmhfaW50Zl9mcHBfcmVtb3ZlKHN0cnVjdCB1c2JfaW50ZXJmYWNlICppbnRmKQoreworCXN0cnVj dCBmdDIzMmhfaW50Zl9wcml2ICpwcml2ID0gdXNiX2dldF9pbnRmZGF0YShpbnRmKTsKKwlzdHJ1 Y3QgZGV2aWNlICpkZXYgPSAmaW50Zi0+ZGV2OworCisJZGV2X2RiZyhkZXYsICIlc1xuIiwgX19m dW5jX18pOworCXBsYXRmb3JtX2RldmljZV91bnJlZ2lzdGVyKHByaXYtPmZpZm9fcGRldik7CisJ Z3Bpb2RfcmVtb3ZlX2xvb2t1cF90YWJsZShwcml2LT5sb29rdXBfZmlmbyk7CisJcmV0dXJuIDA7 Cit9CisKKy8qCisgKiBGUEdBIGNvbmZpZyBpbnRlcmZhY2U6IFBTLVNQSSB2aWEgTVBTU0UKKyAq LworI2RlZmluZSBTUElfSU5URl9ERVZOQU1FCSJmdGRpLW1wc3NlLXNwaSIKKworc3RhdGljIHN0 cnVjdCBzcGlfYm9hcmRfaW5mbyBmcGdhX2NmZ19zcGlfaW5mb1tdID0geworCXsKKwkubW9kYWxp YXMJPSAiZnBnYS1wYXNzaXZlLXNlcmlhbCIsCisJLm1vZGUJCT0gU1BJX01PREVfMCB8IFNQSV9M U0JfRklSU1QsCisJLm1heF9zcGVlZF9oegk9IDMwMDAwMDAwLAorCS5idXNfbnVtCT0gMCwKKwku Y2hpcF9zZWxlY3QJPSAwLAorCX0sCit9OworCitzdGF0aWMgc3RydWN0IGRldl9pb19kZXNjX2Rh dGEgZnBnYV9jZmdfc3BpX2Rldl9pb1szXSA9IHsKKwl7ICJjb25mZCIsIDEsIEdQSU9fQUNUSVZF X0hJR0ggfSwKKwl7ICJuc3RhdCIsIDIsIEdQSU9fQUNUSVZFX0xPVyB9LAorCXsgIm5jb25maWci LCAzLCBHUElPX0FDVElWRV9MT1cgfSwKK307CisKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgbXBzc2Vf c3BpX3BsYXRmb3JtX2RhdGEgZnBnYV9jZmdfc3BpX3BsYXRfZGF0YSA9IHsKKwkub3BzCQk9ICZm dDIzMmhfaW50Zl9vcHMsCisJLnNwaV9pbmZvCT0gZnBnYV9jZmdfc3BpX2luZm8sCisJLnNwaV9p bmZvX2xlbgk9IEFSUkFZX1NJWkUoZnBnYV9jZmdfc3BpX2luZm8pLAorCS5pb19kYXRhCT0gZnBn YV9jZmdfc3BpX2Rldl9pbywKKwkuaW9fZGF0YV9sZW4JPSBBUlJBWV9TSVpFKGZwZ2FfY2ZnX3Nw aV9kZXZfaW8pLAorfTsKKworc3RhdGljIHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKm1wc3NlX2Rl dl9yZWdpc3RlcihzdHJ1Y3QgZnQyMzJoX2ludGZfcHJpdiAqcHJpdiwKKwkJCQljb25zdCBzdHJ1 Y3QgbXBzc2Vfc3BpX3BsYXRmb3JtX2RhdGEgKnBkKQoreworCXN0cnVjdCBkZXZpY2UgKnBhcmVu dCA9ICZwcml2LT5pbnRmLT5kZXY7CisJc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldjsKKwlz dHJ1Y3QgZ3Bpb2RfbG9va3VwX3RhYmxlICpsb29rdXA7CisJc2l6ZV90IGxvb2t1cF9zaXplLCB0 Ymxfc2l6ZTsKKwlpbnQgaSwgcmV0OworCisJcGRldiA9IHBsYXRmb3JtX2RldmljZV9hbGxvYyhT UElfSU5URl9ERVZOQU1FLCAwKTsKKwlpZiAoIXBkZXYpCisJCXJldHVybiBOVUxMOworCisJcGRl di0+ZGV2LnBhcmVudCA9IHBhcmVudDsKKwlwZGV2LT5kZXYuZndub2RlID0gTlVMTDsKKwlwcml2 LT5zcGlfcGRldiA9IHBkZXY7CisKKwl0Ymxfc2l6ZSA9IHBkLT5zcGlfaW5mb19sZW4gKyAxOwor CWxvb2t1cF9zaXplID0gc2l6ZW9mKCpsb29rdXApICsgdGJsX3NpemUgKiBzaXplb2Yoc3RydWN0 IGdwaW9kX2xvb2t1cCk7CisJbG9va3VwID0gZGV2bV9remFsbG9jKHBhcmVudCwgbG9va3VwX3Np emUsIEdGUF9LRVJORUwpOworCWlmICghbG9va3VwKSB7CisJCXJldCA9IC1FTk9NRU07CisJCWdv dG8gZXJyOworCX0KKworCWZvciAoaSA9IDA7IGkgPCBwZC0+c3BpX2luZm9fbGVuOyBpKyspIHsK KwkJZGV2X2RiZyhwYXJlbnQsICJJTkZPOiAlcyBjcyAlZFxuIiwKKwkJCXBkLT5zcGlfaW5mb1tp XS5tb2RhbGlhcywgcGQtPnNwaV9pbmZvW2ldLmNoaXBfc2VsZWN0KTsKKwl9CisKKwlyZXQgPSBw bGF0Zm9ybV9kZXZpY2VfYWRkX2RhdGEocGRldiwgcGQsIHNpemVvZigqcGQpKTsKKwlpZiAocmV0 KQorCQlnb3RvIGVycjsKKworCXBkZXYtPmlkID0gcHJpdi0+aWQ7CisKKwlyZXQgPSBmdDIzMmhf aW50Zl9hZGRfbXBzc2VfZ3Bpbyhwcml2KTsKKwlpZiAocmV0IDwgMCkKKwkJZ290byBlcnI7CisK Kwlsb29rdXAtPmRldl9pZCA9IGRldm1fa2FzcHJpbnRmKHBhcmVudCwgR0ZQX0tFUk5FTCwgIiVz LiVkIiwKKwkJCQkJcGRldi0+bmFtZSwgcGRldi0+aWQpOworCWlmICghbG9va3VwLT5kZXZfaWQp IHsKKwkJcmV0ID0gLUVOT01FTTsKKwkJZ290byBlcnI7CisJfQorCisJZm9yIChpID0gMDsgaSA8 IHBkLT5zcGlfaW5mb19sZW47IGkrKykgeworCQlsb29rdXAtPnRhYmxlW2ldLmNoaXBfbGFiZWwg PSBwcml2LT5tcHNzZV9ncGlvLmxhYmVsOworCQlsb29rdXAtPnRhYmxlW2ldLmNoaXBfaHdudW0g PSBwZC0+c3BpX2luZm9baV0uY2hpcF9zZWxlY3Q7CisJCWxvb2t1cC0+dGFibGVbaV0uaWR4ID0g aTsKKwkJbG9va3VwLT50YWJsZVtpXS5jb25faWQgPSBOVUxMOworCQlpZiAocGQtPnNwaV9pbmZv W2ldLm1vZGUgJiBTUElfQ1NfSElHSCkKKwkJCWxvb2t1cC0+dGFibGVbaV0uZmxhZ3MgPSBHUElP X0FDVElWRV9ISUdIOworCQllbHNlCisJCQlsb29rdXAtPnRhYmxlW2ldLmZsYWdzID0gR1BJT19B Q1RJVkVfTE9XOworCX0KKworCXByaXYtPmxvb2t1cF9jcyA9IGxvb2t1cDsKKwlncGlvZF9hZGRf bG9va3VwX3RhYmxlKHByaXYtPmxvb2t1cF9jcyk7CisKKwlyZXQgPSBwbGF0Zm9ybV9kZXZpY2Vf YWRkKHBkZXYpOworCWlmIChyZXQgPCAwKQorCQlnb3RvIGVycl9hZGQ7CisKKwlkZXZfZGJnKCZw ZGV2LT5kZXYsICIlcyBkb25lXG4iLCBfX2Z1bmNfXyk7CisJcmV0dXJuIHBkZXY7CisKK2Vycl9h ZGQ6CisJZ3Bpb2RfcmVtb3ZlX2xvb2t1cF90YWJsZShwcml2LT5sb29rdXBfY3MpOworZXJyOgor CXBsYXRmb3JtX2RldmljZV9wdXQocGRldik7CisJcmV0dXJuIEVSUl9QVFIocmV0KTsKK30KKwor c3RhdGljIGludCBmdDIzMmhfaW50Zl9zcGlfcHJvYmUoc3RydWN0IHVzYl9pbnRlcmZhY2UgKmlu dGYsCisJCQkJIGNvbnN0IHZvaWQgKnBsYXRfZGF0YSkKK3sKKwlzdHJ1Y3QgZnQyMzJoX2ludGZf cHJpdiAqcHJpdiA9IHVzYl9nZXRfaW50ZmRhdGEoaW50Zik7CisJc3RydWN0IGRldmljZSAqZGV2 ID0gJmludGYtPmRldjsKKwlzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2OworCisJcGRldiA9 IG1wc3NlX2Rldl9yZWdpc3Rlcihwcml2LCBwbGF0X2RhdGEpOworCWlmIChJU19FUlIocGRldikp IHsKKwkJZGV2X2VycihkZXYsICIlczogQ2FuJ3QgY3JlYXRlIE1QU1NFIFNQSSBkZXZpY2UgJWxk XG4iLAorCQkJX19mdW5jX18sIFBUUl9FUlIocGRldikpOworCQlyZXR1cm4gUFRSX0VSUihwZGV2 KTsKKwl9CisKKwlwcml2LT5zcGlfcGRldiA9IHBkZXY7CisJcmV0dXJuIDA7Cit9CisKK3N0YXRp YyBpbnQgZnQyMzJoX2ludGZfc3BpX3JlbW92ZShzdHJ1Y3QgdXNiX2ludGVyZmFjZSAqaW50ZikK K3sKKwlzdHJ1Y3QgZnQyMzJoX2ludGZfcHJpdiAqcHJpdiA9IHVzYl9nZXRfaW50ZmRhdGEoaW50 Zik7CisJc3RydWN0IGRldmljZSAqZGV2ID0gJmludGYtPmRldjsKKworCWRldl9kYmcoZGV2LCAi JXM6IHNwaSBwZGV2ICVwXG4iLCBfX2Z1bmNfXywgcHJpdi0+c3BpX3BkZXYpOworCWdwaW9kX3Jl bW92ZV9sb29rdXBfdGFibGUocHJpdi0+bG9va3VwX2NzKTsKKwlwbGF0Zm9ybV9kZXZpY2VfdW5y ZWdpc3Rlcihwcml2LT5zcGlfcGRldik7CisJcmV0dXJuIDA7Cit9CisKK3N0YXRpYyBjb25zdCBz dHJ1Y3QgZnQyMzJoX2ludGZfaW5mbyBmcGdhX2NmZ19zcGlfaW50Zl9pbmZvID0geworCS5wcm9i ZSAgPSBmdDIzMmhfaW50Zl9zcGlfcHJvYmUsCisJLnJlbW92ZSAgPSBmdDIzMmhfaW50Zl9zcGlf cmVtb3ZlLAorCS5wbGF0X2RhdGEgID0gJmZwZ2FfY2ZnX3NwaV9wbGF0X2RhdGEsCit9OworCitz dGF0aWMgY29uc3Qgc3RydWN0IGZ0MjMyaF9pbnRmX2luZm8gZnBnYV9jZmdfZmlmb19pbnRmX2lu Zm8gPSB7CisJLnByb2JlID0gZnQyMzJoX2ludGZfZnBwX3Byb2JlLAorCS5yZW1vdmUgPSBmdDIz MmhfaW50Zl9mcHBfcmVtb3ZlLAorCS5wbGF0X2RhdGEgPSAmZnBnYV9jZmdfZnBwX3BsYXRfZGF0 YSwKK307CisKK3N0YXRpYyBpbnQgZnQyMzJoX2ludGZfcHJvYmUoc3RydWN0IHVzYl9pbnRlcmZh Y2UgKmludGYsCisJCQkgICAgIGNvbnN0IHN0cnVjdCB1c2JfZGV2aWNlX2lkICppZCkKK3sKKwlz dHJ1Y3QgZnQyMzJoX2ludGZfcHJpdiAqcHJpdjsKKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSAmaW50 Zi0+ZGV2OworCXN0cnVjdCB1c2JfaG9zdF9pbnRlcmZhY2UgKmlmYWNlX2Rlc2M7CisJc3RydWN0 IHVzYl9lbmRwb2ludF9kZXNjcmlwdG9yICplbmRwb2ludDsKKwljb25zdCBzdHJ1Y3QgZnQyMzJo X2ludGZfaW5mbyAqaW5mbzsKKwl1bnNpZ25lZCBpbnQgaTsKKwlpbnQgcmV0ID0gMDsKKworCXBy aXYgPSBkZXZtX2t6YWxsb2MoZGV2LCBzaXplb2YoKnByaXYpLCBHRlBfS0VSTkVMKTsKKwlpZiAo IXByaXYpCisJCXJldHVybiAtRU5PTUVNOworCisJaWZhY2VfZGVzYyA9IGludGYtPmN1cl9hbHRz ZXR0aW5nOworCisJZm9yIChpID0gMDsgaSA8IGlmYWNlX2Rlc2MtPmRlc2MuYk51bUVuZHBvaW50 czsgaSsrKSB7CisJCWVuZHBvaW50ID0gJmlmYWNlX2Rlc2MtPmVuZHBvaW50W2ldLmRlc2M7CisK KwkJaWYgKHVzYl9lbmRwb2ludF9pc19idWxrX291dChlbmRwb2ludCkpCisJCQlwcml2LT5idWxr X291dCA9IGVuZHBvaW50LT5iRW5kcG9pbnRBZGRyZXNzOworCisJCWlmICh1c2JfZW5kcG9pbnRf aXNfYnVsa19pbihlbmRwb2ludCkpIHsKKwkJCXByaXYtPmJ1bGtfaW4gPSBlbmRwb2ludC0+YkVu ZHBvaW50QWRkcmVzczsKKwkJCXByaXYtPmJ1bGtfaW5fc3ogPSB1c2JfZW5kcG9pbnRfbWF4cChl bmRwb2ludCk7CisJCX0KKwl9CisKKwlwcml2LT51c2JfZGV2X2lkID0gaWQ7CisJcHJpdi0+aW5k ZXggPSAxOworCXByaXYtPmludGYgPSBpbnRmOworCXByaXYtPmluZm8gPSAoc3RydWN0IGZ0MjMy aF9pbnRmX2luZm8gKilpZC0+ZHJpdmVyX2luZm87CisKKwlpbmZvID0gcHJpdi0+aW5mbzsKKwlp ZiAoIWluZm8pIHsKKwkJZGV2X2VycihkZXYsICJNaXNzaW5nIGRldmljZSBzcGVjaWZpYyBkcml2 ZXIgaW5mby4uLlxuIik7CisJCXJldHVybiAtRU5PREVWOworCX0KKworCW11dGV4X2luaXQoJnBy aXYtPmlvX211dGV4KTsKKwltdXRleF9pbml0KCZwcml2LT5vcHNfbXV0ZXgpOworCXVzYl9zZXRf aW50ZmRhdGEoaW50ZiwgcHJpdik7CisKKwlwcml2LT5idWxrX2luX2J1ZiA9IGRldm1fa21hbGxv YyhkZXYsIHByaXYtPmJ1bGtfaW5fc3osIEdGUF9LRVJORUwpOworCWlmICghcHJpdi0+YnVsa19p bl9idWYpCisJCXJldHVybiAtRU5PTUVNOworCisJcHJpdi0+dWRldiA9IHVzYl9nZXRfZGV2KGlu dGVyZmFjZV90b191c2JkZXYoaW50ZikpOworCisJcHJpdi0+aWQgPSBpZGFfc2ltcGxlX2dldCgm ZnRkaV9kZXZpZF9pZGEsIDAsIDAsIEdGUF9LRVJORUwpOworCWlmIChwcml2LT5pZCA8IDApCisJ CXJldHVybiBwcml2LT5pZDsKKworCWlmIChpbmZvLT5wcm9iZSkgeworCQlyZXQgPSBpbmZvLT5w cm9iZShpbnRmLCBpbmZvLT5wbGF0X2RhdGEpOworCQlpZiAocmV0IDwgMCkKKwkJCWdvdG8gZXJy OworCQlyZXR1cm4gMDsKKwl9CisKKwkvKiBmb3Igc2ltcGxlIEdQSU8tb25seSBkZXZpY2VzICov CisJcmV0ID0gLUVOT0RFVjsKKwlpZiAoaW5mby0+dXNlX2NidXNfZ3Bpb19jdHJsKQorCQlyZXQg PSBmdDIzMmhfaW50Zl9hZGRfY2J1c19ncGlvKHByaXYpOworCWVsc2UgaWYgKGluZm8tPnVzZV9t cHNzZV9ncGlvX2N0cmwpCisJCXJldCA9IGZ0MjMyaF9pbnRmX2FkZF9tcHNzZV9ncGlvKHByaXYp OworCWlmICghcmV0KQorCQlyZXR1cm4gMDsKK2VycjoKKwlpZGFfc2ltcGxlX3JlbW92ZSgmZnRk aV9kZXZpZF9pZGEsIHByaXYtPmlkKTsKKwlyZXR1cm4gcmV0OworfQorCitzdGF0aWMgdm9pZCBm dDIzMmhfaW50Zl9kaXNjb25uZWN0KHN0cnVjdCB1c2JfaW50ZXJmYWNlICppbnRmKQoreworCXN0 cnVjdCBmdDIzMmhfaW50Zl9wcml2ICpwcml2ID0gdXNiX2dldF9pbnRmZGF0YShpbnRmKTsKKwlj b25zdCBzdHJ1Y3QgZnQyMzJoX2ludGZfaW5mbyAqaW5mbzsKKworCWluZm8gPSAoc3RydWN0IGZ0 MjMyaF9pbnRmX2luZm8gKilwcml2LT51c2JfZGV2X2lkLT5kcml2ZXJfaW5mbzsKKwlpZiAoaW5m byAmJiBpbmZvLT5yZW1vdmUpCisJCWluZm8tPnJlbW92ZShpbnRmKTsKKworCWlmIChpbmZvLT51 c2VfbXBzc2VfZ3Bpb19jdHJsKQorCQlkZXZtX2dwaW9jaGlwX3JlbW92ZSgmaW50Zi0+ZGV2LCAm cHJpdi0+bXBzc2VfZ3Bpbyk7CisKKwlpZiAoaW5mby0+dXNlX2NidXNfZ3Bpb19jdHJsKQorCQlk ZXZtX2dwaW9jaGlwX3JlbW92ZSgmaW50Zi0+ZGV2LCAmcHJpdi0+Y2J1c19ncGlvKTsKKworCW11 dGV4X2xvY2soJnByaXYtPmlvX211dGV4KTsKKwlwcml2LT5pbnRmID0gTlVMTDsKKwl1c2Jfc2V0 X2ludGZkYXRhKGludGYsIE5VTEwpOworCW11dGV4X3VubG9jaygmcHJpdi0+aW9fbXV0ZXgpOwor CisJdXNiX3B1dF9kZXYocHJpdi0+dWRldik7CisJaWRhX3NpbXBsZV9yZW1vdmUoJmZ0ZGlfZGV2 aWRfaWRhLCBwcml2LT5pZCk7Cit9CisKKyNkZWZpbmUgRlRESV9WSUQJCQkweDA0MDMKKyNkZWZp bmUgQVJSSV9GUFBfSU5URl9QUk9EVUNUX0lECTB4NzE0OAorI2RlZmluZSBBUlJJX1NQSV9JTlRG X1BST0RVQ1RfSUQJMHg3MTQ5CisKK3N0YXRpYyBzdHJ1Y3QgdXNiX2RldmljZV9pZCBmdDIzMmhf aW50Zl90YWJsZVtdID0geworCXsgVVNCX0RFVklDRShGVERJX1ZJRCwgQVJSSV9GUFBfSU5URl9Q Uk9EVUNUX0lEKSwKKwkJLmRyaXZlcl9pbmZvID0gKGtlcm5lbF91bG9uZ190KSZmcGdhX2NmZ19m aWZvX2ludGZfaW5mbyB9LAorCXsgVVNCX0RFVklDRShGVERJX1ZJRCwgQVJSSV9TUElfSU5URl9Q Uk9EVUNUX0lEKSwKKwkJLmRyaXZlcl9pbmZvID0gKGtlcm5lbF91bG9uZ190KSZmcGdhX2NmZ19z cGlfaW50Zl9pbmZvIH0sCisJe30KK307CitNT0RVTEVfREVWSUNFX1RBQkxFKHVzYiwgZnQyMzJo X2ludGZfdGFibGUpOworCitzdGF0aWMgc3RydWN0IHVzYl9kcml2ZXIgZnQyMzJoX2ludGZfZHJp dmVyID0geworCS5uYW1lCQk9IEtCVUlMRF9NT0ROQU1FLAorCS5pZF90YWJsZQk9IGZ0MjMyaF9p bnRmX3RhYmxlLAorCS5wcm9iZQkJPSBmdDIzMmhfaW50Zl9wcm9iZSwKKwkuZGlzY29ubmVjdAk9 IGZ0MjMyaF9pbnRmX2Rpc2Nvbm5lY3QsCit9OworCittb2R1bGVfdXNiX2RyaXZlcihmdDIzMmhf aW50Zl9kcml2ZXIpOworCitNT0RVTEVfQUxJQVMoImZ0MjMyaC1pbnRmIik7CitNT0RVTEVfQVVU SE9SKCJBbmF0b2xpaiBHdXN0c2NoaW4gPGFndXN0QGRlbnguZGU+Iik7CitNT0RVTEVfREVTQ1JJ UFRJT04oIkZUMjMySCB0byBGUEdBIGludGVyZmFjZSBkcml2ZXIiKTsKK01PRFVMRV9MSUNFTlNF KCJHUEwgdjIiKTsKZGlmZiAtLWdpdCBhL2luY2x1ZGUvbGludXgvdXNiL2Z0MjMyaC1pbnRmLmgg Yi9pbmNsdWRlL2xpbnV4L3VzYi9mdDIzMmgtaW50Zi5oCm5ldyBmaWxlIG1vZGUgMTAwNjQ0Cmlu ZGV4IDAwMDAwMDAwMDAwMC4uZjgzZmFlMDUwOTY4Ci0tLSAvZGV2L251bGwKKysrIGIvaW5jbHVk ZS9saW51eC91c2IvZnQyMzJoLWludGYuaApAQCAtMCwwICsxLDE4NyBAQAorLyogU1BEWC1MaWNl bnNlLUlkZW50aWZpZXI6IEdQTC0yLjAgKi8KKy8qCisgKiBDb21tb24gZGVmaW5pdGlvbnMgZm9y IEZUREkgRlQyMzJIIGludGVyZmFjZSBkZXZpY2UKKyAqCisgKiBDb3B5cmlnaHQgKEMpIDIwMTcg LSAyMDE4IERFTlggU29mdHdhcmUgRW5naW5lZXJpbmcKKyAqIEFuYXRvbGlqIEd1c3RzY2hpbiA8 YWd1c3RAZGVueC5kZT4KKyAqLworCisjaWZuZGVmIF9fTElOVVhfRlQyMzJIX0lOVEZfSAorI2Rl ZmluZSBfX0xJTlVYX0ZUMjMySF9JTlRGX0gKKworLyogVXNlZCBGVERJIFVTQiBSZXF1ZXN0cyAq LworI2RlZmluZSBGVERJX1NJT19SRVNFVF9SRVFVRVNUCQkweDAwCisjZGVmaW5lIEZURElfU0lP X1NFVF9CQVVEUkFURV9SRVFVRVNUCTB4MDMKKyNkZWZpbmUgRlRESV9TSU9fU0VUX0JJVE1PREVf UkVRVUVTVAkweDBCCisjZGVmaW5lIEZURElfU0lPX1JFQURfUElOU19SRVFVRVNUCTB4MEMKKyNk ZWZpbmUgRlRESV9TSU9fUkVBRF9FRVBST01fUkVRVUVTVAkweDkwCisKKy8qIE1QU1NFIENvbW1h bmRzICovCisjZGVmaW5lIFRYX0JZVEVTX1JFX01TQgkJMHgxMCAvKiB0eCBvbiArdmUgY2xrIChy aXNpbmcgZWRnZSkgKi8KKyNkZWZpbmUgVFhfQllURVNfRkVfTVNCCQkweDExIC8qIHR4IG9uIC12 ZSBjbGsgKGZhbGxpbmcgZWRnZSkgKi8KKyNkZWZpbmUgUlhfQllURVNfUkVfTVNCCQkweDIwCisj ZGVmaW5lIFJYX0JZVEVTX0ZFX01TQgkJMHgyNAorI2RlZmluZSBUWEZfUlhSX0JZVEVTX01TQgkw eDMxIC8qIHR4IG9uIC12ZSBjbGssIHJ4IG9uICt2ZSAqLworI2RlZmluZSBUWFJfUlhGX0JZVEVT X01TQgkweDM0IC8qIHR4IG9uICt2ZSBjbGssIHJ4IG9uIC12ZSAqLworCisjZGVmaW5lIFRYX0JZ VEVTX1JFX0xTQgkJMHgxOCAvKiB0eCBvbiArdmUgY2xrICovCisjZGVmaW5lIFRYX0JZVEVTX0ZF X0xTQgkJMHgxOSAvKiB0eCBvbiAtdmUgY2xrICovCisjZGVmaW5lIFJYX0JZVEVTX1JFX0xTQgkJ MHgyOAorI2RlZmluZSBSWF9CWVRFU19GRV9MU0IJCTB4MkMKKyNkZWZpbmUgVFhGX1JYUl9CWVRF U19MU0IJMHgzOSAvKiB0eCBvbiAtdmUgY2xrLCByeCBvbiArdmUgKi8KKyNkZWZpbmUgVFhSX1JY Rl9CWVRFU19MU0IJMHgzQyAvKiB0eCBvbiArdmUgY2xrLCByeCBvbiAtdmUgKi8KKworI2RlZmlu ZSBMT09QQkFDS19PTgkJMHg4NAorI2RlZmluZSBMT09QQkFDS19PRkYJCTB4ODUKKyNkZWZpbmUg VENLX0RJVklTT1IJCTB4ODYKKyNkZWZpbmUgRElTX0RJVl81CQkweDhBCisjZGVmaW5lIEVOX0RJ Vl81CQkweDhCCisjZGVmaW5lIEVOXzNfUEhBU0UJCTB4OEMKKyNkZWZpbmUgRElTXzNfUEhBU0UJ CTB4OEQKKyNkZWZpbmUgRElTX0FEQVBUSVZFCQkweDk3CisKKy8qIEZvciBFRVBST00gSS9PIG1v ZGUgKi8KKyNkZWZpbmUgRlRESV9NQVhfRUVQUk9NX1NJWkUJMjU2CisjZGVmaW5lIEZURElfMjMy SF9DQlVTX0lPTU9ERQkweDA4CisKKyNkZWZpbmUgRlRESV9VU0JfUkVBRF9USU1FT1VUCTUwMDAK KyNkZWZpbmUgRlRESV9VU0JfV1JJVEVfVElNRU9VVAk1MDAwCisKKy8qIE1QU1NFIGJpdGJhbmcg bW9kZXMgKGNvcGllZCBmcm9tIGxpYmZ0ZGkpICovCitlbnVtIGZ0ZGlfbXBzc2VfbW9kZSB7CisJ QklUTU9ERV9SRVNFVAk9IDB4MDAsCS8qIHN3aXRjaCBvZmYgYml0YmFuZyBtb2RlICovCisJQklU TU9ERV9CSVRCQU5HCT0gMHgwMSwJLyogYXN5bmNocm9ub3VzIGJpdGJhbmcgbW9kZSAqLworCUJJ VE1PREVfTVBTU0UJPSAweDAyLAkvKiBNUFNTRSBtb2RlLCBvbiAyMjMyeCBjaGlwcyAqLworCUJJ VE1PREVfU1lOQ0JCCT0gMHgwNCwJLyogc3luY2hyb25vdXMgYml0YmFuZyBtb2RlICAqLworCUJJ VE1PREVfTUNVCT0gMHgwOCwJLyogTUNVIEhvc3QgQnVzIEVtdWxhdGlvbiBtb2RlICovCisJCQkJ LyogQ1BVLXN0eWxlIGZpZm8gbW9kZSBnZXRzIHNldCB2aWEgRUVQUk9NICovCisJQklUTU9ERV9P UFRPCT0gMHgxMCwJLyogRmFzdCBPcHRvLUlzb2xhdGVkIFNlcmlhbCBJbnRlcmZhY2UgTW9kZSAq LworCUJJVE1PREVfQ0JVUwk9IDB4MjAsCS8qIEJpdGJhbmcgb24gQ0JVUyBwaW5zLCBFRVBST00g Y29uZmlnIG5lZWRlZCAqLworCUJJVE1PREVfU1lOQ0ZGCT0gMHg0MCwJLyogU2luZ2xlIENoYW5u ZWwgU3luY2hyb25vdXMgRklGTyBtb2RlICovCisJQklUTU9ERV9GVDEyODQJPSAweDgwLAkvKiBG VDEyODQgbW9kZSwgYXZhaWxhYmxlIG9uIDIzMkggY2hpcHMgKi8KK307CisKK3N0cnVjdCBjdHJs X2Rlc2MgeworCXVuc2lnbmVkIGludCBkaXJfb3V0OworCXU4IHJlcXVlc3Q7CisJdTggcmVxdWVz dHR5cGU7CisJdTE2IHZhbHVlOworCXUxNiBpbmRleDsKKwl1MTYgc2l6ZTsKKwl2b2lkICpkYXRh OworCWludCB0aW1lb3V0OworfTsKKworc3RydWN0IGJ1bGtfZGVzYyB7CisJdW5zaWduZWQgaW50 IGRpcl9vdXQ7CisJdm9pZCAqZGF0YTsKKwlpbnQgbGVuOworCWludCBhY3RfbGVuOworCWludCB0 aW1lb3V0OworfTsKKworLyoKKyAqIHN0cnVjdCBmdDIzMmhfaW50Zl9vcHMgLSBGVDIzMkggaW50 ZXJmYWNlIG9wZXJhdGlvbnMgZm9yIHVwcGVyIGRyaXZlcnMKKyAqCisgKiBAYnVsa194ZmVyOiBG VERJIFVTQiBidWxrIHRyYW5zZmVyCisgKiBAY3RybF94ZmVyOiBGVERJIFVTQiBjb250cm9sIHRy YW5zZmVyCisgKiBAcmVhZF9kYXRhOiByZWFkICdsZW4nIGJ5dGVzIGZyb20gRlRESSBkZXZpY2Ug dG8gdGhlIGdpdmVuIGJ1ZmZlcgorICogQHdyaXRlX2RhdGE6IHdyaXRlICdsZW4nIGJ5dGVzIGZy b20gdGhlIGdpdmVuIGJ1ZmZlciB0byB0aGUgRlRESSBkZXZpY2UKKyAqIEBsb2NrOiBsb2NrIHRo ZSBpbnRlcmZhY2UgZm9yIGFuIG9wZXJhdGlvbiBzZXF1ZW5jZS4gVXNlZCB3aGVuIG11bHRpcGxl CisgKgkgIGNvbW1hbmQgYW5kL29yIGRhdGEgb3BlcmF0aW9ucyBtdXN0IGJlIGV4ZWN1dGVkIGlu IGEgc3BlY2lmaWMgb3JkZXIKKyAqCSAgKHdoZW4gb3RoZXIgaW50ZXJtZWRpYXRlIGNvbW1hbmQv ZGF0YSB0cmFuc2ZlcnMgbWF5IG5vdCBpbnRlcmZlcmUpCisgKiBAdW5sb2NrOiB1bmxvY2sgdGhl IHByZXZpb3VzbHkgbG9ja2VkIGludGVyZmFjZQorICogQHNldF9iaXRtb2RlOiBjb25maWd1cmUg RlRESSBiaXQgbW9kZQorICogQHNldF9iYXVkcmF0ZTogY29uZmlndXJlIEZUREkgYmF1ZHJhdGUK KyAqIEBkaXNhYmxlX2JpdGJhbmc6IHR1cm4gb2ZmIGJpdGJhbmcgbW9kZQorICogQGluaXRfcGlu czogaW5pdGlhbGl6ZSBHUElPTC9HUElPSCBwb3J0IHBpbnMgaW4gTVBTU0UgbW9kZQorICogQGNm Z19idXNfcGluczogY29uZmlndXJlIE1QU1NFIFNQSSBidXMgcGlucworICoKKyAqIENvbW1vbiBG VDIzMkggaW50ZXJmYWNlIFVTQiB4ZmVyIGFuZCBkZXZpY2UgY29uZmlndXJhdGlvbiBvcGVyYXRp b25zIHVzZWQKKyAqIGluIEZJRk8tRlBQLCBNUFNTRS1TUEkgb3IgTVBTU0UtSTJDIGRyaXZlcnMu IE1hbnkgb2YgdGhlbSBhcmUgbGlrZSBGVERJCisgKiBwcm90b2NvbCBmdW5jdGlvbnMsIHdoaWNo IEkgbWFpbmx5IGJvcnJvd2VkIGZyb20gbGliZnRkaQorICovCitzdHJ1Y3QgZnQyMzJoX2ludGZf b3BzIHsKKwlpbnQgKCpidWxrX3hmZXIpKHN0cnVjdCB1c2JfaW50ZXJmYWNlICppbnRmLCBzdHJ1 Y3QgYnVsa19kZXNjICpkZXNjKTsKKwlpbnQgKCpjdHJsX3hmZXIpKHN0cnVjdCB1c2JfaW50ZXJm YWNlICppbnRmLCBzdHJ1Y3QgY3RybF9kZXNjICpkZXNjKTsKKwlpbnQgKCpyZWFkX2RhdGEpKHN0 cnVjdCB1c2JfaW50ZXJmYWNlICppbnRmLCB2b2lkICpidWYsIHNpemVfdCBsZW4pOworCWludCAo KndyaXRlX2RhdGEpKHN0cnVjdCB1c2JfaW50ZXJmYWNlICppbnRmLCBjb25zdCBjaGFyICpidWYs CisJCQkgIHNpemVfdCBsZW4pOworCXZvaWQgKCpsb2NrKShzdHJ1Y3QgdXNiX2ludGVyZmFjZSAq aW50Zik7CisJdm9pZCAoKnVubG9jaykoc3RydWN0IHVzYl9pbnRlcmZhY2UgKmludGYpOworCWlu dCAoKnNldF9iaXRtb2RlKShzdHJ1Y3QgdXNiX2ludGVyZmFjZSAqaW50ZiwgdW5zaWduZWQgY2hh ciBiaXRtYXNrLAorCQkJICAgdW5zaWduZWQgY2hhciBtb2RlKTsKKwlpbnQgKCpzZXRfYmF1ZHJh dGUpKHN0cnVjdCB1c2JfaW50ZXJmYWNlICppbnRmLCBpbnQgYmF1ZHJhdGUpOworCWludCAoKmRp c2FibGVfYml0YmFuZykoc3RydWN0IHVzYl9pbnRlcmZhY2UgKmludGYpOworCWludCAoKmluaXRf cGlucykoc3RydWN0IHVzYl9pbnRlcmZhY2UgKmludGYsIGJvb2wgbG93LCB1OCBiaXRzLCB1OCBk aXIpOworCWludCAoKmNmZ19idXNfcGlucykoc3RydWN0IHVzYl9pbnRlcmZhY2UgKmludGYsIHU4 IGRpcl9iaXRzLAorCQkJICAgIHU4IHZhbHVlX2JpdHMpOworfTsKKworLyoKKyAqIHN0cnVjdCBk ZXZfaW9fZGVzY19kYXRhIC0gRGVzY3JpcHRvciBvZiBGVDIzMkggcGluIHVzZWQgYnkgYXR0YWNo ZWQgZGV2aWNlCisgKiBAY29uX2lkOiBOYW1lIG9mIHRoZSBHUElPIHBpbgorICogQGlkeDogSW5k ZXggb2YgdGhlIHBpbgorICogQGZsYWdzOiBHUElPRCBmbGFncyBvZiB0aGUgcGluCisgKgorICog RGVzY3JpcHRpb24gb2YgYSBHUElPIHVzZWQgYnkgZGV2aWNlIGNvbm5lY3RlZCB0byBGVDIzMkgK KyAqLworc3RydWN0IGRldl9pb19kZXNjX2RhdGEgeworCWNvbnN0IGNoYXIgKmNvbl9pZDsKKwl1 bnNpZ25lZCBpbnQgaWR4OworCXVuc2lnbmVkIGludCBmbGFnczsKK307CisKKy8qCisgKiBzdHJ1 Y3QgZmlmb19mcHBfbWdyX3BsYXRmb3JtX2RhdGEgLSBGSUZPL0ZQUCBkZXZpY2UgcGxhdGZvcm0g ZGF0YQorICogQG9wczogVVNCIGludGVyZmFjZSBvcGVyYXRpb25zIHVzZWQgaW4gRlBQIG1hbmFn ZXIgZHJpdmVyCisgKiBAaW9fZGF0YTogQXJyYXkgd2l0aCBkZXNjcmlwdG9ycyBvZiB1c2VkIEkv TyBwaW5zCisgKiBAaW9fZGF0YV9sZW46IExlbmd0aCBvZiBpb19kYXRhIGFycmF5CisgKiBAbmNv bmZpZ19udW06IEFDQlVTIHBpbiBudW1iZXIgb2YgdGhlIE5DT05GSUcgcGluCisgKiBAY29uZl9k b25lX251bTogQUNCVVMgcGluIG51bWJlciBvZiB0aGUgQ09ORl9ET05FIHBpbgorICoKKyAqIEZJ Rk8vRlBQIGZwZ2EgbWFuYWdlciBzcGVjaWZpYyBwbGF0Zm9ybSBkYXRhCisgKi8KK3N0cnVjdCBm aWZvX2ZwcF9tZ3JfcGxhdGZvcm1fZGF0YSB7CisJY29uc3Qgc3RydWN0IGZ0MjMyaF9pbnRmX29w cyAqb3BzOworCXN0cnVjdCBkZXZfaW9fZGVzY19kYXRhICppb19kYXRhOworCXNpemVfdCBpb19k YXRhX2xlbjsKKwlpbnQgbmNvbmZpZ19udW07CisJaW50IGNvbmZfZG9uZV9udW07Cit9OworCisv KgorICogc3RydWN0IG1wc3NlX3NwaV9wbGF0Zm9ybV9kYXRhIC0gTVBTU0UgU1BJIGJ1cyBwbGF0 Zm9ybSBkYXRhCisgKiBAb3BzOiBVU0IgaW50ZXJmYWNlIG9wZXJhdGlvbnMgdXNlZCBpbiBNUFNT RSBTUEkgY29udHJvbGxlciBkcml2ZXIKKyAqIEBzcGlfaW5mbzogQXJyYXkgd2l0aCBzcGlfYm9h cmRfaW5mbyBzdHJ1Y3R1cmVzIG9mIGF0dGFjaGVkIFNQSSBzbGF2ZXMKKyAqIEBzcGlfaW5mb19s ZW46IExlbmd0aCBvZiBzcGlfaW5mbyBhcnJheQorICogQGlvX2RhdGE6IEFycmF5IHdpdGggZGVz Y3JpcHRvcnMgb2YgdXNlZCBJL08gcGlucworICogQGlvX2RhdGFfbGVuOiBMZW5ndGggb2YgaW9f ZGF0YSBhcnJheQorICoKKyAqIE1QU1NFIFNQSSBzcGVjaWZpYyBwbGF0Zm9ybSBkYXRhIGRlc2Ny aWJpbmcgYXR0YWNoZWQgU1BJIHNsYXZlcyBhbmQKKyAqIHRoZWlyIGFkZGl0aW9uYWwgSS9PIHBp bnMKKyAqLworc3RydWN0IG1wc3NlX3NwaV9wbGF0Zm9ybV9kYXRhIHsKKwljb25zdCBzdHJ1Y3Qg ZnQyMzJoX2ludGZfb3BzICpvcHM7CisJc3RydWN0IHNwaV9ib2FyZF9pbmZvICpzcGlfaW5mbzsK KwlzaXplX3Qgc3BpX2luZm9fbGVuOworCXN0cnVjdCBkZXZfaW9fZGVzY19kYXRhICppb19kYXRh OworCXNpemVfdCBpb19kYXRhX2xlbjsKK307CisKKy8qCisgKiBWYWx1ZSBISUdILiByYXRlIGlz IDEyMDAwMDAwIC8gKCgxICsgdmFsdWUpICogMikKKyAqLworc3RhdGljIGlubGluZSBpbnQgZGl2 X3ZhbHVlKGludCByYXRlKQoreworCWludCByOworCisJaWYgKHJhdGUgPj0gNjAwMDAwMCkKKwkJ cmV0dXJuIDA7CisJciA9IDYwMDAwMDAgLyByYXRlIC0gMTsKKwlpZiAociA8IDB4ZmZmZikKKwkJ cmV0dXJuIHI7CisJcmV0dXJuIDB4ZmZmZjsKK30KKworI2VuZGlmIC8qIF9fTElOVVhfRlQyMzJI X0lOVEZfSCAqLwo=