From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6B2F0C6FA82 for ; Thu, 22 Sep 2022 13:49:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231883AbiIVNtg (ORCPT ); Thu, 22 Sep 2022 09:49:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54016 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231641AbiIVNtI (ORCPT ); Thu, 22 Sep 2022 09:49:08 -0400 Received: from metis.ext.pengutronix.de (metis.ext.pengutronix.de [IPv6:2001:67c:670:201:290:27ff:fe1d:cc33]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E80BEDF3BC for ; Thu, 22 Sep 2022 06:49:04 -0700 (PDT) Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1obMZM-0008Ea-Fc; Thu, 22 Sep 2022 15:48:48 +0200 Received: from [2a0a:edc0:0:1101:1d::28] (helo=dude02.red.stw.pengutronix.de) by drehscheibe.grey.stw.pengutronix.de with esmtp (Exim 4.94.2) (envelope-from ) id 1obMZM-002GUi-76; Thu, 22 Sep 2022 15:48:46 +0200 Received: from mfe by dude02.red.stw.pengutronix.de with local (Exim 4.94.2) (envelope-from ) id 1obMZJ-00D4Dl-G4; Thu, 22 Sep 2022 15:48:45 +0200 From: Marco Felsch To: mchehab@kernel.org, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, kishon@ti.com, vkoul@kernel.org, laurent.pinchart@ideasonboard.com, sakari.ailus@linux.intel.com, jacopo@jmondi.org, hverkuil@xs4all.nl Cc: linux-phy@lists.infradead.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-media@vger.kernel.org, kernel@pengutronix.de Subject: [PATCH v3 4/4] media: tc358746: add Toshiba TC358746 Parallel to CSI-2 bridge driver Date: Thu, 22 Sep 2022 15:48:43 +0200 Message-Id: <20220922134843.3108267-5-m.felsch@pengutronix.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220922134843.3108267-1-m.felsch@pengutronix.de> References: <20220922134843.3108267-1-m.felsch@pengutronix.de> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-SA-Exim-Connect-IP: 2a0a:edc0:0:c01:1d::a2 X-SA-Exim-Mail-From: mfe@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-kernel@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Adding support for the TC358746 parallel <-> MIPI CSI bridge. This chip supports two operating modes: 1st) parallel-in -> mipi-csi out 2nd) mipi-csi in -> parallel out This patch only adds the support for the 1st mode. Signed-off-by: Marco Felsch --- Changelog: v3: - added missing static - drop s/MHZ/HZ_PER_MHZ/ - kconfig: add "depends on PM" - Add tc358746_valid_reg() for regmap. - tc358746_set_fmt: fix format negotiation for pad == SOURCE - tc358746_write/read: add error messages - replace udelay with fsleep() - tc358746_apply_misc_config: const mbusfmt - tc358746_s_stream: fix comment about LP-00/11 state change - tc358746_link_validate: s/sensor/source/ - tc358746_link_validate: s/pclk_rate/link_freq/ - tc358746_link_validate: fix v4l2_subdev_unlock_state() - tc358746_link_validate: adapt fifo-sz comment - tc358746_g/s_register: use pm_runtime_get_if_in_use - tc358746_setup_mclk_provider: move to clk related location - tc358746_init_hw: fix error case - tc358746_init_controls: add comment - tc358746_notify_bound: add MEDIA_LNK_FL_IMMUTABLE - tc358746_async_register: fix error path - tc358746_async_register: put sd.fwnode on error and remove - tc358746_probe: increase autosuspend to 1s v2: - use the correct CID_LINK_FREQ control to query the sensor_pclk_rate - remove now not needed tc358746_link_setup() and struct v4l2_ctrl sensor_pclk_ctrl - call v4l2_subdev_link_validate_default() during link validation - remove MEDIA_BUS_FMT_GBR888_1X24/YUV444 format support - use subdev active_state API - replace own .get_fmt with v4l2_subdev_get_fmt - remove unnecessary pad checks - restructure tc358746_get_format_by_code() if-case - move apply_dphy_config|apply_misc_config from resume intos s_stream - use goto in s_stream enable case - fix error handling in suspend/resume - split probe() into more sub-functions --- drivers/media/i2c/Kconfig | 17 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/tc358746.c | 1692 ++++++++++++++++++++++++++++++++++ 3 files changed, 1710 insertions(+) create mode 100644 drivers/media/i2c/tc358746.c diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 7806d4b81716..f85cdb94c524 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -1272,6 +1272,23 @@ config VIDEO_TC358743_CEC When selected the tc358743 will support the optional HDMI CEC feature. +config VIDEO_TC358746 + tristate "Toshiba TC358746 parallel-CSI2 bridge" + depends on VIDEO_DEV && PM && I2C + select VIDEO_V4L2_SUBDEV_API + select MEDIA_CONTROLLER + select V4L2_FWNODE + select GENERIC_PHY_MIPI_DPHY + select REGMAP_I2C + select COMMON_CLK + help + Support for the Toshiba TC358746 parallel to MIPI CSI-2 bridge. + The bridge can work in both directions but currently only the + parallel-in / csi-out path is supported. + + To compile this driver as a module, choose M here: the + module will be called tc358746. + config VIDEO_TVP514X tristate "Texas Instruments TVP514x video decoder" depends on VIDEO_DEV && I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 0a2933103dd9..d1096c2ab480 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -118,6 +118,7 @@ obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o obj-$(CONFIG_VIDEO_TC358743) += tc358743.o +obj-$(CONFIG_VIDEO_TC358746) += tc358746.o obj-$(CONFIG_VIDEO_TDA1997X) += tda1997x.o obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c new file mode 100644 index 000000000000..0dcd5e0e0855 --- /dev/null +++ b/drivers/media/i2c/tc358746.c @@ -0,0 +1,1692 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * TC358746 - Parallel <-> CSI-2 Bridge + * + * Copyright 2022 Marco Felsch + * + * Notes: + * - Currently only 'Parallel-in -> CSI-out' mode is supported! + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 16-bit registers */ +#define CHIPID_REG 0x0000 +#define CHIPID GENMASK(15, 8) + +#define SYSCTL_REG 0x0002 +#define SRESET BIT(0) + +#define CONFCTL_REG 0x0004 +#define PDATAF_MASK GENMASK(9, 8) +#define PDATAF_MODE0 0 +#define PDATAF_MODE1 1 +#define PDATAF_MODE2 2 +#define PDATAF(val) FIELD_PREP(PDATAF_MASK, (val)) +#define PPEN BIT(6) +#define DATALANE_MASK GENMASK(1, 0) + +#define FIFOCTL_REG 0x0006 +#define DATAFMT_REG 0x0008 +#define PDFMT(val) FIELD_PREP(GENMASK(7, 4), (val)) + +#define MCLKCTL_REG 0x000c +#define MCLK_HIGH_MASK GENMASK(15, 8) +#define MCLK_LOW_MASK GENMASK(7, 0) +#define MCLK_HIGH(val) FIELD_PREP(MCLK_HIGH_MASK, (val)) +#define MCLK_LOW(val) FIELD_PREP(MCLK_LOW_MASK, (val)) + +#define PLLCTL0_REG 0x0016 +#define PLL_PRD_MASK GENMASK(15, 12) +#define PLL_PRD(val) FIELD_PREP(PLL_PRD_MASK, (val)) +#define PLL_FBD_MASK GENMASK(8, 0) +#define PLL_FBD(val) FIELD_PREP(PLL_FBD_MASK, (val)) + +#define PLLCTL1_REG 0x0018 +#define PLL_FRS_MASK GENMASK(11, 10) +#define PLL_FRS(val) FIELD_PREP(PLL_FRS_MASK, (val)) +#define CKEN BIT(4) +#define RESETB BIT(1) +#define PLL_EN BIT(0) + +#define CLKCTL_REG 0x0020 +#define MCLKDIV_MASK GENMASK(3, 2) +#define MCLKDIV(val) FIELD_PREP(MCLKDIV_MASK, (val)) +#define MCLKDIV_8 0 +#define MCLKDIV_4 1 +#define MCLKDIV_2 2 + +#define WORDCNT_REG 0x0022 +#define PP_MISC_REG 0x0032 +#define FRMSTOP BIT(15) +#define RSTPTR BIT(14) + +/* 32-bit registers */ +#define CLW_DPHYCONTTX_REG 0x0100 +#define CLW_CNTRL_REG 0x0140 +#define D0W_CNTRL_REG 0x0144 +#define LANEDISABLE BIT(0) + +#define STARTCNTRL_REG 0x0204 +#define START BIT(0) + +#define LINEINITCNT_REG 0x0210 +#define LPTXTIMECNT_REG 0x0214 +#define TCLK_HEADERCNT_REG 0x0218 +#define TCLK_ZEROCNT(val) FIELD_PREP(GENMASK(15, 8), (val)) +#define TCLK_PREPARECNT(val) FIELD_PREP(GENMASK(6, 0), (val)) + +#define TCLK_TRAILCNT_REG 0x021C +#define THS_HEADERCNT_REG 0x0220 +#define THS_ZEROCNT(val) FIELD_PREP(GENMASK(14, 8), (val)) +#define THS_PREPARECNT(val) FIELD_PREP(GENMASK(6, 0), (val)) + +#define TWAKEUP_REG 0x0224 +#define TCLK_POSTCNT_REG 0x0228 +#define THS_TRAILCNT_REG 0x022C +#define HSTXVREGEN_REG 0x0234 +#define TXOPTIONCNTRL_REG 0x0238 +#define CSI_CONTROL_REG 0x040C +#define CSI_MODE BIT(15) +#define TXHSMD BIT(7) +#define NOL(val) FIELD_PREP(GENMASK(2, 1), (val)) + +#define CSI_CONFW_REG 0x0500 +#define MODE(val) FIELD_PREP(GENMASK(31, 29), (val)) +#define MODE_SET 0x5 +#define ADDRESS(val) FIELD_PREP(GENMASK(28, 24), (val)) +#define CSI_CONTROL_ADDRESS 0x3 +#define DATA(val) FIELD_PREP(GENMASK(15, 0), (val)) + +#define CSI_START_REG 0x0518 +#define STRT BIT(0) + +static const struct v4l2_mbus_framefmt tc358746_def_fmt = { + .width = 640, + .height = 480, + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_DEFAULT, + .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT, + .quantization = V4L2_QUANTIZATION_DEFAULT, + .xfer_func = V4L2_XFER_FUNC_DEFAULT, +}; + +static const char * const tc358746_supplies[] = { + "vddc", "vddio", "vddmipi" +}; + +enum { + TC358746_SINK, + TC358746_SOURCE, + TC358746_NR_PADS +}; + +struct tc358746 { + struct v4l2_subdev sd; + struct media_pad pads[TC358746_NR_PADS]; + struct v4l2_async_notifier notifier; + struct v4l2_fwnode_endpoint csi_vep; + + struct v4l2_ctrl_handler ctrl_hdl; + + struct regmap *regmap; + struct clk *refclk; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[ARRAY_SIZE(tc358746_supplies)]; + + struct clk_hw mclk_hw; + unsigned long mclk_rate; + u8 mclk_prediv; + u16 mclk_postdiv; + + unsigned long pll_rate; + u8 pll_post_div; + u16 pll_pre_div; + u16 pll_mul; + +#define TC358746_VB_MAX_SIZE (511 * 32) +#define TC358746_VB_DEFAULT_SIZE (1 * 32) + unsigned int vb_size; /* Video buffer size in bits */ + + struct phy_configure_opts_mipi_dphy dphy_cfg; +}; + +static inline struct tc358746 *to_tc358746(struct v4l2_subdev *sd) +{ + return container_of(sd, struct tc358746, sd); +} + +static inline struct tc358746 *clk_hw_to_tc358746(struct clk_hw *hw) +{ + return container_of(hw, struct tc358746, mclk_hw); +} + +struct tc358746_format { + u32 code; + bool csi_format; + unsigned char bus_width; + unsigned char bpp; + /* Register values */ + u8 pdformat; /* Peripheral Data Format */ + u8 pdataf; /* Parallel Data Format Option */ +}; + +enum { + PDFORMAT_RAW8 = 0, + PDFORMAT_RAW10, + PDFORMAT_RAW12, + PDFORMAT_RGB888, + PDFORMAT_RGB666, + PDFORMAT_RGB565, + PDFORMAT_YUV422_8BIT, + /* RESERVED = 7 */ + PDFORMAT_RAW14 = 8, + PDFORMAT_YUV422_10BIT, + PDFORMAT_YUV444, +}; + +/* Check tc358746_src_mbus_code() if you add new formats */ +static const struct tc358746_format tc358746_formats[] = { + { + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .bus_width = 8, + .bpp = 16, + .pdformat = PDFORMAT_YUV422_8BIT, + .pdataf = PDATAF_MODE0, + }, { + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .csi_format = true, + .bus_width = 16, + .bpp = 16, + .pdformat = PDFORMAT_YUV422_8BIT, + .pdataf = PDATAF_MODE1, + }, { + .code = MEDIA_BUS_FMT_YUYV8_1X16, + .csi_format = true, + .bus_width = 16, + .bpp = 16, + .pdformat = PDFORMAT_YUV422_8BIT, + .pdataf = PDATAF_MODE2, + }, { + .code = MEDIA_BUS_FMT_UYVY10_2X10, + .bus_width = 10, + .bpp = 20, + .pdformat = PDFORMAT_YUV422_10BIT, + .pdataf = PDATAF_MODE0, /* don't care */ + } +}; + +/* Get n-th format for pad */ +static const struct tc358746_format * +tc358746_get_format_by_idx(unsigned int pad, unsigned int index) +{ + unsigned int idx = 0; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(tc358746_formats); i++) { + const struct tc358746_format *fmt = &tc358746_formats[i]; + + if ((pad == TC358746_SOURCE && fmt->csi_format) || + (pad == TC358746_SINK)) { + if (idx == index) + return fmt; + idx++; + } + } + + return ERR_PTR(-EINVAL); +} + +static const struct tc358746_format * +tc358746_get_format_by_code(unsigned int pad, u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(tc358746_formats); i++) { + const struct tc358746_format *fmt = &tc358746_formats[i]; + + if (pad == TC358746_SINK && fmt->code == code) + return fmt; + + if (pad == TC358746_SOURCE && !fmt->csi_format) + continue; + + if (fmt->code == code) + return fmt; + } + + return ERR_PTR(-EINVAL); +} + +static u32 tc358746_src_mbus_code(u32 code) +{ + switch (code) { + case MEDIA_BUS_FMT_UYVY8_2X8: + return MEDIA_BUS_FMT_UYVY8_1X16; + case MEDIA_BUS_FMT_UYVY10_2X10: + return MEDIA_BUS_FMT_UYVY10_1X20; + default: + return code; + } +} + +static bool tc358746_valid_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CHIPID_REG ... CSI_START_REG: + return true; + default: + return false; + } +} + +static const struct regmap_config tc358746_regmap_config = { + .name = "tc358746", + .reg_bits = 16, + .val_bits = 16, + .max_register = CSI_START_REG, + .writeable_reg = tc358746_valid_reg, + .readable_reg = tc358746_valid_reg, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, +}; + +static int tc358746_write(struct tc358746 *tc358746, u32 reg, u32 val) +{ + size_t count; + int err; + + /* 32-bit registers starting from CLW_DPHYCONTTX */ + count = reg < CLW_DPHYCONTTX_REG ? 1 : 2; + + err = regmap_bulk_write(tc358746->regmap, reg, &val, count); + if (err) + dev_dbg(tc358746->sd.dev, + "Failed to write reg:0x%04x val:0x%04x\n", reg, val); + + return err; +} + +static int tc358746_read(struct tc358746 *tc358746, u32 reg, u32 *val) +{ + size_t count; + int err; + + /* 32-bit registers starting from CLW_DPHYCONTTX */ + count = reg < CLW_DPHYCONTTX_REG ? 1 : 2; + *val = 0; + + err = regmap_bulk_read(tc358746->regmap, reg, val, count); + if (err) + dev_dbg(tc358746->sd.dev, "Failed to read reg:0x%04x\n", reg); + + return err; +} + +static int +tc358746_update_bits(struct tc358746 *tc358746, u32 reg, u32 mask, u32 val) +{ + u32 tmp, orig; + int err; + + err = tc358746_read(tc358746, reg, &orig); + if (err) + return err; + + tmp = orig & ~mask; + tmp |= val & mask; + + return tc358746_write(tc358746, reg, tmp); +} + +static int tc358746_set_bits(struct tc358746 *tc358746, u32 reg, u32 bits) +{ + return tc358746_update_bits(tc358746, reg, bits, bits); +} + +static int tc358746_clear_bits(struct tc358746 *tc358746, u32 reg, u32 bits) +{ + return tc358746_update_bits(tc358746, reg, bits, 0); +} + +static int tc358746_sw_reset(struct tc358746 *tc358746) +{ + int err; + + err = tc358746_set_bits(tc358746, SYSCTL_REG, SRESET); + if (err) + return err; + + fsleep(10); + + return tc358746_clear_bits(tc358746, SYSCTL_REG, SRESET); +} + +static int +tc358746_apply_pll_config(struct tc358746 *tc358746) +{ + u8 post = tc358746->pll_post_div; + u16 pre = tc358746->pll_pre_div; + u16 mul = tc358746->pll_mul; + u32 val, mask; + int err; + + err = tc358746_read(tc358746, PLLCTL1_REG, &val); + if (err) + return err; + + /* Don't touch the PLL if running */ + if (FIELD_GET(PLL_EN, val) == 1) + return 0; + + /* Pre-div and Multiplicator have a internal +1 logic */ + val = PLL_PRD(pre - 1) | PLL_FBD(mul - 1); + mask = PLL_PRD_MASK | PLL_FBD_MASK; + err = tc358746_update_bits(tc358746, PLLCTL0_REG, mask, val); + if (err) + return err; + + val = PLL_FRS(ilog2(post)) | RESETB | PLL_EN; + mask = PLL_FRS_MASK | RESETB | PLL_EN; + tc358746_update_bits(tc358746, PLLCTL1_REG, mask, val); + if (err) + return err; + + fsleep(1000); + + return tc358746_set_bits(tc358746, PLLCTL1_REG, CKEN); +} + +static int tc358746_apply_misc_config(struct tc358746 *tc358746) +{ + const struct v4l2_mbus_framefmt *mbusfmt; + struct v4l2_subdev *sd = &tc358746->sd; + struct v4l2_subdev_state *sink_state; + const struct tc358746_format *fmt; + struct device *dev = sd->dev; + u32 val; + int err; + + sink_state = v4l2_subdev_lock_and_get_active_state(sd); + mbusfmt = v4l2_subdev_get_pad_format(sd, sink_state, TC358746_SINK); + v4l2_subdev_unlock_state(sink_state); + + fmt = tc358746_get_format_by_code(TC358746_SINK, mbusfmt->code); + + /* Self defined CSI user data type id's are not supported yet */ + val = PDFMT(fmt->pdformat); + dev_dbg(dev, "DATAFMT: 0x%x\n", val); + err = tc358746_write(tc358746, DATAFMT_REG, val); + if (err) + return err; + + val = PDATAF(fmt->pdataf); + dev_dbg(dev, "CONFCTL[PDATAF]: 0x%x\n", fmt->pdataf); + err = tc358746_update_bits(tc358746, CONFCTL_REG, PDATAF_MASK, val); + if (err) + return err; + + val = tc358746->vb_size / 32; + dev_dbg(dev, "FIFOCTL: %u (0x%x)\n", val, val); + err = tc358746_write(tc358746, FIFOCTL_REG, val); + if (err) + return err; + + /* Total number of bytes for each line/width */ + val = mbusfmt->width * fmt->bpp / 8; + dev_dbg(dev, "WORDCNT: %u (0x%x)\n", val, val); + return tc358746_write(tc358746, WORDCNT_REG, val); +} + +/* Use MHz as base so the div needs no u64 */ +static u32 tc358746_cfg_to_cnt(unsigned int cfg_val, + unsigned int clk_mhz, + unsigned int time_base) +{ + return DIV_ROUND_UP(cfg_val * clk_mhz, time_base); +} + +static u32 tc358746_ps_to_cnt(unsigned int cfg_val, + unsigned int clk_mhz) +{ + return tc358746_cfg_to_cnt(cfg_val, clk_mhz, USEC_PER_SEC); +} + +static u32 tc358746_us_to_cnt(unsigned int cfg_val, + unsigned int clk_mhz) +{ + return tc358746_cfg_to_cnt(cfg_val, clk_mhz, 1); +} + +static int tc358746_apply_dphy_config(struct tc358746 *tc358746) +{ + struct phy_configure_opts_mipi_dphy *cfg = &tc358746->dphy_cfg; + bool non_cont_clk = !!(tc358746->csi_vep.bus.mipi_csi2.flags & + V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK); + struct device *dev = tc358746->sd.dev; + unsigned long hs_byte_clk, hf_clk; + u32 val, val2, lptxcnt; + int err; + + /* The hs_byte_clk is also called SYSCLK in the excel sheet */ + hs_byte_clk = cfg->hs_clk_rate / 8; + hs_byte_clk /= HZ_PER_MHZ; + hf_clk = hs_byte_clk / 2; + + val = tc358746_us_to_cnt(cfg->init, hf_clk) - 1; + dev_dbg(dev, "LINEINITCNT: %u (0x%x)\n", val, val); + err = tc358746_write(tc358746, LINEINITCNT_REG, val); + if (err) + return err; + + val = tc358746_ps_to_cnt(cfg->lpx, hs_byte_clk) - 1; + lptxcnt = val; + dev_dbg(dev, "LPTXTIMECNT: %u (0x%x)\n", val, val); + err = tc358746_write(tc358746, LPTXTIMECNT_REG, val); + if (err) + return err; + + val = tc358746_ps_to_cnt(cfg->clk_prepare, hs_byte_clk) - 1; + val2 = tc358746_ps_to_cnt(cfg->clk_zero, hs_byte_clk) - 1; + dev_dbg(dev, "TCLK_PREPARECNT: %u (0x%x)\n", val, val); + dev_dbg(dev, "TCLK_ZEROCNT: %u (0x%x)\n", val2, val2); + dev_dbg(dev, "TCLK_HEADERCNT: 0x%x\n", + (u32)(TCLK_PREPARECNT(val) | TCLK_ZEROCNT(val2))); + err = tc358746_write(tc358746, TCLK_HEADERCNT_REG, + TCLK_PREPARECNT(val) | TCLK_ZEROCNT(val2)); + if (err) + return err; + + val = tc358746_ps_to_cnt(cfg->clk_trail, hs_byte_clk); + dev_dbg(dev, "TCLK_TRAILCNT: %u (0x%x)\n", val, val); + err = tc358746_write(tc358746, TCLK_TRAILCNT_REG, val); + if (err) + return err; + + val = tc358746_ps_to_cnt(cfg->hs_prepare, hs_byte_clk) - 1; + val2 = tc358746_ps_to_cnt(cfg->hs_zero, hs_byte_clk) - 1; + dev_dbg(dev, "THS_PREPARECNT: %u (0x%x)\n", val, val); + dev_dbg(dev, "THS_ZEROCNT: %u (0x%x)\n", val2, val2); + dev_dbg(dev, "THS_HEADERCNT: 0x%x\n", + (u32)(THS_PREPARECNT(val) | THS_ZEROCNT(val2))); + err = tc358746_write(tc358746, THS_HEADERCNT_REG, + THS_PREPARECNT(val) | THS_ZEROCNT(val2)); + if (err) + return err; + + /* TWAKEUP > 1ms in lptxcnt steps */ + val = tc358746_us_to_cnt(cfg->wakeup, hs_byte_clk); + val = val / (lptxcnt + 1) - 1; + dev_dbg(dev, "TWAKEUP: %u (0x%x)\n", val, val); + err = tc358746_write(tc358746, TWAKEUP_REG, val); + if (err) + return err; + + val = tc358746_ps_to_cnt(cfg->clk_post, hs_byte_clk); + dev_dbg(dev, "TCLK_POSTCNT: %u (0x%x)\n", val, val); + err = tc358746_write(tc358746, TCLK_POSTCNT_REG, val); + if (err) + return err; + + val = tc358746_ps_to_cnt(cfg->hs_trail, hs_byte_clk); + dev_dbg(dev, "THS_TRAILCNT: %u (0x%x)\n", val, val); + err = tc358746_write(tc358746, THS_TRAILCNT_REG, val); + if (err) + return err; + + dev_dbg(dev, "CONTCLKMODE: %u", non_cont_clk ? 0 : 1); + return tc358746_write(tc358746, TXOPTIONCNTRL_REG, non_cont_clk ? 0 : 1); +} + +#define MAX_DATA_LANES 4 + +static int tc358746_enable_csi_lanes(struct tc358746 *tc358746, int enable) +{ + unsigned int lanes = tc358746->dphy_cfg.lanes; + unsigned int lane; + u32 reg, val; + int err; + + err = tc358746_update_bits(tc358746, CONFCTL_REG, DATALANE_MASK, + lanes - 1); + if (err) + return err; + + /* Clock lane */ + val = enable ? 0 : LANEDISABLE; + dev_dbg(tc358746->sd.dev, "CLW_CNTRL: 0x%x\n", val); + err = tc358746_write(tc358746, CLW_CNTRL_REG, val); + if (err) + return err; + + for (lane = 0; lane < MAX_DATA_LANES; lane++) { + /* Data lanes */ + reg = D0W_CNTRL_REG + lane * 0x4; + val = (enable && lane < lanes) ? 0 : LANEDISABLE; + + dev_dbg(tc358746->sd.dev, "D%uW_CNTRL: 0x%x\n", lane, val); + err = tc358746_write(tc358746, reg, val); + if (err) + return err; + } + + val = 0; + if (enable) { + /* Clock lane */ + val |= BIT(0); + + /* Data lanes */ + for (lane = 1; lane <= lanes; lane++) + val |= BIT(lane); + } + + dev_dbg(tc358746->sd.dev, "HSTXVREGEN: 0x%x\n", val); + return tc358746_write(tc358746, HSTXVREGEN_REG, val); +} + +static int tc358746_enable_csi_module(struct tc358746 *tc358746, int enable) +{ + unsigned int lanes = tc358746->dphy_cfg.lanes; + int err; + + /* + * START and STRT are only reseted/disabled by sw reset. This is + * required to put the lane state back into LP-11 state. The sw reset + * don't reset register values. + */ + if (!enable) + return tc358746_sw_reset(tc358746); + + err = tc358746_write(tc358746, STARTCNTRL_REG, START); + if (err) + return err; + + err = tc358746_write(tc358746, CSI_START_REG, STRT); + if (err) + return err; + + /* CSI_CONTROL_REG is only indirect accessible */ + return tc358746_write(tc358746, CSI_CONFW_REG, + MODE(MODE_SET) | + ADDRESS(CSI_CONTROL_ADDRESS) | + DATA(CSI_MODE | TXHSMD | NOL(lanes - 1))); +} + +static int tc358746_enable_parallel_port(struct tc358746 *tc358746, int enable) +{ + int err; + + if (enable) { + err = tc358746_write(tc358746, PP_MISC_REG, 0); + if (err) + return err; + + return tc358746_set_bits(tc358746, CONFCTL_REG, PPEN); + } + + err = tc358746_set_bits(tc358746, PP_MISC_REG, FRMSTOP); + if (err) + return err; + + err = tc358746_clear_bits(tc358746, CONFCTL_REG, PPEN); + if (err) + return err; + + return tc358746_set_bits(tc358746, PP_MISC_REG, RSTPTR); +} + +static inline struct v4l2_subdev *tc358746_get_remote_sd(struct media_pad *pad) +{ + pad = media_pad_remote_pad_first(pad); + if (!pad) + return NULL; + + return media_entity_to_v4l2_subdev(pad->entity); +} + +static int tc358746_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct tc358746 *tc358746 = to_tc358746(sd); + struct v4l2_subdev *src; + int err; + + dev_dbg(sd->dev, "%sable\n", enable ? "en" : "dis"); + + src = tc358746_get_remote_sd(&tc358746->pads[TC358746_SINK]); + if (!src) + return -EPIPE; + + if (enable) { + err = pm_runtime_resume_and_get(sd->dev); + if (err) + return err; + + err = tc358746_apply_dphy_config(tc358746); + if (err) + goto err_out; + + err = tc358746_apply_misc_config(tc358746); + if (err) + goto err_out; + + err = tc358746_enable_csi_lanes(tc358746, 1); + if (err) + goto err_out; + + err = tc358746_enable_csi_module(tc358746, 1); + if (err) + goto err_out; + + err = tc358746_enable_parallel_port(tc358746, 1); + if (err) + goto err_out; + + err = v4l2_subdev_call(src, video, s_stream, 1); + if (err) + goto err_out; + + return err; + +err_out: + pm_runtime_mark_last_busy(sd->dev); + pm_runtime_put_sync_autosuspend(sd->dev); + + return err; + } + + /* + * The lanes must be disabled first (before the csi module) so the + * LP-11 state is entered correctly. + */ + err = tc358746_enable_csi_lanes(tc358746, 0); + if (err) + return err; + + err = tc358746_enable_csi_module(tc358746, 0); + if (err) + return err; + + err = tc358746_enable_parallel_port(tc358746, 0); + if (err) + return err; + + pm_runtime_mark_last_busy(sd->dev); + pm_runtime_put_sync_autosuspend(sd->dev); + + return v4l2_subdev_call(src, video, s_stream, 0); +} + +static int tc358746_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *fmt; + + fmt = v4l2_subdev_get_pad_format(sd, state, TC358746_SINK); + *fmt = tc358746_def_fmt; + + fmt = v4l2_subdev_get_pad_format(sd, state, TC358746_SOURCE); + *fmt = tc358746_def_fmt; + fmt->code = tc358746_src_mbus_code(tc358746_def_fmt.code); + + return 0; +} + +static int tc358746_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + const struct tc358746_format *fmt; + + fmt = tc358746_get_format_by_idx(code->pad, code->index); + if (IS_ERR(fmt)) + return PTR_ERR(fmt); + + code->code = fmt->code; + + return 0; +} + +static int tc358746_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *src_fmt, *sink_fmt; + const struct tc358746_format *fmt; + + /* Source follows the sink */ + if (format->pad == TC358746_SOURCE) + return v4l2_subdev_get_fmt(sd, sd_state, format); + + sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, TC358746_SINK); + + fmt = tc358746_get_format_by_code(format->pad, format->format.code); + if (IS_ERR(fmt)) + fmt = tc358746_get_format_by_code(format->pad, tc358746_def_fmt.code); + + format->format.code = fmt->code; + format->format.field = V4L2_FIELD_NONE; + + dev_dbg(sd->dev, "Update format: %ux%u code:0x%x -> %ux%u code:0x%x", + sink_fmt->width, sink_fmt->height, sink_fmt->code, + format->format.width, format->format.height, format->format.code); + + *sink_fmt = format->format; + + src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, TC358746_SOURCE); + *src_fmt = *sink_fmt; + src_fmt->code = tc358746_src_mbus_code(sink_fmt->code); + + return 0; +} + +static unsigned long tc358746_find_pll_settings(struct tc358746 *tc358746, + unsigned long refclk, + unsigned long fout) + +{ + struct device *dev = tc358746->sd.dev; + unsigned long best_freq = 0; + u32 min_delta = 0xffffffff; + u16 prediv_max = 17; + u16 prediv_min = 1; + u16 m_best, mul; + u16 p_best, p; + u8 postdiv; + + if (fout > 1000 * HZ_PER_MHZ) { + dev_err(dev, "HS-Clock above 1 Ghz are not supported\n"); + return 0; + } + + if (fout >= 500 * HZ_PER_MHZ) + postdiv = 1; + else if (fout >= 250 * HZ_PER_MHZ) + postdiv = 2; + else if (fout >= 125 * HZ_PER_MHZ) + postdiv = 4; + else + postdiv = 8; + + for (p = prediv_min; p <= prediv_max; p++) { + unsigned long delta, fin; + u64 tmp; + + fin = DIV_ROUND_CLOSEST(refclk, p); + if (fin < 4 * HZ_PER_MHZ || fin > 40 * HZ_PER_MHZ) + continue; + + tmp = fout * p * postdiv; + do_div(tmp, fin); + mul = tmp; + if (mul > 511) + continue; + + tmp = mul * fin; + do_div(tmp, p * postdiv); + + delta = abs(fout - tmp); + if (delta < min_delta) { + p_best = p; + m_best = mul; + min_delta = delta; + best_freq = tmp; + }; + + if (delta == 0) + break; + }; + + if (!best_freq) { + dev_err(dev, "Failed find PLL frequency\n"); + return 0; + } + + tc358746->pll_post_div = postdiv; + tc358746->pll_pre_div = p_best; + tc358746->pll_mul = m_best; + + if (best_freq != fout) + dev_warn(dev, "Request PLL freq:%lu, found PLL freq:%lu\n", + fout, best_freq); + + dev_dbg(dev, "Found PLL settings: freq:%lu prediv:%u multi:%u postdiv:%u\n", + best_freq, p_best, m_best, postdiv); + + return best_freq; +} + +#define TC358746_PRECISION 10 + +static int +tc358746_link_validate(struct v4l2_subdev *sd, struct media_link *link, + struct v4l2_subdev_format *source_fmt, + struct v4l2_subdev_format *sink_fmt) +{ + struct tc358746 *tc358746 = to_tc358746(sd); + unsigned long csi_bitrate, source_bitrate; + struct v4l2_subdev_state *sink_state; + struct v4l2_mbus_framefmt *mbusfmt; + const struct tc358746_format *fmt; + unsigned int fifo_sz, tmp, n; + struct v4l2_subdev *source; + s64 source_link_freq; + int err; + + err = v4l2_subdev_link_validate_default(sd, link, source_fmt, sink_fmt); + if (err) + return err; + + sink_state = v4l2_subdev_lock_and_get_active_state(sd); + mbusfmt = v4l2_subdev_get_pad_format(sd, sink_state, TC358746_SINK); + + /* Check the FIFO settings */ + fmt = tc358746_get_format_by_code(TC358746_SINK, mbusfmt->code); + + source = media_entity_to_v4l2_subdev(link->source->entity); + source_link_freq = v4l2_get_link_freq(source->ctrl_handler, 0, 0); + if (source_link_freq <= 0) { + dev_err(tc358746->sd.dev, + "Failed to query or invalid source link frequency\n"); + v4l2_subdev_unlock_state(sink_state); + /* Return -EINVAL in case of source_link_freq is 0 */ + return source_link_freq ? : -EINVAL; + } + source_bitrate = source_link_freq * fmt->bus_width; + + csi_bitrate = tc358746->dphy_cfg.lanes * tc358746->pll_rate; + + dev_dbg(tc358746->sd.dev, + "Fifo settings params: source-bitrate:%lu csi-bitrate:%lu", + source_bitrate, csi_bitrate); + + /* Avoid possible FIFO overflows */ + if (csi_bitrate < source_bitrate) { + v4l2_subdev_unlock_state(sink_state); + return -EINVAL; + } + + /* Best case */ + if (csi_bitrate == source_bitrate) { + fifo_sz = TC358746_VB_DEFAULT_SIZE; + tc358746->vb_size = TC358746_VB_DEFAULT_SIZE; + goto out; + } + + /* + * Avoid possible FIFO underflow in case of + * csi_bitrate > source_bitrate. For such case the chip has a internal + * fifo which can be used to delay the line output. + * + * Fifo size calculation (excluding precision): + * + * fifo-sz, image-width - in bits + * sbr - source_bitrate in bits/s + * csir - csi_bitrate in bits/s + * + * 1 1 1 + * image-width * --- + fifo-sz * --- >= ---- * image-width + * sbr sbr csir + * + * fifo-sz >= abs(sbr/csir * image-width - image-width); with n = csir/sbr + * + * fifo-sz >= abs(image-width / n - image-width) + * >= image-width - image-width / n + */ + + source_bitrate /= TC358746_PRECISION; + n = csi_bitrate / source_bitrate; + tmp = (mbusfmt->width * TC358746_PRECISION) / n; + fifo_sz = mbusfmt->width - tmp; + fifo_sz *= fmt->bpp; + tc358746->vb_size = round_up(fifo_sz, 32); + +out: + dev_dbg(tc358746->sd.dev, + "Found FIFO size[bits]:%u -> aligned to size[bits]:%u\n", + fifo_sz, tc358746->vb_size); + + v4l2_subdev_unlock_state(sink_state); + + return tc358746->vb_size > TC358746_VB_MAX_SIZE ? -EINVAL : 0; +} + +static int tc358746_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_config *config) +{ + struct tc358746 *tc358746 = to_tc358746(sd); + + if (pad != TC358746_SOURCE) + return -EINVAL; + + config->type = V4L2_MBUS_CSI2_DPHY; + config->bus.mipi_csi2 = tc358746->csi_vep.bus.mipi_csi2; + + return 0; +} + +static int __maybe_unused +tc358746_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +{ + struct tc358746 *tc358746 = to_tc358746(sd); + + /* 32-bit registers starting from CLW_DPHYCONTTX */ + reg->size = reg->reg < CLW_DPHYCONTTX_REG ? 2 : 4; + + if (!pm_runtime_get_if_in_use(sd->dev)) + return 0; + + tc358746_read(tc358746, reg->reg, (u32 *)®->val); + + pm_runtime_mark_last_busy(sd->dev); + pm_runtime_put_sync_autosuspend(sd->dev); + + return 0; +} + +static int __maybe_unused +tc358746_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) +{ + struct tc358746 *tc358746 = to_tc358746(sd); + + if (!pm_runtime_get_if_in_use(sd->dev)) + return 0; + + tc358746_write(tc358746, (u32)reg->reg, (u32)reg->val); + + pm_runtime_mark_last_busy(sd->dev); + pm_runtime_put_sync_autosuspend(sd->dev); + + return 0; +} + +static const struct v4l2_subdev_core_ops tc358746_core_ops = { +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = tc358746_g_register, + .s_register = tc358746_s_register, +#endif +}; + +static const struct v4l2_subdev_video_ops tc358746_video_ops = { + .s_stream = tc358746_s_stream, +}; + +static const struct v4l2_subdev_pad_ops tc358746_pad_ops = { + .init_cfg = tc358746_init_cfg, + .enum_mbus_code = tc358746_enum_mbus_code, + .set_fmt = tc358746_set_fmt, + .get_fmt = v4l2_subdev_get_fmt, + .link_validate = tc358746_link_validate, + .get_mbus_config = tc358746_get_mbus_config, +}; + +static const struct v4l2_subdev_ops tc358746_ops = { + .core = &tc358746_core_ops, + .video = &tc358746_video_ops, + .pad = &tc358746_pad_ops, +}; + +static const struct media_entity_operations tc358746_entity_ops = { + .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1, + .link_validate = v4l2_subdev_link_validate, +}; + +static int tc358746_mclk_enable(struct clk_hw *hw) +{ + struct tc358746 *tc358746 = clk_hw_to_tc358746(hw); + unsigned int div; + u32 val; + int err; + + div = tc358746->mclk_postdiv / 2; + val = MCLK_HIGH(div - 1) | MCLK_LOW(div - 1); + dev_dbg(tc358746->sd.dev, "MCLKCTL: %u (0x%x)\n", val, val); + err = tc358746_write(tc358746, MCLKCTL_REG, val); + if (err) + return err; + + if (tc358746->mclk_prediv == 8) + val = MCLKDIV(MCLKDIV_8); + else if (tc358746->mclk_prediv == 4) + val = MCLKDIV(MCLKDIV_4); + else + val = MCLKDIV(MCLKDIV_2); + + dev_dbg(tc358746->sd.dev, "CLKCTL[MCLKDIV]: %u (0x%x)\n", val, val); + return tc358746_update_bits(tc358746, CLKCTL_REG, MCLKDIV_MASK, val); +} + +static void tc358746_mclk_disable(struct clk_hw *hw) +{ + struct tc358746 *tc358746 = clk_hw_to_tc358746(hw); + + tc358746_write(tc358746, MCLKCTL_REG, 0); +} + +static long +tc358746_find_mclk_settings(struct tc358746 *tc358746, unsigned long mclk_rate) +{ + unsigned long pll_rate = tc358746->pll_rate; + const unsigned char prediv[] = { 2, 4, 8 }; + unsigned int mclk_prediv, mclk_postdiv; + struct device *dev = tc358746->sd.dev; + unsigned int postdiv, mclkdiv; + unsigned long best_mclk_rate; + unsigned int i; + + /* + * MCLK-Div + * -------------------´`--------------------- + * ´ ` + * +-------------+ +------------------------+ + * | MCLK-PreDiv | | MCLK-PostDiv | + * PLL --> | (2/4/8) | --> | (mclk_low + mclk_high) | --> MCLK + * +-------------+ +------------------------+ + * + * The register value of mclk_low/high is mclk_low/high+1, i.e.: + * mclk_low/high = 1 --> 2 MCLK-Ref Counts + * mclk_low/high = 255 --> 256 MCLK-Ref Counts == max. + * If mclk_low and mclk_high are 0 then MCLK is disabled. + * + * Keep it simple and support 50/50 duty cycles only for now, + * so the calc will be: + * + * MCLK = PLL / (MCLK-PreDiv * 2 * MCLK-PostDiv) + */ + + if (mclk_rate == tc358746->mclk_rate) + return mclk_rate; + + /* Highest possible rate */ + mclkdiv = pll_rate / mclk_rate; + if (mclkdiv <= 8) { + mclk_prediv = 2; + mclk_postdiv = 4; + best_mclk_rate = pll_rate / (2 * 4); + goto out; + } + + /* First check the prediv */ + for (i = 0; i < ARRAY_SIZE(prediv); i++) { + postdiv = mclkdiv / prediv[i]; + + if (postdiv % 2) + continue; + + if (postdiv >= 4 && postdiv <= 512) { + mclk_prediv = prediv[i]; + mclk_postdiv = postdiv; + best_mclk_rate = pll_rate / (prediv[i] * postdiv); + goto out; + } + } + + /* No suitable prediv found, so try to adjust the postdiv */ + for (postdiv = 4; postdiv <= 512; postdiv += 2) { + unsigned int pre; + + pre = mclkdiv / postdiv; + if (pre == 2 || pre == 4 || pre == 8) { + mclk_prediv = pre; + mclk_postdiv = postdiv; + best_mclk_rate = pll_rate / (pre * postdiv); + goto out; + } + } + + /* The MCLK <-> PLL gap is to high -> use largest possible div */ + mclk_prediv = 8; + mclk_postdiv = 512; + best_mclk_rate = pll_rate / (8 * 512); + +out: + tc358746->mclk_prediv = mclk_prediv; + tc358746->mclk_postdiv = mclk_postdiv; + tc358746->mclk_rate = best_mclk_rate; + + if (best_mclk_rate != mclk_rate) + dev_warn(dev, "Request MCLK freq:%lu, found MCLK freq:%lu\n", + mclk_rate, best_mclk_rate); + + dev_dbg(dev, "Found MCLK settings: freq:%lu prediv:%u postdiv:%u\n", + best_mclk_rate, mclk_prediv, mclk_postdiv); + + return best_mclk_rate; +} + +static unsigned long +tc358746_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct tc358746 *tc358746 = clk_hw_to_tc358746(hw); + unsigned int prediv, postdiv; + u32 val; + int err; + + err = tc358746_read(tc358746, MCLKCTL_REG, &val); + if (err) + return 0; + + postdiv = FIELD_GET(MCLK_LOW_MASK, val) + 1; + postdiv += FIELD_GET(MCLK_HIGH_MASK, val) + 1; + + err = tc358746_read(tc358746, CLKCTL_REG, &val); + if (err) + return 0; + + prediv = FIELD_GET(MCLKDIV_MASK, val); + if (prediv == MCLKDIV_8) + prediv = 8; + else if (prediv == MCLKDIV_4) + prediv = 4; + else + prediv = 2; + + return tc358746->pll_rate / (prediv * postdiv); +} + +static long tc358746_mclk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct tc358746 *tc358746 = clk_hw_to_tc358746(hw); + + *parent_rate = tc358746->pll_rate; + + return tc358746_find_mclk_settings(tc358746, rate); +} + +static int tc358746_mclk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct tc358746 *tc358746 = clk_hw_to_tc358746(hw); + + tc358746_find_mclk_settings(tc358746, rate); + + return tc358746_mclk_enable(hw); +} + +static const struct clk_ops tc358746_mclk_ops = { + .enable = tc358746_mclk_enable, + .disable = tc358746_mclk_disable, + .recalc_rate = tc358746_recalc_rate, + .round_rate = tc358746_mclk_round_rate, + .set_rate = tc358746_mclk_set_rate, +}; + +static int tc358746_setup_mclk_provider(struct tc358746 *tc358746) +{ + struct clk_init_data mclk_initdata = { }; + struct device *dev = tc358746->sd.dev; + const char *mclk_name; + int err; + + /* MCLK clk provider support is optional */ + if (!device_property_present(dev, "#clock-cells")) + return 0; + + /* Init to highest possibel MCLK */ + tc358746->mclk_postdiv = 512; + tc358746->mclk_prediv = 8; + + mclk_name = "tc358746-mclk"; + device_property_read_string(dev, "clock-output-names", &mclk_name); + + mclk_initdata.name = mclk_name; + mclk_initdata.ops = &tc358746_mclk_ops; + tc358746->mclk_hw.init = &mclk_initdata; + + err = devm_clk_hw_register(dev, &tc358746->mclk_hw); + if (err) { + dev_err(dev, "Failed to register mclk provider\n"); + return err; + } + + err = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, + &tc358746->mclk_hw); + if (err) + dev_err(dev, "Failed to add mclk provider\n"); + + return err; +} + +static int +tc358746_init_subdev(struct tc358746 *tc358746, struct i2c_client *client) +{ + struct v4l2_subdev *sd = &tc358746->sd; + int err; + + v4l2_i2c_subdev_init(sd, client, &tc358746_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + sd->entity.ops = &tc358746_entity_ops; + + tc358746->pads[TC358746_SINK].flags = MEDIA_PAD_FL_SINK; + tc358746->pads[TC358746_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + err = media_entity_pads_init(&sd->entity, TC358746_NR_PADS, + tc358746->pads); + if (err) + return err; + + err = v4l2_subdev_init_finalize(sd); + if (err) + media_entity_cleanup(&sd->entity); + + return err; +} + +static int +tc358746_init_output_port(struct tc358746 *tc358746, unsigned long refclk) +{ + struct device *dev = tc358746->sd.dev; + struct v4l2_fwnode_endpoint *vep; + unsigned long csi_link_rate; + struct fwnode_handle *ep; + unsigned char csi_lanes; + int err; + + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), TC358746_SOURCE, + 0, 0); + if (!ep) { + dev_err(dev, "Missing endpoint node\n"); + return -EINVAL; + } + + /* Currently we only support 'parallel in' -> 'csi out' */ + vep = &tc358746->csi_vep; + vep->bus_type = V4L2_MBUS_CSI2_DPHY; + err = v4l2_fwnode_endpoint_alloc_parse(ep, vep); + fwnode_handle_put(ep); + if (err) { + dev_err(dev, "Failed to parse source endpoint\n"); + return err; + } + + csi_lanes = vep->bus.mipi_csi2.num_data_lanes; + if (csi_lanes == 0 || csi_lanes > 4 || + vep->nr_of_link_frequencies == 0) { + dev_err(dev, "error: Invalid CSI-2 settings\n"); + err = -EINVAL; + goto err; + } + + /* TODO: Add support to handle multiple link frequencies */ + csi_link_rate = (unsigned long)vep->link_frequencies[0]; + tc358746->pll_rate = tc358746_find_pll_settings(tc358746, refclk, + csi_link_rate * 2); + if (!tc358746->pll_rate) { + err = -EINVAL; + goto err; + } + + err = phy_mipi_dphy_get_default_config_for_hsclk(tc358746->pll_rate, + csi_lanes, &tc358746->dphy_cfg); + if (err) + goto err; + + tc358746->vb_size = TC358746_VB_DEFAULT_SIZE; + + return 0; + +err: + v4l2_fwnode_endpoint_free(vep); + + return err; +} + +static int tc358746_init_hw(struct tc358746 *tc358746) +{ + struct device *dev = tc358746->sd.dev; + unsigned int chipid; + u32 val; + int err; + + err = pm_runtime_resume_and_get(dev); + if (err < 0) { + dev_err(dev, "Failed to resume the device\n"); + return err; + } + + /* Ensure that CSI interface is put into LP-11 state */ + err = tc358746_sw_reset(tc358746); + if (err) { + pm_runtime_put_sync(dev); + dev_err(dev, "Failed to reset the device\n"); + return err; + } + + err = tc358746_read(tc358746, CHIPID_REG, &val); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_sync_autosuspend(dev); + if (err) + return -ENODEV; + + chipid = FIELD_GET(CHIPID, val); + if (chipid != 0x44) { + dev_err(dev, "Invalid chipid 0x%02x\n", chipid); + return -ENODEV; + } + + return 0; +} + +static int tc358746_init_controls(struct tc358746 *tc358746) +{ + u64 *link_frequencies = tc358746->csi_vep.link_frequencies; + struct v4l2_ctrl *ctrl; + int err; + + err = v4l2_ctrl_handler_init(&tc358746->ctrl_hdl, 1); + if (err) + return err; + + /* + * The driver currently supports only one link-frequency, regardless of + * the input from the firmware, see: tc358746_init_output_port(). So + * report only the first frequency from the array of possible given + * frequencies. + */ + ctrl = v4l2_ctrl_new_int_menu(&tc358746->ctrl_hdl, NULL, + V4L2_CID_LINK_FREQ, 0, 0, + link_frequencies); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + err = tc358746->ctrl_hdl.error; + if (err) { + v4l2_ctrl_handler_free(&tc358746->ctrl_hdl); + return err; + } + + tc358746->sd.ctrl_handler = &tc358746->ctrl_hdl; + + return 0; +} + +static int tc358746_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, + struct v4l2_async_subdev *asd) +{ + struct tc358746 *tc358746 = + container_of(notifier, struct tc358746, notifier); + u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE; + struct media_pad *sink = &tc358746->pads[TC358746_SINK]; + + return v4l2_create_fwnode_links_to_pad(sd, sink, flags); +} + +static const struct v4l2_async_notifier_operations tc358746_notify_ops = { + .bound = tc358746_notify_bound, +}; + +static int tc358746_async_register(struct tc358746 *tc358746) +{ + struct v4l2_fwnode_endpoint vep = { + .bus_type = V4L2_MBUS_PARALLEL, + }; + struct v4l2_async_subdev *asd; + struct fwnode_handle *ep; + int err; + + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(tc358746->sd.dev), + TC358746_SINK, 0, 0); + if (!ep) + return -ENOTCONN; + + err = v4l2_fwnode_endpoint_parse(ep, &vep); + if (err) { + fwnode_handle_put(ep); + return err; + } + + v4l2_async_nf_init(&tc358746->notifier); + asd = v4l2_async_nf_add_fwnode_remote(&tc358746->notifier, ep, + struct v4l2_async_subdev); + fwnode_handle_put(ep); + + if (IS_ERR(asd)) { + err = PTR_ERR(asd); + goto err_cleanup; + } + + tc358746->notifier.ops = &tc358746_notify_ops; + + err = v4l2_async_subdev_nf_register(&tc358746->sd, &tc358746->notifier); + if (err) + goto err_cleanup; + + tc358746->sd.fwnode = fwnode_graph_get_endpoint_by_id( + dev_fwnode(tc358746->sd.dev), TC358746_SOURCE, 0, 0); + + err = v4l2_async_register_subdev(&tc358746->sd); + if (err) + goto err_unregister; + + return 0; + +err_unregister: + fwnode_handle_put(tc358746->sd.fwnode); + v4l2_async_nf_unregister(&tc358746->notifier); +err_cleanup: + v4l2_async_nf_cleanup(&tc358746->notifier); + + return err; +} + +static int tc358746_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct tc358746 *tc358746; + unsigned long refclk; + unsigned int i; + int err; + + tc358746 = devm_kzalloc(&client->dev, sizeof(*tc358746), GFP_KERNEL); + if (!tc358746) + return -ENOMEM; + + tc358746->regmap = devm_regmap_init_i2c(client, &tc358746_regmap_config); + if (IS_ERR(tc358746->regmap)) + return dev_err_probe(dev, PTR_ERR(tc358746->regmap), + "Failed to init regmap\n"); + + tc358746->refclk = devm_clk_get(dev, "refclk"); + if (IS_ERR(tc358746->refclk)) + return dev_err_probe(dev, PTR_ERR(tc358746->refclk), + "Failed to get refclk\n"); + + err = clk_prepare_enable(tc358746->refclk); + if (err) + return dev_err_probe(dev, err, + "Failed to enable refclk\n"); + + refclk = clk_get_rate(tc358746->refclk); + clk_disable_unprepare(tc358746->refclk); + + if (refclk < 6 * HZ_PER_MHZ || refclk > 40 * HZ_PER_MHZ) + return dev_err_probe(dev, -EINVAL, "Invalid refclk range\n"); + + for (i = 0; i < ARRAY_SIZE(tc358746_supplies); i++) + tc358746->supplies[i].supply = tc358746_supplies[i]; + + err = devm_regulator_bulk_get(dev, ARRAY_SIZE(tc358746_supplies), + tc358746->supplies); + if (err) + return dev_err_probe(dev, err, "Failed to get supplies\n"); + + tc358746->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(tc358746->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(tc358746->reset_gpio), + "Failed to get reset-gpios\n"); + + err = tc358746_init_subdev(tc358746, client); + if (err) + return dev_err_probe(dev, err, "Failed to init subdev\n"); + + err = tc358746_init_output_port(tc358746, refclk); + if (err) + goto err_subdev; + + /* + * Keep this order since we need the output port link-frequencies + * information. + */ + err = tc358746_init_controls(tc358746); + if (err) + goto err_fwnode; + + dev_set_drvdata(dev, tc358746); + + /* Set to 1sec to give the stream reconfiguration enough time */ + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + pm_runtime_enable(dev); + + err = tc358746_init_hw(tc358746); + if (err) + goto err_pm; + + err = tc358746_setup_mclk_provider(tc358746); + if (err) + goto err_pm; + + err = tc358746_async_register(tc358746); + if (err < 0) + goto err_pm; + + dev_dbg(dev, "%s found @ 0x%x (%s)\n", client->name, + client->addr, client->adapter->name); + + return 0; + +err_pm: + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_dont_use_autosuspend(dev); + v4l2_ctrl_handler_free(&tc358746->ctrl_hdl); +err_fwnode: + v4l2_fwnode_endpoint_free(&tc358746->csi_vep); +err_subdev: + v4l2_subdev_cleanup(&tc358746->sd); + media_entity_cleanup(&tc358746->sd.entity); + + return err; +} + +static int tc358746_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct tc358746 *tc358746 = to_tc358746(sd); + + v4l2_subdev_cleanup(sd); + v4l2_ctrl_handler_free(&tc358746->ctrl_hdl); + v4l2_fwnode_endpoint_free(&tc358746->csi_vep); + v4l2_async_nf_unregister(&tc358746->notifier); + v4l2_async_nf_cleanup(&tc358746->notifier); + fwnode_handle_put(sd->fwnode); + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + + pm_runtime_disable(sd->dev); + pm_runtime_set_suspended(sd->dev); + pm_runtime_dont_use_autosuspend(sd->dev); + + return 0; +} + +static int tc358746_suspend(struct device *dev) +{ + struct tc358746 *tc358746 = dev_get_drvdata(dev); + int err; + + clk_disable_unprepare(tc358746->refclk); + + err = regulator_bulk_disable(ARRAY_SIZE(tc358746_supplies), + tc358746->supplies); + if (err) + clk_prepare_enable(tc358746->refclk); + + return err; +} + +static int tc358746_resume(struct device *dev) +{ + struct tc358746 *tc358746 = dev_get_drvdata(dev); + int err; + + gpiod_set_value(tc358746->reset_gpio, 1); + + err = regulator_bulk_enable(ARRAY_SIZE(tc358746_supplies), + tc358746->supplies); + if (err) + return err; + + /* min. 200ns */ + usleep_range(10, 20); + + gpiod_set_value(tc358746->reset_gpio, 0); + + err = clk_prepare_enable(tc358746->refclk); + if (err) + goto err; + + /* min. 700us ... 1ms */ + usleep_range(1000, 1500); + + /* + * Enable the PLL here since it can be called by the clk-framework or by + * the .s_stream() callback. So this is the common place for both. + */ + err = tc358746_apply_pll_config(tc358746); + if (err) + goto err_clk; + + return 0; + +err_clk: + clk_disable_unprepare(tc358746->refclk); +err: + regulator_bulk_disable(ARRAY_SIZE(tc358746_supplies), + tc358746->supplies); + return err; +} + +DEFINE_RUNTIME_DEV_PM_OPS(tc358746_pm_ops, tc358746_suspend, + tc358746_resume, NULL); + +static const struct of_device_id __maybe_unused tc358746_of_match[] = { + { .compatible = "toshiba,tc358746" }, + { }, +}; +MODULE_DEVICE_TABLE(of, tc358746_of_match); + +static struct i2c_driver tc358746_driver = { + .driver = { + .name = "tc358746", + .pm = pm_ptr(&tc358746_pm_ops), + .of_match_table = tc358746_of_match, + }, + .probe_new = tc358746_probe, + .remove = tc358746_remove, +}; + +module_i2c_driver(tc358746_driver); + +MODULE_DESCRIPTION("Toshiba TC358746 Parallel to CSI-2 bridge driver"); +MODULE_AUTHOR("Marco Felsch "); +MODULE_LICENSE("GPL"); -- 2.30.2 From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 9F493C6FA82 for ; Thu, 22 Sep 2022 13:49:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=PbBIHQynQFzDRJrzZuUQpG1ccnwwAB/QIaFtEBUuJL0=; b=O1moht1qxeZ6ou JsA3mt13B9F/a8/+Mv1QBJIkCU5Fsi+EhoivXixv/8lcJvhrOhdMBuImAgHvkfpOLXY17xjnx2yvK HQE6u3TI3HAr/UUNaiqhb2eoOyLf6j4yQSijX5WZI/uQiD8MgOvAJxB6bj3ozHf+JkWqmbkB2xXLp yrBA2SAFiUUmWyoRqWx7k683tadgRO1tIqwrQFkrCsfHoygMidtI68N8QRsNHfSfxBeMvbW1XQ5IO Yq3Iv086NoxCaQ/Rz0aX2Bi4viWsYkbCdQ3ulskpeOF5dWPhBlKge79tXEgb2jejJ6HCrEZBb4dX4 gcZupxhpFkvsRifeIKzQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1obMZn-00FmbE-Vm; Thu, 22 Sep 2022 13:49:15 +0000 Received: from metis.ext.pengutronix.de ([2001:67c:670:201:290:27ff:fe1d:cc33]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1obMZc-00FmUn-9U for linux-phy@lists.infradead.org; Thu, 22 Sep 2022 13:49:13 +0000 Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1obMZM-0008Ea-Fc; Thu, 22 Sep 2022 15:48:48 +0200 Received: from [2a0a:edc0:0:1101:1d::28] (helo=dude02.red.stw.pengutronix.de) by drehscheibe.grey.stw.pengutronix.de with esmtp (Exim 4.94.2) (envelope-from ) id 1obMZM-002GUi-76; Thu, 22 Sep 2022 15:48:46 +0200 Received: from mfe by dude02.red.stw.pengutronix.de with local (Exim 4.94.2) (envelope-from ) id 1obMZJ-00D4Dl-G4; Thu, 22 Sep 2022 15:48:45 +0200 From: Marco Felsch To: mchehab@kernel.org, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, kishon@ti.com, vkoul@kernel.org, laurent.pinchart@ideasonboard.com, sakari.ailus@linux.intel.com, jacopo@jmondi.org, hverkuil@xs4all.nl Cc: linux-phy@lists.infradead.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-media@vger.kernel.org, kernel@pengutronix.de Subject: [PATCH v3 4/4] media: tc358746: add Toshiba TC358746 Parallel to CSI-2 bridge driver Date: Thu, 22 Sep 2022 15:48:43 +0200 Message-Id: <20220922134843.3108267-5-m.felsch@pengutronix.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220922134843.3108267-1-m.felsch@pengutronix.de> References: <20220922134843.3108267-1-m.felsch@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2a0a:edc0:0:c01:1d::a2 X-SA-Exim-Mail-From: mfe@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-phy@lists.infradead.org X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20220922_064904_865105_C1E7C955 X-CRM114-Status: GOOD ( 31.00 ) X-BeenThere: linux-phy@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux Phy Mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Sender: "linux-phy" Errors-To: linux-phy-bounces+linux-phy=archiver.kernel.org@lists.infradead.org QWRkaW5nIHN1cHBvcnQgZm9yIHRoZSBUQzM1ODc0NiBwYXJhbGxlbCA8LT4gTUlQSSBDU0kgYnJp ZGdlLiBUaGlzIGNoaXAKc3VwcG9ydHMgdHdvIG9wZXJhdGluZyBtb2RlczoKICAxc3QpIHBhcmFs bGVsLWluIC0+IG1pcGktY3NpIG91dAogIDJuZCkgbWlwaS1jc2kgaW4gLT4gcGFyYWxsZWwgb3V0 CgpUaGlzIHBhdGNoIG9ubHkgYWRkcyB0aGUgc3VwcG9ydCBmb3IgdGhlIDFzdCBtb2RlLgoKU2ln bmVkLW9mZi1ieTogTWFyY28gRmVsc2NoIDxtLmZlbHNjaEBwZW5ndXRyb25peC5kZT4KLS0tCkNo YW5nZWxvZzoKCnYzOgotIGFkZGVkIG1pc3Npbmcgc3RhdGljCi0gZHJvcCBzL01IWi9IWl9QRVJf TUhaLwotIGtjb25maWc6IGFkZCAiZGVwZW5kcyBvbiBQTSIKLSBBZGQgdGMzNTg3NDZfdmFsaWRf cmVnKCkgZm9yIHJlZ21hcC4KLSB0YzM1ODc0Nl9zZXRfZm10OiBmaXggZm9ybWF0IG5lZ290aWF0 aW9uIGZvciBwYWQgPT0gU09VUkNFCi0gdGMzNTg3NDZfd3JpdGUvcmVhZDogYWRkIGVycm9yIG1l c3NhZ2VzCi0gcmVwbGFjZSB1ZGVsYXkgd2l0aCBmc2xlZXAoKQotIHRjMzU4NzQ2X2FwcGx5X21p c2NfY29uZmlnOiBjb25zdCBtYnVzZm10Ci0gdGMzNTg3NDZfc19zdHJlYW06IGZpeCBjb21tZW50 IGFib3V0IExQLTAwLzExIHN0YXRlIGNoYW5nZQotIHRjMzU4NzQ2X2xpbmtfdmFsaWRhdGU6IHMv c2Vuc29yL3NvdXJjZS8KLSB0YzM1ODc0Nl9saW5rX3ZhbGlkYXRlOiBzL3BjbGtfcmF0ZS9saW5r X2ZyZXEvCi0gdGMzNTg3NDZfbGlua192YWxpZGF0ZTogZml4IHY0bDJfc3ViZGV2X3VubG9ja19z dGF0ZSgpCi0gdGMzNTg3NDZfbGlua192YWxpZGF0ZTogYWRhcHQgZmlmby1zeiBjb21tZW50Ci0g dGMzNTg3NDZfZy9zX3JlZ2lzdGVyOiB1c2UgcG1fcnVudGltZV9nZXRfaWZfaW5fdXNlCi0gdGMz NTg3NDZfc2V0dXBfbWNsa19wcm92aWRlcjogbW92ZSB0byBjbGsgcmVsYXRlZCBsb2NhdGlvbgot IHRjMzU4NzQ2X2luaXRfaHc6IGZpeCBlcnJvciBjYXNlCi0gdGMzNTg3NDZfaW5pdF9jb250cm9s czogYWRkIGNvbW1lbnQKLSB0YzM1ODc0Nl9ub3RpZnlfYm91bmQ6IGFkZCBNRURJQV9MTktfRkxf SU1NVVRBQkxFCi0gdGMzNTg3NDZfYXN5bmNfcmVnaXN0ZXI6IGZpeCBlcnJvciBwYXRoCi0gdGMz NTg3NDZfYXN5bmNfcmVnaXN0ZXI6IHB1dCBzZC5md25vZGUgb24gZXJyb3IgYW5kIHJlbW92ZQot IHRjMzU4NzQ2X3Byb2JlOiBpbmNyZWFzZSBhdXRvc3VzcGVuZCB0byAxcwoKdjI6Ci0gdXNlIHRo ZSBjb3JyZWN0IENJRF9MSU5LX0ZSRVEgY29udHJvbCB0byBxdWVyeSB0aGUgc2Vuc29yX3BjbGtf cmF0ZQotIHJlbW92ZSBub3cgbm90IG5lZWRlZCB0YzM1ODc0Nl9saW5rX3NldHVwKCkgYW5kCiAg c3RydWN0IHY0bDJfY3RybCBzZW5zb3JfcGNsa19jdHJsCi0gY2FsbCB2NGwyX3N1YmRldl9saW5r X3ZhbGlkYXRlX2RlZmF1bHQoKSBkdXJpbmcgbGluayB2YWxpZGF0aW9uCi0gcmVtb3ZlIE1FRElB X0JVU19GTVRfR0JSODg4XzFYMjQvWVVWNDQ0IGZvcm1hdCBzdXBwb3J0Ci0gdXNlIHN1YmRldiBh Y3RpdmVfc3RhdGUgQVBJCi0gcmVwbGFjZSBvd24gLmdldF9mbXQgd2l0aCB2NGwyX3N1YmRldl9n ZXRfZm10Ci0gcmVtb3ZlIHVubmVjZXNzYXJ5IHBhZCBjaGVja3MKLSByZXN0cnVjdHVyZSB0YzM1 ODc0Nl9nZXRfZm9ybWF0X2J5X2NvZGUoKSBpZi1jYXNlCi0gbW92ZSBhcHBseV9kcGh5X2NvbmZp Z3xhcHBseV9taXNjX2NvbmZpZyBmcm9tIHJlc3VtZSBpbnRvcyBzX3N0cmVhbQotIHVzZSBnb3Rv IGluIHNfc3RyZWFtIGVuYWJsZSBjYXNlCi0gZml4IGVycm9yIGhhbmRsaW5nIGluIHN1c3BlbmQv cmVzdW1lCi0gc3BsaXQgcHJvYmUoKSBpbnRvIG1vcmUgc3ViLWZ1bmN0aW9ucwotLS0KIGRyaXZl cnMvbWVkaWEvaTJjL0tjb25maWcgICAgfCAgIDE3ICsKIGRyaXZlcnMvbWVkaWEvaTJjL01ha2Vm aWxlICAgfCAgICAxICsKIGRyaXZlcnMvbWVkaWEvaTJjL3RjMzU4NzQ2LmMgfCAxNjkyICsrKysr KysrKysrKysrKysrKysrKysrKysrKysrKysrKysKIDMgZmlsZXMgY2hhbmdlZCwgMTcxMCBpbnNl cnRpb25zKCspCiBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9tZWRpYS9pMmMvdGMzNTg3NDYu YwoKZGlmZiAtLWdpdCBhL2RyaXZlcnMvbWVkaWEvaTJjL0tjb25maWcgYi9kcml2ZXJzL21lZGlh L2kyYy9LY29uZmlnCmluZGV4IDc4MDZkNGI4MTcxNi4uZjg1Y2RiOTRjNTI0IDEwMDY0NAotLS0g YS9kcml2ZXJzL21lZGlhL2kyYy9LY29uZmlnCisrKyBiL2RyaXZlcnMvbWVkaWEvaTJjL0tjb25m aWcKQEAgLTEyNzIsNiArMTI3MiwyMyBAQCBjb25maWcgVklERU9fVEMzNTg3NDNfQ0VDCiAJICBX aGVuIHNlbGVjdGVkIHRoZSB0YzM1ODc0MyB3aWxsIHN1cHBvcnQgdGhlIG9wdGlvbmFsCiAJICBI RE1JIENFQyBmZWF0dXJlLgogCitjb25maWcgVklERU9fVEMzNTg3NDYKKwl0cmlzdGF0ZSAiVG9z aGliYSBUQzM1ODc0NiBwYXJhbGxlbC1DU0kyIGJyaWRnZSIKKwlkZXBlbmRzIG9uIFZJREVPX0RF ViAmJiBQTSAmJiBJMkMKKwlzZWxlY3QgVklERU9fVjRMMl9TVUJERVZfQVBJCisJc2VsZWN0IE1F RElBX0NPTlRST0xMRVIKKwlzZWxlY3QgVjRMMl9GV05PREUKKwlzZWxlY3QgR0VORVJJQ19QSFlf TUlQSV9EUEhZCisJc2VsZWN0IFJFR01BUF9JMkMKKwlzZWxlY3QgQ09NTU9OX0NMSworCWhlbHAK KwkgIFN1cHBvcnQgZm9yIHRoZSBUb3NoaWJhIFRDMzU4NzQ2IHBhcmFsbGVsIHRvIE1JUEkgQ1NJ LTIgYnJpZGdlLgorCSAgVGhlIGJyaWRnZSBjYW4gd29yayBpbiBib3RoIGRpcmVjdGlvbnMgYnV0 IGN1cnJlbnRseSBvbmx5IHRoZQorCSAgcGFyYWxsZWwtaW4gLyBjc2ktb3V0IHBhdGggaXMgc3Vw cG9ydGVkLgorCisJICBUbyBjb21waWxlIHRoaXMgZHJpdmVyIGFzIGEgbW9kdWxlLCBjaG9vc2Ug TSBoZXJlOiB0aGUKKwkgIG1vZHVsZSB3aWxsIGJlIGNhbGxlZCB0YzM1ODc0Ni4KKwogY29uZmln IFZJREVPX1RWUDUxNFgKIAl0cmlzdGF0ZSAiVGV4YXMgSW5zdHJ1bWVudHMgVFZQNTE0eCB2aWRl byBkZWNvZGVyIgogCWRlcGVuZHMgb24gVklERU9fREVWICYmIEkyQwpkaWZmIC0tZ2l0IGEvZHJp dmVycy9tZWRpYS9pMmMvTWFrZWZpbGUgYi9kcml2ZXJzL21lZGlhL2kyYy9NYWtlZmlsZQppbmRl eCAwYTI5MzMxMDNkZDkuLmQxMDk2YzJhYjQ4MCAxMDA2NDQKLS0tIGEvZHJpdmVycy9tZWRpYS9p MmMvTWFrZWZpbGUKKysrIGIvZHJpdmVycy9tZWRpYS9pMmMvTWFrZWZpbGUKQEAgLTExOCw2ICsx MTgsNyBAQCBvYmotJChDT05GSUdfVklERU9fU09OWV9CVEZfTVBYKSArPSBzb255LWJ0Zi1tcHgu bwogb2JqLSQoQ09ORklHX1ZJREVPX1NSMDMwUEMzMCkgKz0gc3IwMzBwYzMwLm8KIG9iai0kKENP TkZJR19WSURFT19TVF9NSVBJRDAyKSArPSBzdC1taXBpZDAyLm8KIG9iai0kKENPTkZJR19WSURF T19UQzM1ODc0MykgKz0gdGMzNTg3NDMubworb2JqLSQoQ09ORklHX1ZJREVPX1RDMzU4NzQ2KSAr PSB0YzM1ODc0Ni5vCiBvYmotJChDT05GSUdfVklERU9fVERBMTk5N1gpICs9IHRkYTE5OTd4Lm8K IG9iai0kKENPTkZJR19WSURFT19UREE3NDMyKSArPSB0ZGE3NDMyLm8KIG9iai0kKENPTkZJR19W SURFT19UREE5ODQwKSArPSB0ZGE5ODQwLm8KZGlmZiAtLWdpdCBhL2RyaXZlcnMvbWVkaWEvaTJj L3RjMzU4NzQ2LmMgYi9kcml2ZXJzL21lZGlhL2kyYy90YzM1ODc0Ni5jCm5ldyBmaWxlIG1vZGUg MTAwNjQ0CmluZGV4IDAwMDAwMDAwMDAwMC4uMGRjZDVlMGUwODU1Ci0tLSAvZGV2L251bGwKKysr IGIvZHJpdmVycy9tZWRpYS9pMmMvdGMzNTg3NDYuYwpAQCAtMCwwICsxLDE2OTIgQEAKKy8vIFNQ RFgtTGljZW5zZS1JZGVudGlmaWVyOiBHUEwtMi4wLW9ubHkKKy8qCisgKiBUQzM1ODc0NiAtIFBh cmFsbGVsIDwtPiBDU0ktMiBCcmlkZ2UKKyAqCisgKiBDb3B5cmlnaHQgMjAyMiBNYXJjbyBGZWxz Y2ggPGtlcm5lbEBwZW5ndXRyb25peC5kZT4KKyAqCisgKiBOb3RlczoKKyAqICAtIEN1cnJlbnRs eSBvbmx5ICdQYXJhbGxlbC1pbiAtPiBDU0ktb3V0JyBtb2RlIGlzIHN1cHBvcnRlZCEKKyAqLwor CisjaW5jbHVkZSA8bGludXgvYml0ZmllbGQuaD4KKyNpbmNsdWRlIDxsaW51eC9jbGsuaD4KKyNp bmNsdWRlIDxsaW51eC9jbGstcHJvdmlkZXIuaD4KKyNpbmNsdWRlIDxsaW51eC9kZWxheS5oPgor I2luY2x1ZGUgPGxpbnV4L2kyYy5oPgorI2luY2x1ZGUgPGxpbnV4L2ludGVycnVwdC5oPgorI2lu Y2x1ZGUgPGxpbnV4L2tlcm5lbC5oPgorI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPgorI2luY2x1 ZGUgPGxpbnV4L3BoeS9waHktbWlwaS1kcGh5Lmg+CisjaW5jbHVkZSA8bGludXgvcHJvcGVydHku aD4KKyNpbmNsdWRlIDxsaW51eC9wbV9ydW50aW1lLmg+CisjaW5jbHVkZSA8bGludXgvcmVnbWFw Lmg+CisjaW5jbHVkZSA8bGludXgvdW5pdHMuaD4KKyNpbmNsdWRlIDxtZWRpYS92NGwyLWN0cmxz Lmg+CisjaW5jbHVkZSA8bWVkaWEvdjRsMi1kZXZpY2UuaD4KKyNpbmNsdWRlIDxtZWRpYS92NGwy LWZ3bm9kZS5oPgorI2luY2x1ZGUgPG1lZGlhL3Y0bDItbWMuaD4KKworLyogMTYtYml0IHJlZ2lz dGVycyAqLworI2RlZmluZSBDSElQSURfUkVHCQkJMHgwMDAwCisjZGVmaW5lCQlDSElQSUQJCQlH RU5NQVNLKDE1LCA4KQorCisjZGVmaW5lIFNZU0NUTF9SRUcJCQkweDAwMDIKKyNkZWZpbmUJCVNS RVNFVAkJCUJJVCgwKQorCisjZGVmaW5lIENPTkZDVExfUkVHCQkJMHgwMDA0CisjZGVmaW5lCQlQ REFUQUZfTUFTSwkJR0VOTUFTSyg5LCA4KQorI2RlZmluZQkJUERBVEFGX01PREUwCQkwCisjZGVm aW5lCQlQREFUQUZfTU9ERTEJCTEKKyNkZWZpbmUJCVBEQVRBRl9NT0RFMgkJMgorI2RlZmluZQkJ UERBVEFGKHZhbCkJCUZJRUxEX1BSRVAoUERBVEFGX01BU0ssICh2YWwpKQorI2RlZmluZQkJUFBF TgkJCUJJVCg2KQorI2RlZmluZQkJREFUQUxBTkVfTUFTSwkJR0VOTUFTSygxLCAwKQorCisjZGVm aW5lIEZJRk9DVExfUkVHCQkJMHgwMDA2CisjZGVmaW5lIERBVEFGTVRfUkVHCQkJMHgwMDA4Cisj ZGVmaW5lCQlQREZNVCh2YWwpCQlGSUVMRF9QUkVQKEdFTk1BU0soNywgNCksICh2YWwpKQorCisj ZGVmaW5lIE1DTEtDVExfUkVHCQkJMHgwMDBjCisjZGVmaW5lCQlNQ0xLX0hJR0hfTUFTSwkJR0VO TUFTSygxNSwgOCkKKyNkZWZpbmUJCU1DTEtfTE9XX01BU0sJCUdFTk1BU0soNywgMCkKKyNkZWZp bmUJCU1DTEtfSElHSCh2YWwpCQlGSUVMRF9QUkVQKE1DTEtfSElHSF9NQVNLLCAodmFsKSkKKyNk ZWZpbmUJCU1DTEtfTE9XKHZhbCkJCUZJRUxEX1BSRVAoTUNMS19MT1dfTUFTSywgKHZhbCkpCisK KyNkZWZpbmUgUExMQ1RMMF9SRUcJCQkweDAwMTYKKyNkZWZpbmUJCVBMTF9QUkRfTUFTSwkJR0VO TUFTSygxNSwgMTIpCisjZGVmaW5lCQlQTExfUFJEKHZhbCkJCUZJRUxEX1BSRVAoUExMX1BSRF9N QVNLLCAodmFsKSkKKyNkZWZpbmUJCVBMTF9GQkRfTUFTSwkJR0VOTUFTSyg4LCAwKQorI2RlZmlu ZQkJUExMX0ZCRCh2YWwpCQlGSUVMRF9QUkVQKFBMTF9GQkRfTUFTSywgKHZhbCkpCisKKyNkZWZp bmUgUExMQ1RMMV9SRUcJCQkweDAwMTgKKyNkZWZpbmUJCVBMTF9GUlNfTUFTSwkJR0VOTUFTSygx MSwgMTApCisjZGVmaW5lCQlQTExfRlJTKHZhbCkJCUZJRUxEX1BSRVAoUExMX0ZSU19NQVNLLCAo dmFsKSkKKyNkZWZpbmUJCUNLRU4JCQlCSVQoNCkKKyNkZWZpbmUJCVJFU0VUQgkJCUJJVCgxKQor I2RlZmluZQkJUExMX0VOCQkJQklUKDApCisKKyNkZWZpbmUgQ0xLQ1RMX1JFRwkJCTB4MDAyMAor I2RlZmluZQkJTUNMS0RJVl9NQVNLCQlHRU5NQVNLKDMsIDIpCisjZGVmaW5lCQlNQ0xLRElWKHZh bCkJCUZJRUxEX1BSRVAoTUNMS0RJVl9NQVNLLCAodmFsKSkKKyNkZWZpbmUJCU1DTEtESVZfOAkJ MAorI2RlZmluZQkJTUNMS0RJVl80CQkxCisjZGVmaW5lCQlNQ0xLRElWXzIJCTIKKworI2RlZmlu ZSBXT1JEQ05UX1JFRwkJCTB4MDAyMgorI2RlZmluZSBQUF9NSVNDX1JFRwkJCTB4MDAzMgorI2Rl ZmluZQkJRlJNU1RPUAkJCUJJVCgxNSkKKyNkZWZpbmUJCVJTVFBUUgkJCUJJVCgxNCkKKworLyog MzItYml0IHJlZ2lzdGVycyAqLworI2RlZmluZSBDTFdfRFBIWUNPTlRUWF9SRUcJCTB4MDEwMAor I2RlZmluZSBDTFdfQ05UUkxfUkVHCQkJMHgwMTQwCisjZGVmaW5lIEQwV19DTlRSTF9SRUcJCQkw eDAxNDQKKyNkZWZpbmUJCUxBTkVESVNBQkxFCQlCSVQoMCkKKworI2RlZmluZSBTVEFSVENOVFJM X1JFRwkJCTB4MDIwNAorI2RlZmluZQkJU1RBUlQJCQlCSVQoMCkKKworI2RlZmluZSBMSU5FSU5J VENOVF9SRUcJCQkweDAyMTAKKyNkZWZpbmUgTFBUWFRJTUVDTlRfUkVHCQkJMHgwMjE0CisjZGVm aW5lIFRDTEtfSEVBREVSQ05UX1JFRwkJMHgwMjE4CisjZGVmaW5lCQlUQ0xLX1pFUk9DTlQodmFs KQlGSUVMRF9QUkVQKEdFTk1BU0soMTUsIDgpLCAodmFsKSkKKyNkZWZpbmUJCVRDTEtfUFJFUEFS RUNOVCh2YWwpCUZJRUxEX1BSRVAoR0VOTUFTSyg2LCAwKSwgKHZhbCkpCisKKyNkZWZpbmUgVENM S19UUkFJTENOVF9SRUcJCTB4MDIxQworI2RlZmluZSBUSFNfSEVBREVSQ05UX1JFRwkJMHgwMjIw CisjZGVmaW5lCQlUSFNfWkVST0NOVCh2YWwpCUZJRUxEX1BSRVAoR0VOTUFTSygxNCwgOCksICh2 YWwpKQorI2RlZmluZQkJVEhTX1BSRVBBUkVDTlQodmFsKQlGSUVMRF9QUkVQKEdFTk1BU0soNiwg MCksICh2YWwpKQorCisjZGVmaW5lIFRXQUtFVVBfUkVHCQkJMHgwMjI0CisjZGVmaW5lIFRDTEtf UE9TVENOVF9SRUcJCTB4MDIyOAorI2RlZmluZSBUSFNfVFJBSUxDTlRfUkVHCQkweDAyMkMKKyNk ZWZpbmUgSFNUWFZSRUdFTl9SRUcJCQkweDAyMzQKKyNkZWZpbmUgVFhPUFRJT05DTlRSTF9SRUcJ CTB4MDIzOAorI2RlZmluZSBDU0lfQ09OVFJPTF9SRUcJCQkweDA0MEMKKyNkZWZpbmUJCUNTSV9N T0RFCQlCSVQoMTUpCisjZGVmaW5lCQlUWEhTTUQJCQlCSVQoNykKKyNkZWZpbmUJCU5PTCh2YWwp CQlGSUVMRF9QUkVQKEdFTk1BU0soMiwgMSksICh2YWwpKQorCisjZGVmaW5lIENTSV9DT05GV19S RUcJCQkweDA1MDAKKyNkZWZpbmUJCU1PREUodmFsKQkJRklFTERfUFJFUChHRU5NQVNLKDMxLCAy OSksICh2YWwpKQorI2RlZmluZQkJTU9ERV9TRVQJCTB4NQorI2RlZmluZQkJQUREUkVTUyh2YWwp CQlGSUVMRF9QUkVQKEdFTk1BU0soMjgsIDI0KSwgKHZhbCkpCisjZGVmaW5lCQlDU0lfQ09OVFJP TF9BRERSRVNTCTB4MworI2RlZmluZQkJREFUQSh2YWwpCQlGSUVMRF9QUkVQKEdFTk1BU0soMTUs IDApLCAodmFsKSkKKworI2RlZmluZSBDU0lfU1RBUlRfUkVHCQkJMHgwNTE4CisjZGVmaW5lCQlT VFJUCQkJQklUKDApCisKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgdjRsMl9tYnVzX2ZyYW1lZm10IHRj MzU4NzQ2X2RlZl9mbXQgPSB7CisJLndpZHRoCQk9IDY0MCwKKwkuaGVpZ2h0CQk9IDQ4MCwKKwku Y29kZQkJPSBNRURJQV9CVVNfRk1UX1VZVlk4XzJYOCwKKwkuZmllbGQJCT0gVjRMMl9GSUVMRF9O T05FLAorCS5jb2xvcnNwYWNlCT0gVjRMMl9DT0xPUlNQQUNFX0RFRkFVTFQsCisJLnljYmNyX2Vu Ywk9IFY0TDJfWUNCQ1JfRU5DX0RFRkFVTFQsCisJLnF1YW50aXphdGlvbgk9IFY0TDJfUVVBTlRJ WkFUSU9OX0RFRkFVTFQsCisJLnhmZXJfZnVuYwk9IFY0TDJfWEZFUl9GVU5DX0RFRkFVTFQsCit9 OworCitzdGF0aWMgY29uc3QgY2hhciAqIGNvbnN0IHRjMzU4NzQ2X3N1cHBsaWVzW10gPSB7CisJ InZkZGMiLCAidmRkaW8iLCAidmRkbWlwaSIKK307CisKK2VudW0geworCVRDMzU4NzQ2X1NJTkss CisJVEMzNTg3NDZfU09VUkNFLAorCVRDMzU4NzQ2X05SX1BBRFMKK307CisKK3N0cnVjdCB0YzM1 ODc0NiB7CisJc3RydWN0IHY0bDJfc3ViZGV2CQlzZDsKKwlzdHJ1Y3QgbWVkaWFfcGFkCQlwYWRz W1RDMzU4NzQ2X05SX1BBRFNdOworCXN0cnVjdCB2NGwyX2FzeW5jX25vdGlmaWVyCW5vdGlmaWVy OworCXN0cnVjdCB2NGwyX2Z3bm9kZV9lbmRwb2ludAljc2lfdmVwOworCisJc3RydWN0IHY0bDJf Y3RybF9oYW5kbGVyCWN0cmxfaGRsOworCisJc3RydWN0IHJlZ21hcAkJCSpyZWdtYXA7CisJc3Ry dWN0IGNsawkJCSpyZWZjbGs7CisJc3RydWN0IGdwaW9fZGVzYwkJKnJlc2V0X2dwaW87CisJc3Ry dWN0IHJlZ3VsYXRvcl9idWxrX2RhdGEJc3VwcGxpZXNbQVJSQVlfU0laRSh0YzM1ODc0Nl9zdXBw bGllcyldOworCisJc3RydWN0IGNsa19odwkJCW1jbGtfaHc7CisJdW5zaWduZWQgbG9uZwkJCW1j bGtfcmF0ZTsKKwl1OAkJCQltY2xrX3ByZWRpdjsKKwl1MTYJCQkJbWNsa19wb3N0ZGl2OworCisJ dW5zaWduZWQgbG9uZwkJCXBsbF9yYXRlOworCXU4CQkJCXBsbF9wb3N0X2RpdjsKKwl1MTYJCQkJ cGxsX3ByZV9kaXY7CisJdTE2CQkJCXBsbF9tdWw7CisKKyNkZWZpbmUgVEMzNTg3NDZfVkJfTUFY X1NJWkUJCSg1MTEgKiAzMikKKyNkZWZpbmUgVEMzNTg3NDZfVkJfREVGQVVMVF9TSVpFCSAgKDEg KiAzMikKKwl1bnNpZ25lZCBpbnQJCQl2Yl9zaXplOyAvKiBWaWRlbyBidWZmZXIgc2l6ZSBpbiBi aXRzICovCisKKwlzdHJ1Y3QgcGh5X2NvbmZpZ3VyZV9vcHRzX21pcGlfZHBoeSBkcGh5X2NmZzsK K307CisKK3N0YXRpYyBpbmxpbmUgc3RydWN0IHRjMzU4NzQ2ICp0b190YzM1ODc0NihzdHJ1Y3Qg djRsMl9zdWJkZXYgKnNkKQoreworCXJldHVybiBjb250YWluZXJfb2Yoc2QsIHN0cnVjdCB0YzM1 ODc0Niwgc2QpOworfQorCitzdGF0aWMgaW5saW5lIHN0cnVjdCB0YzM1ODc0NiAqY2xrX2h3X3Rv X3RjMzU4NzQ2KHN0cnVjdCBjbGtfaHcgKmh3KQoreworCXJldHVybiBjb250YWluZXJfb2YoaHcs IHN0cnVjdCB0YzM1ODc0NiwgbWNsa19odyk7Cit9CisKK3N0cnVjdCB0YzM1ODc0Nl9mb3JtYXQg eworCXUzMgkJY29kZTsKKwlib29sCQljc2lfZm9ybWF0OworCXVuc2lnbmVkIGNoYXIJYnVzX3dp ZHRoOworCXVuc2lnbmVkIGNoYXIJYnBwOworCS8qIFJlZ2lzdGVyIHZhbHVlcyAqLworCXU4CQlw ZGZvcm1hdDsgLyogUGVyaXBoZXJhbCBEYXRhIEZvcm1hdCAqLworCXU4CQlwZGF0YWY7ICAgLyog UGFyYWxsZWwgRGF0YSBGb3JtYXQgT3B0aW9uICovCit9OworCitlbnVtIHsKKwlQREZPUk1BVF9S QVc4ID0gMCwKKwlQREZPUk1BVF9SQVcxMCwKKwlQREZPUk1BVF9SQVcxMiwKKwlQREZPUk1BVF9S R0I4ODgsCisJUERGT1JNQVRfUkdCNjY2LAorCVBERk9STUFUX1JHQjU2NSwKKwlQREZPUk1BVF9Z VVY0MjJfOEJJVCwKKwkvKiBSRVNFUlZFRCA9IDcgKi8KKwlQREZPUk1BVF9SQVcxNCA9IDgsCisJ UERGT1JNQVRfWVVWNDIyXzEwQklULAorCVBERk9STUFUX1lVVjQ0NCwKK307CisKKy8qIENoZWNr IHRjMzU4NzQ2X3NyY19tYnVzX2NvZGUoKSBpZiB5b3UgYWRkIG5ldyBmb3JtYXRzICovCitzdGF0 aWMgY29uc3Qgc3RydWN0IHRjMzU4NzQ2X2Zvcm1hdCB0YzM1ODc0Nl9mb3JtYXRzW10gPSB7CisJ eworCQkuY29kZSA9IE1FRElBX0JVU19GTVRfVVlWWThfMlg4LAorCQkuYnVzX3dpZHRoID0gOCwK KwkJLmJwcCA9IDE2LAorCQkucGRmb3JtYXQgPSBQREZPUk1BVF9ZVVY0MjJfOEJJVCwKKwkJLnBk YXRhZiA9IFBEQVRBRl9NT0RFMCwKKwl9LCB7CisJCS5jb2RlID0gTUVESUFfQlVTX0ZNVF9VWVZZ OF8xWDE2LAorCQkuY3NpX2Zvcm1hdCA9IHRydWUsCisJCS5idXNfd2lkdGggPSAxNiwKKwkJLmJw cCA9IDE2LAorCQkucGRmb3JtYXQgPSBQREZPUk1BVF9ZVVY0MjJfOEJJVCwKKwkJLnBkYXRhZiA9 IFBEQVRBRl9NT0RFMSwKKwl9LCB7CisJCS5jb2RlID0gTUVESUFfQlVTX0ZNVF9ZVVlWOF8xWDE2 LAorCQkuY3NpX2Zvcm1hdCA9IHRydWUsCisJCS5idXNfd2lkdGggPSAxNiwKKwkJLmJwcCA9IDE2 LAorCQkucGRmb3JtYXQgPSBQREZPUk1BVF9ZVVY0MjJfOEJJVCwKKwkJLnBkYXRhZiA9IFBEQVRB Rl9NT0RFMiwKKwl9LCB7CisJCS5jb2RlID0gTUVESUFfQlVTX0ZNVF9VWVZZMTBfMlgxMCwKKwkJ LmJ1c193aWR0aCA9IDEwLAorCQkuYnBwID0gMjAsCisJCS5wZGZvcm1hdCA9IFBERk9STUFUX1lV VjQyMl8xMEJJVCwKKwkJLnBkYXRhZiA9IFBEQVRBRl9NT0RFMCwgLyogZG9uJ3QgY2FyZSAqLwor CX0KK307CisKKy8qIEdldCBuLXRoIGZvcm1hdCBmb3IgcGFkICovCitzdGF0aWMgY29uc3Qgc3Ry dWN0IHRjMzU4NzQ2X2Zvcm1hdCAqCit0YzM1ODc0Nl9nZXRfZm9ybWF0X2J5X2lkeCh1bnNpZ25l ZCBpbnQgcGFkLCB1bnNpZ25lZCBpbnQgaW5kZXgpCit7CisJdW5zaWduZWQgaW50IGlkeCA9IDA7 CisJdW5zaWduZWQgaW50IGk7CisKKwlmb3IgKGkgPSAwOyBpIDwgQVJSQVlfU0laRSh0YzM1ODc0 Nl9mb3JtYXRzKTsgaSsrKSB7CisJCWNvbnN0IHN0cnVjdCB0YzM1ODc0Nl9mb3JtYXQgKmZtdCA9 ICZ0YzM1ODc0Nl9mb3JtYXRzW2ldOworCisJCWlmICgocGFkID09IFRDMzU4NzQ2X1NPVVJDRSAm JiBmbXQtPmNzaV9mb3JtYXQpIHx8CisJCSAgICAocGFkID09IFRDMzU4NzQ2X1NJTkspKSB7CisJ CQlpZiAoaWR4ID09IGluZGV4KQorCQkJCXJldHVybiBmbXQ7CisJCQlpZHgrKzsKKwkJfQorCX0K KworCXJldHVybiBFUlJfUFRSKC1FSU5WQUwpOworfQorCitzdGF0aWMgY29uc3Qgc3RydWN0IHRj MzU4NzQ2X2Zvcm1hdCAqCit0YzM1ODc0Nl9nZXRfZm9ybWF0X2J5X2NvZGUodW5zaWduZWQgaW50 IHBhZCwgdTMyIGNvZGUpCit7CisJdW5zaWduZWQgaW50IGk7CisKKwlmb3IgKGkgPSAwOyBpIDwg QVJSQVlfU0laRSh0YzM1ODc0Nl9mb3JtYXRzKTsgaSsrKSB7CisJCWNvbnN0IHN0cnVjdCB0YzM1 ODc0Nl9mb3JtYXQgKmZtdCA9ICZ0YzM1ODc0Nl9mb3JtYXRzW2ldOworCisJCWlmIChwYWQgPT0g VEMzNTg3NDZfU0lOSyAmJiBmbXQtPmNvZGUgPT0gY29kZSkKKwkJCXJldHVybiBmbXQ7CisKKwkJ aWYgKHBhZCA9PSBUQzM1ODc0Nl9TT1VSQ0UgJiYgIWZtdC0+Y3NpX2Zvcm1hdCkKKwkJCWNvbnRp bnVlOworCisJCWlmIChmbXQtPmNvZGUgPT0gY29kZSkKKwkJCXJldHVybiBmbXQ7CisJfQorCisJ cmV0dXJuIEVSUl9QVFIoLUVJTlZBTCk7Cit9CisKK3N0YXRpYyB1MzIgdGMzNTg3NDZfc3JjX21i dXNfY29kZSh1MzIgY29kZSkKK3sKKwlzd2l0Y2ggKGNvZGUpIHsKKwljYXNlIE1FRElBX0JVU19G TVRfVVlWWThfMlg4OgorCQlyZXR1cm4gTUVESUFfQlVTX0ZNVF9VWVZZOF8xWDE2OworCWNhc2Ug TUVESUFfQlVTX0ZNVF9VWVZZMTBfMlgxMDoKKwkJcmV0dXJuIE1FRElBX0JVU19GTVRfVVlWWTEw XzFYMjA7CisJZGVmYXVsdDoKKwkJcmV0dXJuIGNvZGU7CisJfQorfQorCitzdGF0aWMgYm9vbCB0 YzM1ODc0Nl92YWxpZF9yZWcoc3RydWN0IGRldmljZSAqZGV2LCB1bnNpZ25lZCBpbnQgcmVnKQor eworCXN3aXRjaCAocmVnKSB7CisJY2FzZSBDSElQSURfUkVHIC4uLiBDU0lfU1RBUlRfUkVHOgor CQlyZXR1cm4gdHJ1ZTsKKwlkZWZhdWx0OgorCQlyZXR1cm4gZmFsc2U7CisJfQorfQorCitzdGF0 aWMgY29uc3Qgc3RydWN0IHJlZ21hcF9jb25maWcgdGMzNTg3NDZfcmVnbWFwX2NvbmZpZyA9IHsK KwkubmFtZSA9ICJ0YzM1ODc0NiIsCisJLnJlZ19iaXRzID0gMTYsCisJLnZhbF9iaXRzID0gMTYs CisJLm1heF9yZWdpc3RlciA9IENTSV9TVEFSVF9SRUcsCisJLndyaXRlYWJsZV9yZWcgPSB0YzM1 ODc0Nl92YWxpZF9yZWcsCisJLnJlYWRhYmxlX3JlZyA9IHRjMzU4NzQ2X3ZhbGlkX3JlZywKKwku cmVnX2Zvcm1hdF9lbmRpYW4gPSBSRUdNQVBfRU5ESUFOX0JJRywKKwkudmFsX2Zvcm1hdF9lbmRp YW4gPSBSRUdNQVBfRU5ESUFOX0JJRywKK307CisKK3N0YXRpYyBpbnQgdGMzNTg3NDZfd3JpdGUo c3RydWN0IHRjMzU4NzQ2ICp0YzM1ODc0NiwgdTMyIHJlZywgdTMyIHZhbCkKK3sKKwlzaXplX3Qg Y291bnQ7CisJaW50IGVycjsKKworCS8qIDMyLWJpdCByZWdpc3RlcnMgc3RhcnRpbmcgZnJvbSBD TFdfRFBIWUNPTlRUWCAqLworCWNvdW50ID0gcmVnIDwgQ0xXX0RQSFlDT05UVFhfUkVHID8gMSA6 IDI7CisKKwllcnIgPSByZWdtYXBfYnVsa193cml0ZSh0YzM1ODc0Ni0+cmVnbWFwLCByZWcsICZ2 YWwsIGNvdW50KTsKKwlpZiAoZXJyKQorCQlkZXZfZGJnKHRjMzU4NzQ2LT5zZC5kZXYsCisJCQki RmFpbGVkIHRvIHdyaXRlIHJlZzoweCUwNHggdmFsOjB4JTA0eFxuIiwgcmVnLCB2YWwpOworCisJ cmV0dXJuIGVycjsKK30KKworc3RhdGljIGludCB0YzM1ODc0Nl9yZWFkKHN0cnVjdCB0YzM1ODc0 NiAqdGMzNTg3NDYsIHUzMiByZWcsIHUzMiAqdmFsKQoreworCXNpemVfdCBjb3VudDsKKwlpbnQg ZXJyOworCisJLyogMzItYml0IHJlZ2lzdGVycyBzdGFydGluZyBmcm9tIENMV19EUEhZQ09OVFRY ICovCisJY291bnQgPSByZWcgPCBDTFdfRFBIWUNPTlRUWF9SRUcgPyAxIDogMjsKKwkqdmFsID0g MDsKKworCWVyciA9IHJlZ21hcF9idWxrX3JlYWQodGMzNTg3NDYtPnJlZ21hcCwgcmVnLCB2YWws IGNvdW50KTsKKwlpZiAoZXJyKQorCQlkZXZfZGJnKHRjMzU4NzQ2LT5zZC5kZXYsICJGYWlsZWQg dG8gcmVhZCByZWc6MHglMDR4XG4iLCByZWcpOworCisJcmV0dXJuIGVycjsKK30KKworc3RhdGlj IGludAordGMzNTg3NDZfdXBkYXRlX2JpdHMoc3RydWN0IHRjMzU4NzQ2ICp0YzM1ODc0NiwgdTMy IHJlZywgdTMyIG1hc2ssIHUzMiB2YWwpCit7CisJdTMyIHRtcCwgb3JpZzsKKwlpbnQgZXJyOwor CisJZXJyID0gdGMzNTg3NDZfcmVhZCh0YzM1ODc0NiwgcmVnLCAmb3JpZyk7CisJaWYgKGVycikK KwkJcmV0dXJuIGVycjsKKworCXRtcCA9IG9yaWcgJiB+bWFzazsKKwl0bXAgfD0gdmFsICYgbWFz azsKKworCXJldHVybiB0YzM1ODc0Nl93cml0ZSh0YzM1ODc0NiwgcmVnLCB0bXApOworfQorCitz dGF0aWMgaW50IHRjMzU4NzQ2X3NldF9iaXRzKHN0cnVjdCB0YzM1ODc0NiAqdGMzNTg3NDYsIHUz MiByZWcsIHUzMiBiaXRzKQoreworCXJldHVybiB0YzM1ODc0Nl91cGRhdGVfYml0cyh0YzM1ODc0 NiwgcmVnLCBiaXRzLCBiaXRzKTsKK30KKworc3RhdGljIGludCB0YzM1ODc0Nl9jbGVhcl9iaXRz KHN0cnVjdCB0YzM1ODc0NiAqdGMzNTg3NDYsIHUzMiByZWcsIHUzMiBiaXRzKQoreworCXJldHVy biB0YzM1ODc0Nl91cGRhdGVfYml0cyh0YzM1ODc0NiwgcmVnLCBiaXRzLCAwKTsKK30KKworc3Rh dGljIGludCB0YzM1ODc0Nl9zd19yZXNldChzdHJ1Y3QgdGMzNTg3NDYgKnRjMzU4NzQ2KQorewor CWludCBlcnI7CisKKwllcnIgPSB0YzM1ODc0Nl9zZXRfYml0cyh0YzM1ODc0NiwgU1lTQ1RMX1JF RywgU1JFU0VUKTsKKwlpZiAoZXJyKQorCQlyZXR1cm4gZXJyOworCisJZnNsZWVwKDEwKTsKKwor CXJldHVybiB0YzM1ODc0Nl9jbGVhcl9iaXRzKHRjMzU4NzQ2LCBTWVNDVExfUkVHLCBTUkVTRVQp OworfQorCitzdGF0aWMgaW50Cit0YzM1ODc0Nl9hcHBseV9wbGxfY29uZmlnKHN0cnVjdCB0YzM1 ODc0NiAqdGMzNTg3NDYpCit7CisJdTggcG9zdCA9IHRjMzU4NzQ2LT5wbGxfcG9zdF9kaXY7CisJ dTE2IHByZSA9IHRjMzU4NzQ2LT5wbGxfcHJlX2RpdjsKKwl1MTYgbXVsID0gdGMzNTg3NDYtPnBs bF9tdWw7CisJdTMyIHZhbCwgbWFzazsKKwlpbnQgZXJyOworCisJZXJyID0gdGMzNTg3NDZfcmVh ZCh0YzM1ODc0NiwgUExMQ1RMMV9SRUcsICZ2YWwpOworCWlmIChlcnIpCisJCXJldHVybiBlcnI7 CisKKwkvKiBEb24ndCB0b3VjaCB0aGUgUExMIGlmIHJ1bm5pbmcgKi8KKwlpZiAoRklFTERfR0VU KFBMTF9FTiwgdmFsKSA9PSAxKQorCQlyZXR1cm4gMDsKKworCS8qIFByZS1kaXYgYW5kIE11bHRp cGxpY2F0b3IgaGF2ZSBhIGludGVybmFsICsxIGxvZ2ljICovCisJdmFsID0gUExMX1BSRChwcmUg LSAxKSB8IFBMTF9GQkQobXVsIC0gMSk7CisJbWFzayA9IFBMTF9QUkRfTUFTSyB8IFBMTF9GQkRf TUFTSzsKKwllcnIgPSB0YzM1ODc0Nl91cGRhdGVfYml0cyh0YzM1ODc0NiwgUExMQ1RMMF9SRUcs IG1hc2ssIHZhbCk7CisJaWYgKGVycikKKwkJcmV0dXJuIGVycjsKKworCXZhbCA9IFBMTF9GUlMo aWxvZzIocG9zdCkpIHwgUkVTRVRCIHwgUExMX0VOOworCW1hc2sgPSBQTExfRlJTX01BU0sgfCBS RVNFVEIgfCBQTExfRU47CisJdGMzNTg3NDZfdXBkYXRlX2JpdHModGMzNTg3NDYsIFBMTENUTDFf UkVHLCBtYXNrLCB2YWwpOworCWlmIChlcnIpCisJCXJldHVybiBlcnI7CisKKwlmc2xlZXAoMTAw MCk7CisKKwlyZXR1cm4gdGMzNTg3NDZfc2V0X2JpdHModGMzNTg3NDYsIFBMTENUTDFfUkVHLCBD S0VOKTsKK30KKworc3RhdGljIGludCB0YzM1ODc0Nl9hcHBseV9taXNjX2NvbmZpZyhzdHJ1Y3Qg dGMzNTg3NDYgKnRjMzU4NzQ2KQoreworCWNvbnN0IHN0cnVjdCB2NGwyX21idXNfZnJhbWVmbXQg Km1idXNmbXQ7CisJc3RydWN0IHY0bDJfc3ViZGV2ICpzZCA9ICZ0YzM1ODc0Ni0+c2Q7CisJc3Ry dWN0IHY0bDJfc3ViZGV2X3N0YXRlICpzaW5rX3N0YXRlOworCWNvbnN0IHN0cnVjdCB0YzM1ODc0 Nl9mb3JtYXQgKmZtdDsKKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSBzZC0+ZGV2OworCXUzMiB2YWw7 CisJaW50IGVycjsKKworCXNpbmtfc3RhdGUgPSB2NGwyX3N1YmRldl9sb2NrX2FuZF9nZXRfYWN0 aXZlX3N0YXRlKHNkKTsKKwltYnVzZm10ID0gdjRsMl9zdWJkZXZfZ2V0X3BhZF9mb3JtYXQoc2Qs IHNpbmtfc3RhdGUsIFRDMzU4NzQ2X1NJTkspOworCXY0bDJfc3ViZGV2X3VubG9ja19zdGF0ZShz aW5rX3N0YXRlKTsKKworCWZtdCA9IHRjMzU4NzQ2X2dldF9mb3JtYXRfYnlfY29kZShUQzM1ODc0 Nl9TSU5LLCBtYnVzZm10LT5jb2RlKTsKKworCS8qIFNlbGYgZGVmaW5lZCBDU0kgdXNlciBkYXRh IHR5cGUgaWQncyBhcmUgbm90IHN1cHBvcnRlZCB5ZXQgKi8KKwl2YWwgPSBQREZNVChmbXQtPnBk Zm9ybWF0KTsKKwlkZXZfZGJnKGRldiwgIkRBVEFGTVQ6IDB4JXhcbiIsIHZhbCk7CisJZXJyID0g dGMzNTg3NDZfd3JpdGUodGMzNTg3NDYsIERBVEFGTVRfUkVHLCB2YWwpOworCWlmIChlcnIpCisJ CXJldHVybiBlcnI7CisKKwl2YWwgPSBQREFUQUYoZm10LT5wZGF0YWYpOworCWRldl9kYmcoZGV2 LCAiQ09ORkNUTFtQREFUQUZdOiAweCV4XG4iLCBmbXQtPnBkYXRhZik7CisJZXJyID0gdGMzNTg3 NDZfdXBkYXRlX2JpdHModGMzNTg3NDYsIENPTkZDVExfUkVHLCBQREFUQUZfTUFTSywgdmFsKTsK KwlpZiAoZXJyKQorCQlyZXR1cm4gZXJyOworCisJdmFsID0gdGMzNTg3NDYtPnZiX3NpemUgLyAz MjsKKwlkZXZfZGJnKGRldiwgIkZJRk9DVEw6ICV1ICgweCV4KVxuIiwgdmFsLCB2YWwpOworCWVy ciA9IHRjMzU4NzQ2X3dyaXRlKHRjMzU4NzQ2LCBGSUZPQ1RMX1JFRywgdmFsKTsKKwlpZiAoZXJy KQorCQlyZXR1cm4gZXJyOworCisJLyogVG90YWwgbnVtYmVyIG9mIGJ5dGVzIGZvciBlYWNoIGxp bmUvd2lkdGggKi8KKwl2YWwgPSBtYnVzZm10LT53aWR0aCAqIGZtdC0+YnBwIC8gODsKKwlkZXZf ZGJnKGRldiwgIldPUkRDTlQ6ICV1ICgweCV4KVxuIiwgdmFsLCB2YWwpOworCXJldHVybiB0YzM1 ODc0Nl93cml0ZSh0YzM1ODc0NiwgV09SRENOVF9SRUcsIHZhbCk7Cit9CisKKy8qIFVzZSBNSHog YXMgYmFzZSBzbyB0aGUgZGl2IG5lZWRzIG5vIHU2NCAqLworc3RhdGljIHUzMiB0YzM1ODc0Nl9j ZmdfdG9fY250KHVuc2lnbmVkIGludCBjZmdfdmFsLAorCQkJICAgICAgIHVuc2lnbmVkIGludCBj bGtfbWh6LAorCQkJICAgICAgIHVuc2lnbmVkIGludCB0aW1lX2Jhc2UpCit7CisJcmV0dXJuIERJ Vl9ST1VORF9VUChjZmdfdmFsICogY2xrX21oeiwgdGltZV9iYXNlKTsKK30KKworc3RhdGljIHUz MiB0YzM1ODc0Nl9wc190b19jbnQodW5zaWduZWQgaW50IGNmZ192YWwsCisJCQkgICAgICB1bnNp Z25lZCBpbnQgY2xrX21oeikKK3sKKwlyZXR1cm4gdGMzNTg3NDZfY2ZnX3RvX2NudChjZmdfdmFs LCBjbGtfbWh6LCBVU0VDX1BFUl9TRUMpOworfQorCitzdGF0aWMgdTMyIHRjMzU4NzQ2X3VzX3Rv X2NudCh1bnNpZ25lZCBpbnQgY2ZnX3ZhbCwKKwkJCSAgICAgIHVuc2lnbmVkIGludCBjbGtfbWh6 KQoreworCXJldHVybiB0YzM1ODc0Nl9jZmdfdG9fY250KGNmZ192YWwsIGNsa19taHosIDEpOwor fQorCitzdGF0aWMgaW50IHRjMzU4NzQ2X2FwcGx5X2RwaHlfY29uZmlnKHN0cnVjdCB0YzM1ODc0 NiAqdGMzNTg3NDYpCit7CisJc3RydWN0IHBoeV9jb25maWd1cmVfb3B0c19taXBpX2RwaHkgKmNm ZyA9ICZ0YzM1ODc0Ni0+ZHBoeV9jZmc7CisJYm9vbCBub25fY29udF9jbGsgPSAhISh0YzM1ODc0 Ni0+Y3NpX3ZlcC5idXMubWlwaV9jc2kyLmZsYWdzICYKKwkJCSAgICAgICBWNEwyX01CVVNfQ1NJ Ml9OT05DT05USU5VT1VTX0NMT0NLKTsKKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSB0YzM1ODc0Ni0+ c2QuZGV2OworCXVuc2lnbmVkIGxvbmcgaHNfYnl0ZV9jbGssIGhmX2NsazsKKwl1MzIgdmFsLCB2 YWwyLCBscHR4Y250OworCWludCBlcnI7CisKKwkvKiBUaGUgaHNfYnl0ZV9jbGsgaXMgYWxzbyBj YWxsZWQgU1lTQ0xLIGluIHRoZSBleGNlbCBzaGVldCAqLworCWhzX2J5dGVfY2xrID0gY2ZnLT5o c19jbGtfcmF0ZSAvIDg7CisJaHNfYnl0ZV9jbGsgLz0gSFpfUEVSX01IWjsKKwloZl9jbGsgPSBo c19ieXRlX2NsayAvIDI7CisKKwl2YWwgPSB0YzM1ODc0Nl91c190b19jbnQoY2ZnLT5pbml0LCBo Zl9jbGspIC0gMTsKKwlkZXZfZGJnKGRldiwgIkxJTkVJTklUQ05UOiAldSAoMHgleClcbiIsIHZh bCwgdmFsKTsKKwllcnIgPSB0YzM1ODc0Nl93cml0ZSh0YzM1ODc0NiwgTElORUlOSVRDTlRfUkVH LCB2YWwpOworCWlmIChlcnIpCisJCXJldHVybiBlcnI7CisKKwl2YWwgPSB0YzM1ODc0Nl9wc190 b19jbnQoY2ZnLT5scHgsIGhzX2J5dGVfY2xrKSAtIDE7CisJbHB0eGNudCA9IHZhbDsKKwlkZXZf ZGJnKGRldiwgIkxQVFhUSU1FQ05UOiAldSAoMHgleClcbiIsIHZhbCwgdmFsKTsKKwllcnIgPSB0 YzM1ODc0Nl93cml0ZSh0YzM1ODc0NiwgTFBUWFRJTUVDTlRfUkVHLCB2YWwpOworCWlmIChlcnIp CisJCXJldHVybiBlcnI7CisKKwl2YWwgPSB0YzM1ODc0Nl9wc190b19jbnQoY2ZnLT5jbGtfcHJl cGFyZSwgaHNfYnl0ZV9jbGspIC0gMTsKKwl2YWwyID0gdGMzNTg3NDZfcHNfdG9fY250KGNmZy0+ Y2xrX3plcm8sIGhzX2J5dGVfY2xrKSAtIDE7CisJZGV2X2RiZyhkZXYsICJUQ0xLX1BSRVBBUkVD TlQ6ICV1ICgweCV4KVxuIiwgdmFsLCB2YWwpOworCWRldl9kYmcoZGV2LCAiVENMS19aRVJPQ05U OiAldSAoMHgleClcbiIsIHZhbDIsIHZhbDIpOworCWRldl9kYmcoZGV2LCAiVENMS19IRUFERVJD TlQ6IDB4JXhcbiIsCisJCSh1MzIpKFRDTEtfUFJFUEFSRUNOVCh2YWwpIHwgVENMS19aRVJPQ05U KHZhbDIpKSk7CisJZXJyID0gdGMzNTg3NDZfd3JpdGUodGMzNTg3NDYsIFRDTEtfSEVBREVSQ05U X1JFRywKKwkJCSAgICAgVENMS19QUkVQQVJFQ05UKHZhbCkgfCBUQ0xLX1pFUk9DTlQodmFsMikp OworCWlmIChlcnIpCisJCXJldHVybiBlcnI7CisKKwl2YWwgPSB0YzM1ODc0Nl9wc190b19jbnQo Y2ZnLT5jbGtfdHJhaWwsIGhzX2J5dGVfY2xrKTsKKwlkZXZfZGJnKGRldiwgIlRDTEtfVFJBSUxD TlQ6ICV1ICgweCV4KVxuIiwgdmFsLCB2YWwpOworCWVyciA9IHRjMzU4NzQ2X3dyaXRlKHRjMzU4 NzQ2LCBUQ0xLX1RSQUlMQ05UX1JFRywgdmFsKTsKKwlpZiAoZXJyKQorCQlyZXR1cm4gZXJyOwor CisJdmFsID0gdGMzNTg3NDZfcHNfdG9fY250KGNmZy0+aHNfcHJlcGFyZSwgaHNfYnl0ZV9jbGsp IC0gMTsKKwl2YWwyID0gdGMzNTg3NDZfcHNfdG9fY250KGNmZy0+aHNfemVybywgaHNfYnl0ZV9j bGspIC0gMTsKKwlkZXZfZGJnKGRldiwgIlRIU19QUkVQQVJFQ05UOiAldSAoMHgleClcbiIsIHZh bCwgdmFsKTsKKwlkZXZfZGJnKGRldiwgIlRIU19aRVJPQ05UOiAldSAoMHgleClcbiIsIHZhbDIs IHZhbDIpOworCWRldl9kYmcoZGV2LCAiVEhTX0hFQURFUkNOVDogMHgleFxuIiwKKwkJKHUzMiko VEhTX1BSRVBBUkVDTlQodmFsKSB8IFRIU19aRVJPQ05UKHZhbDIpKSk7CisJZXJyID0gdGMzNTg3 NDZfd3JpdGUodGMzNTg3NDYsIFRIU19IRUFERVJDTlRfUkVHLAorCQkJICAgICBUSFNfUFJFUEFS RUNOVCh2YWwpIHwgVEhTX1pFUk9DTlQodmFsMikpOworCWlmIChlcnIpCisJCXJldHVybiBlcnI7 CisKKwkvKiBUV0FLRVVQID4gMW1zIGluIGxwdHhjbnQgc3RlcHMgKi8KKwl2YWwgPSB0YzM1ODc0 Nl91c190b19jbnQoY2ZnLT53YWtldXAsIGhzX2J5dGVfY2xrKTsKKwl2YWwgPSB2YWwgLyAobHB0 eGNudCArIDEpIC0gMTsKKwlkZXZfZGJnKGRldiwgIlRXQUtFVVA6ICV1ICgweCV4KVxuIiwgdmFs LCB2YWwpOworCWVyciA9IHRjMzU4NzQ2X3dyaXRlKHRjMzU4NzQ2LCBUV0FLRVVQX1JFRywgdmFs KTsKKwlpZiAoZXJyKQorCQlyZXR1cm4gZXJyOworCisJdmFsID0gdGMzNTg3NDZfcHNfdG9fY250 KGNmZy0+Y2xrX3Bvc3QsIGhzX2J5dGVfY2xrKTsKKwlkZXZfZGJnKGRldiwgIlRDTEtfUE9TVENO VDogJXUgKDB4JXgpXG4iLCB2YWwsIHZhbCk7CisJZXJyID0gdGMzNTg3NDZfd3JpdGUodGMzNTg3 NDYsIFRDTEtfUE9TVENOVF9SRUcsIHZhbCk7CisJaWYgKGVycikKKwkJcmV0dXJuIGVycjsKKwor CXZhbCA9IHRjMzU4NzQ2X3BzX3RvX2NudChjZmctPmhzX3RyYWlsLCBoc19ieXRlX2Nsayk7CisJ ZGV2X2RiZyhkZXYsICJUSFNfVFJBSUxDTlQ6ICV1ICgweCV4KVxuIiwgdmFsLCB2YWwpOworCWVy ciA9IHRjMzU4NzQ2X3dyaXRlKHRjMzU4NzQ2LCBUSFNfVFJBSUxDTlRfUkVHLCB2YWwpOworCWlm IChlcnIpCisJCXJldHVybiBlcnI7CisKKwlkZXZfZGJnKGRldiwgIkNPTlRDTEtNT0RFOiAldSIs IG5vbl9jb250X2NsayA/IDAgOiAxKTsKKwlyZXR1cm4gIHRjMzU4NzQ2X3dyaXRlKHRjMzU4NzQ2 LCBUWE9QVElPTkNOVFJMX1JFRywgbm9uX2NvbnRfY2xrID8gMCA6IDEpOworfQorCisjZGVmaW5l IE1BWF9EQVRBX0xBTkVTIDQKKworc3RhdGljIGludCB0YzM1ODc0Nl9lbmFibGVfY3NpX2xhbmVz KHN0cnVjdCB0YzM1ODc0NiAqdGMzNTg3NDYsIGludCBlbmFibGUpCit7CisJdW5zaWduZWQgaW50 IGxhbmVzID0gdGMzNTg3NDYtPmRwaHlfY2ZnLmxhbmVzOworCXVuc2lnbmVkIGludCBsYW5lOwor CXUzMiByZWcsIHZhbDsKKwlpbnQgZXJyOworCisJZXJyID0gdGMzNTg3NDZfdXBkYXRlX2JpdHMo dGMzNTg3NDYsIENPTkZDVExfUkVHLCBEQVRBTEFORV9NQVNLLAorCQkJCSAgIGxhbmVzIC0gMSk7 CisJaWYgKGVycikKKwkJcmV0dXJuIGVycjsKKworCS8qIENsb2NrIGxhbmUgKi8KKwl2YWwgPSBl bmFibGUgPyAwIDogTEFORURJU0FCTEU7CisJZGV2X2RiZyh0YzM1ODc0Ni0+c2QuZGV2LCAiQ0xX X0NOVFJMOiAweCV4XG4iLCB2YWwpOworCWVyciA9IHRjMzU4NzQ2X3dyaXRlKHRjMzU4NzQ2LCBD TFdfQ05UUkxfUkVHLCB2YWwpOworCWlmIChlcnIpCisJCXJldHVybiBlcnI7CisKKwlmb3IgKGxh bmUgPSAwOyBsYW5lIDwgTUFYX0RBVEFfTEFORVM7IGxhbmUrKykgeworCQkvKiBEYXRhIGxhbmVz ICovCisJCXJlZyA9IEQwV19DTlRSTF9SRUcgKyBsYW5lICogMHg0OworCQl2YWwgPSAoZW5hYmxl ICYmIGxhbmUgPCBsYW5lcykgPyAwIDogTEFORURJU0FCTEU7CisKKwkJZGV2X2RiZyh0YzM1ODc0 Ni0+c2QuZGV2LCAiRCV1V19DTlRSTDogMHgleFxuIiwgbGFuZSwgdmFsKTsKKwkJZXJyID0gdGMz NTg3NDZfd3JpdGUodGMzNTg3NDYsIHJlZywgdmFsKTsKKwkJaWYgKGVycikKKwkJCXJldHVybiBl cnI7CisJfQorCisJdmFsID0gMDsKKwlpZiAoZW5hYmxlKSB7CisJCS8qIENsb2NrIGxhbmUgKi8K KwkJdmFsIHw9IEJJVCgwKTsKKworCQkvKiBEYXRhIGxhbmVzICovCisJCWZvciAobGFuZSA9IDE7 IGxhbmUgPD0gbGFuZXM7IGxhbmUrKykKKwkJCXZhbCB8PSBCSVQobGFuZSk7CisJfQorCisJZGV2 X2RiZyh0YzM1ODc0Ni0+c2QuZGV2LCAiSFNUWFZSRUdFTjogMHgleFxuIiwgdmFsKTsKKwlyZXR1 cm4gdGMzNTg3NDZfd3JpdGUodGMzNTg3NDYsIEhTVFhWUkVHRU5fUkVHLCB2YWwpOworfQorCitz dGF0aWMgaW50IHRjMzU4NzQ2X2VuYWJsZV9jc2lfbW9kdWxlKHN0cnVjdCB0YzM1ODc0NiAqdGMz NTg3NDYsIGludCBlbmFibGUpCit7CisJdW5zaWduZWQgaW50IGxhbmVzID0gdGMzNTg3NDYtPmRw aHlfY2ZnLmxhbmVzOworCWludCBlcnI7CisKKwkvKgorCSAqIFNUQVJUIGFuZCBTVFJUIGFyZSBv bmx5IHJlc2V0ZWQvZGlzYWJsZWQgYnkgc3cgcmVzZXQuIFRoaXMgaXMKKwkgKiByZXF1aXJlZCB0 byBwdXQgdGhlIGxhbmUgc3RhdGUgYmFjayBpbnRvIExQLTExIHN0YXRlLiBUaGUgc3cgcmVzZXQK KwkgKiBkb24ndCByZXNldCByZWdpc3RlciB2YWx1ZXMuCisJICovCisJaWYgKCFlbmFibGUpCisJ CXJldHVybiB0YzM1ODc0Nl9zd19yZXNldCh0YzM1ODc0Nik7CisKKwllcnIgPSB0YzM1ODc0Nl93 cml0ZSh0YzM1ODc0NiwgU1RBUlRDTlRSTF9SRUcsIFNUQVJUKTsKKwlpZiAoZXJyKQorCQlyZXR1 cm4gZXJyOworCisJZXJyID0gdGMzNTg3NDZfd3JpdGUodGMzNTg3NDYsIENTSV9TVEFSVF9SRUcs IFNUUlQpOworCWlmIChlcnIpCisJCXJldHVybiBlcnI7CisKKwkvKiBDU0lfQ09OVFJPTF9SRUcg aXMgb25seSBpbmRpcmVjdCBhY2Nlc3NpYmxlICovCisJcmV0dXJuIHRjMzU4NzQ2X3dyaXRlKHRj MzU4NzQ2LCBDU0lfQ09ORldfUkVHLAorCQkJICAgICAgTU9ERShNT0RFX1NFVCkgfAorCQkJICAg ICAgQUREUkVTUyhDU0lfQ09OVFJPTF9BRERSRVNTKSB8CisJCQkgICAgICBEQVRBKENTSV9NT0RF IHwgVFhIU01EIHwgTk9MKGxhbmVzIC0gMSkpKTsKK30KKworc3RhdGljIGludCB0YzM1ODc0Nl9l bmFibGVfcGFyYWxsZWxfcG9ydChzdHJ1Y3QgdGMzNTg3NDYgKnRjMzU4NzQ2LCBpbnQgZW5hYmxl KQoreworCWludCBlcnI7CisKKwlpZiAoZW5hYmxlKSB7CisJCWVyciA9IHRjMzU4NzQ2X3dyaXRl KHRjMzU4NzQ2LCBQUF9NSVNDX1JFRywgMCk7CisJCWlmIChlcnIpCisJCQlyZXR1cm4gZXJyOwor CisJCXJldHVybiB0YzM1ODc0Nl9zZXRfYml0cyh0YzM1ODc0NiwgQ09ORkNUTF9SRUcsIFBQRU4p OworCX0KKworCWVyciA9IHRjMzU4NzQ2X3NldF9iaXRzKHRjMzU4NzQ2LCBQUF9NSVNDX1JFRywg RlJNU1RPUCk7CisJaWYgKGVycikKKwkJcmV0dXJuIGVycjsKKworCWVyciA9IHRjMzU4NzQ2X2Ns ZWFyX2JpdHModGMzNTg3NDYsIENPTkZDVExfUkVHLCBQUEVOKTsKKwlpZiAoZXJyKQorCQlyZXR1 cm4gZXJyOworCisJcmV0dXJuIHRjMzU4NzQ2X3NldF9iaXRzKHRjMzU4NzQ2LCBQUF9NSVNDX1JF RywgUlNUUFRSKTsKK30KKworc3RhdGljIGlubGluZSBzdHJ1Y3QgdjRsMl9zdWJkZXYgKnRjMzU4 NzQ2X2dldF9yZW1vdGVfc2Qoc3RydWN0IG1lZGlhX3BhZCAqcGFkKQoreworCXBhZCA9IG1lZGlh X3BhZF9yZW1vdGVfcGFkX2ZpcnN0KHBhZCk7CisJaWYgKCFwYWQpCisJCXJldHVybiBOVUxMOwor CisJcmV0dXJuIG1lZGlhX2VudGl0eV90b192NGwyX3N1YmRldihwYWQtPmVudGl0eSk7Cit9CisK K3N0YXRpYyBpbnQgdGMzNTg3NDZfc19zdHJlYW0oc3RydWN0IHY0bDJfc3ViZGV2ICpzZCwgaW50 IGVuYWJsZSkKK3sKKwlzdHJ1Y3QgdGMzNTg3NDYgKnRjMzU4NzQ2ID0gdG9fdGMzNTg3NDYoc2Qp OworCXN0cnVjdCB2NGwyX3N1YmRldiAqc3JjOworCWludCBlcnI7CisKKwlkZXZfZGJnKHNkLT5k ZXYsICIlc2FibGVcbiIsIGVuYWJsZSA/ICJlbiIgOiAiZGlzIik7CisKKwlzcmMgPSB0YzM1ODc0 Nl9nZXRfcmVtb3RlX3NkKCZ0YzM1ODc0Ni0+cGFkc1tUQzM1ODc0Nl9TSU5LXSk7CisJaWYgKCFz cmMpCisJCXJldHVybiAtRVBJUEU7CisKKwlpZiAoZW5hYmxlKSB7CisJCWVyciA9IHBtX3J1bnRp bWVfcmVzdW1lX2FuZF9nZXQoc2QtPmRldik7CisJCWlmIChlcnIpCisJCQlyZXR1cm4gZXJyOwor CisJCWVyciA9IHRjMzU4NzQ2X2FwcGx5X2RwaHlfY29uZmlnKHRjMzU4NzQ2KTsKKwkJaWYgKGVy cikKKwkJCWdvdG8gZXJyX291dDsKKworCQllcnIgPSB0YzM1ODc0Nl9hcHBseV9taXNjX2NvbmZp Zyh0YzM1ODc0Nik7CisJCWlmIChlcnIpCisJCQlnb3RvIGVycl9vdXQ7CisKKwkJZXJyID0gdGMz NTg3NDZfZW5hYmxlX2NzaV9sYW5lcyh0YzM1ODc0NiwgMSk7CisJCWlmIChlcnIpCisJCQlnb3Rv IGVycl9vdXQ7CisKKwkJZXJyID0gdGMzNTg3NDZfZW5hYmxlX2NzaV9tb2R1bGUodGMzNTg3NDYs IDEpOworCQlpZiAoZXJyKQorCQkJZ290byBlcnJfb3V0OworCisJCWVyciA9IHRjMzU4NzQ2X2Vu YWJsZV9wYXJhbGxlbF9wb3J0KHRjMzU4NzQ2LCAxKTsKKwkJaWYgKGVycikKKwkJCWdvdG8gZXJy X291dDsKKworCQllcnIgPSB2NGwyX3N1YmRldl9jYWxsKHNyYywgdmlkZW8sIHNfc3RyZWFtLCAx KTsKKwkJaWYgKGVycikKKwkJCWdvdG8gZXJyX291dDsKKworCQlyZXR1cm4gZXJyOworCitlcnJf b3V0OgorCQlwbV9ydW50aW1lX21hcmtfbGFzdF9idXN5KHNkLT5kZXYpOworCQlwbV9ydW50aW1l X3B1dF9zeW5jX2F1dG9zdXNwZW5kKHNkLT5kZXYpOworCisJCXJldHVybiBlcnI7CisJfQorCisJ IC8qCisJICAqIFRoZSBsYW5lcyBtdXN0IGJlIGRpc2FibGVkIGZpcnN0IChiZWZvcmUgdGhlIGNz aSBtb2R1bGUpIHNvIHRoZQorCSAgKiBMUC0xMSBzdGF0ZSBpcyBlbnRlcmVkIGNvcnJlY3RseS4K KwkgICovCisJZXJyID0gdGMzNTg3NDZfZW5hYmxlX2NzaV9sYW5lcyh0YzM1ODc0NiwgMCk7CisJ aWYgKGVycikKKwkJcmV0dXJuIGVycjsKKworCWVyciA9IHRjMzU4NzQ2X2VuYWJsZV9jc2lfbW9k dWxlKHRjMzU4NzQ2LCAwKTsKKwlpZiAoZXJyKQorCQlyZXR1cm4gZXJyOworCisJZXJyID0gdGMz NTg3NDZfZW5hYmxlX3BhcmFsbGVsX3BvcnQodGMzNTg3NDYsIDApOworCWlmIChlcnIpCisJCXJl dHVybiBlcnI7CisKKwlwbV9ydW50aW1lX21hcmtfbGFzdF9idXN5KHNkLT5kZXYpOworCXBtX3J1 bnRpbWVfcHV0X3N5bmNfYXV0b3N1c3BlbmQoc2QtPmRldik7CisKKwlyZXR1cm4gdjRsMl9zdWJk ZXZfY2FsbChzcmMsIHZpZGVvLCBzX3N0cmVhbSwgMCk7Cit9CisKK3N0YXRpYyBpbnQgdGMzNTg3 NDZfaW5pdF9jZmcoc3RydWN0IHY0bDJfc3ViZGV2ICpzZCwKKwkJCSAgICAgc3RydWN0IHY0bDJf c3ViZGV2X3N0YXRlICpzdGF0ZSkKK3sKKwlzdHJ1Y3QgdjRsMl9tYnVzX2ZyYW1lZm10ICpmbXQ7 CisKKwlmbXQgPSB2NGwyX3N1YmRldl9nZXRfcGFkX2Zvcm1hdChzZCwgc3RhdGUsIFRDMzU4NzQ2 X1NJTkspOworCSpmbXQgPSB0YzM1ODc0Nl9kZWZfZm10OworCisJZm10ID0gdjRsMl9zdWJkZXZf Z2V0X3BhZF9mb3JtYXQoc2QsIHN0YXRlLCBUQzM1ODc0Nl9TT1VSQ0UpOworCSpmbXQgPSB0YzM1 ODc0Nl9kZWZfZm10OworCWZtdC0+Y29kZSA9IHRjMzU4NzQ2X3NyY19tYnVzX2NvZGUodGMzNTg3 NDZfZGVmX2ZtdC5jb2RlKTsKKworCXJldHVybiAwOworfQorCitzdGF0aWMgaW50IHRjMzU4NzQ2 X2VudW1fbWJ1c19jb2RlKHN0cnVjdCB2NGwyX3N1YmRldiAqc2QsCisJCQkJICAgc3RydWN0IHY0 bDJfc3ViZGV2X3N0YXRlICpzZF9zdGF0ZSwKKwkJCQkgICBzdHJ1Y3QgdjRsMl9zdWJkZXZfbWJ1 c19jb2RlX2VudW0gKmNvZGUpCit7CisJY29uc3Qgc3RydWN0IHRjMzU4NzQ2X2Zvcm1hdCAqZm10 OworCisJZm10ID0gdGMzNTg3NDZfZ2V0X2Zvcm1hdF9ieV9pZHgoY29kZS0+cGFkLCBjb2RlLT5p bmRleCk7CisJaWYgKElTX0VSUihmbXQpKQorCQlyZXR1cm4gUFRSX0VSUihmbXQpOworCisJY29k ZS0+Y29kZSA9IGZtdC0+Y29kZTsKKworCXJldHVybiAwOworfQorCitzdGF0aWMgaW50IHRjMzU4 NzQ2X3NldF9mbXQoc3RydWN0IHY0bDJfc3ViZGV2ICpzZCwKKwkJCSAgICBzdHJ1Y3QgdjRsMl9z dWJkZXZfc3RhdGUgKnNkX3N0YXRlLAorCQkJICAgIHN0cnVjdCB2NGwyX3N1YmRldl9mb3JtYXQg KmZvcm1hdCkKK3sKKwlzdHJ1Y3QgdjRsMl9tYnVzX2ZyYW1lZm10ICpzcmNfZm10LCAqc2lua19m bXQ7CisJY29uc3Qgc3RydWN0IHRjMzU4NzQ2X2Zvcm1hdCAqZm10OworCisJLyogU291cmNlIGZv bGxvd3MgdGhlIHNpbmsgKi8KKwlpZiAoZm9ybWF0LT5wYWQgPT0gVEMzNTg3NDZfU09VUkNFKQor CQlyZXR1cm4gdjRsMl9zdWJkZXZfZ2V0X2ZtdChzZCwgc2Rfc3RhdGUsIGZvcm1hdCk7CisKKwlz aW5rX2ZtdCA9IHY0bDJfc3ViZGV2X2dldF9wYWRfZm9ybWF0KHNkLCBzZF9zdGF0ZSwgVEMzNTg3 NDZfU0lOSyk7CisKKwlmbXQgPSB0YzM1ODc0Nl9nZXRfZm9ybWF0X2J5X2NvZGUoZm9ybWF0LT5w YWQsIGZvcm1hdC0+Zm9ybWF0LmNvZGUpOworCWlmIChJU19FUlIoZm10KSkKKwkJZm10ID0gdGMz NTg3NDZfZ2V0X2Zvcm1hdF9ieV9jb2RlKGZvcm1hdC0+cGFkLCB0YzM1ODc0Nl9kZWZfZm10LmNv ZGUpOworCisJZm9ybWF0LT5mb3JtYXQuY29kZSA9IGZtdC0+Y29kZTsKKwlmb3JtYXQtPmZvcm1h dC5maWVsZCA9IFY0TDJfRklFTERfTk9ORTsKKworCWRldl9kYmcoc2QtPmRldiwgIlVwZGF0ZSBm b3JtYXQ6ICV1eCV1IGNvZGU6MHgleCAtPiAldXgldSBjb2RlOjB4JXgiLAorCQlzaW5rX2ZtdC0+ d2lkdGgsIHNpbmtfZm10LT5oZWlnaHQsIHNpbmtfZm10LT5jb2RlLAorCQlmb3JtYXQtPmZvcm1h dC53aWR0aCwgZm9ybWF0LT5mb3JtYXQuaGVpZ2h0LCBmb3JtYXQtPmZvcm1hdC5jb2RlKTsKKwor CSpzaW5rX2ZtdCA9IGZvcm1hdC0+Zm9ybWF0OworCisJc3JjX2ZtdCA9IHY0bDJfc3ViZGV2X2dl dF9wYWRfZm9ybWF0KHNkLCBzZF9zdGF0ZSwgVEMzNTg3NDZfU09VUkNFKTsKKwkqc3JjX2ZtdCA9 ICpzaW5rX2ZtdDsKKwlzcmNfZm10LT5jb2RlID0gdGMzNTg3NDZfc3JjX21idXNfY29kZShzaW5r X2ZtdC0+Y29kZSk7CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIHVuc2lnbmVkIGxvbmcgdGMz NTg3NDZfZmluZF9wbGxfc2V0dGluZ3Moc3RydWN0IHRjMzU4NzQ2ICp0YzM1ODc0NiwKKwkJCQkJ CXVuc2lnbmVkIGxvbmcgcmVmY2xrLAorCQkJCQkJdW5zaWduZWQgbG9uZyBmb3V0KQorCit7CisJ c3RydWN0IGRldmljZSAqZGV2ID0gdGMzNTg3NDYtPnNkLmRldjsKKwl1bnNpZ25lZCBsb25nIGJl c3RfZnJlcSA9IDA7CisJdTMyIG1pbl9kZWx0YSA9IDB4ZmZmZmZmZmY7CisJdTE2IHByZWRpdl9t YXggPSAxNzsKKwl1MTYgcHJlZGl2X21pbiA9IDE7CisJdTE2IG1fYmVzdCwgbXVsOworCXUxNiBw X2Jlc3QsIHA7CisJdTggcG9zdGRpdjsKKworCWlmIChmb3V0ID4gMTAwMCAqIEhaX1BFUl9NSFop IHsKKwkJZGV2X2VycihkZXYsICJIUy1DbG9jayBhYm92ZSAxIEdoeiBhcmUgbm90IHN1cHBvcnRl ZFxuIik7CisJCXJldHVybiAwOworCX0KKworCWlmIChmb3V0ID49IDUwMCAqIEhaX1BFUl9NSFop CisJCXBvc3RkaXYgPSAxOworCWVsc2UgaWYgKGZvdXQgPj0gMjUwICogSFpfUEVSX01IWikKKwkJ cG9zdGRpdiA9IDI7CisJZWxzZSBpZiAoZm91dCA+PSAxMjUgKiBIWl9QRVJfTUhaKQorCQlwb3N0 ZGl2ID0gNDsKKwllbHNlCisJCXBvc3RkaXYgPSA4OworCisJZm9yIChwID0gcHJlZGl2X21pbjsg cCA8PSBwcmVkaXZfbWF4OyBwKyspIHsKKwkJdW5zaWduZWQgbG9uZyBkZWx0YSwgZmluOworCQl1 NjQgdG1wOworCisJCWZpbiA9IERJVl9ST1VORF9DTE9TRVNUKHJlZmNsaywgcCk7CisJCWlmIChm aW4gPCA0ICogSFpfUEVSX01IWiB8fCBmaW4gPiA0MCAqIEhaX1BFUl9NSFopCisJCQljb250aW51 ZTsKKworCQl0bXAgPSBmb3V0ICogcCAqIHBvc3RkaXY7CisJCWRvX2Rpdih0bXAsIGZpbik7CisJ CW11bCA9IHRtcDsKKwkJaWYgKG11bCA+IDUxMSkKKwkJCWNvbnRpbnVlOworCisJCXRtcCA9IG11 bCAqIGZpbjsKKwkJZG9fZGl2KHRtcCwgcCAqIHBvc3RkaXYpOworCisJCWRlbHRhID0gYWJzKGZv dXQgLSB0bXApOworCQlpZiAoZGVsdGEgPCBtaW5fZGVsdGEpIHsKKwkJCXBfYmVzdCA9IHA7CisJ CQltX2Jlc3QgPSBtdWw7CisJCQltaW5fZGVsdGEgPSBkZWx0YTsKKwkJCWJlc3RfZnJlcSA9IHRt cDsKKwkJfTsKKworCQlpZiAoZGVsdGEgPT0gMCkKKwkJCWJyZWFrOworCX07CisKKwlpZiAoIWJl c3RfZnJlcSkgeworCQlkZXZfZXJyKGRldiwgIkZhaWxlZCBmaW5kIFBMTCBmcmVxdWVuY3lcbiIp OworCQlyZXR1cm4gMDsKKwl9CisKKwl0YzM1ODc0Ni0+cGxsX3Bvc3RfZGl2ID0gcG9zdGRpdjsK Kwl0YzM1ODc0Ni0+cGxsX3ByZV9kaXYgPSBwX2Jlc3Q7CisJdGMzNTg3NDYtPnBsbF9tdWwgPSBt X2Jlc3Q7CisKKwlpZiAoYmVzdF9mcmVxICE9IGZvdXQpCisJCWRldl93YXJuKGRldiwgIlJlcXVl c3QgUExMIGZyZXE6JWx1LCBmb3VuZCBQTEwgZnJlcTolbHVcbiIsCisJCQkgZm91dCwgYmVzdF9m cmVxKTsKKworCWRldl9kYmcoZGV2LCAiRm91bmQgUExMIHNldHRpbmdzOiBmcmVxOiVsdSBwcmVk aXY6JXUgbXVsdGk6JXUgcG9zdGRpdjoldVxuIiwKKwkJYmVzdF9mcmVxLCBwX2Jlc3QsIG1fYmVz dCwgcG9zdGRpdik7CisKKwlyZXR1cm4gYmVzdF9mcmVxOworfQorCisjZGVmaW5lIFRDMzU4NzQ2 X1BSRUNJU0lPTiAxMAorCitzdGF0aWMgaW50Cit0YzM1ODc0Nl9saW5rX3ZhbGlkYXRlKHN0cnVj dCB2NGwyX3N1YmRldiAqc2QsIHN0cnVjdCBtZWRpYV9saW5rICpsaW5rLAorCQkgICAgICAgc3Ry dWN0IHY0bDJfc3ViZGV2X2Zvcm1hdCAqc291cmNlX2ZtdCwKKwkJICAgICAgIHN0cnVjdCB2NGwy X3N1YmRldl9mb3JtYXQgKnNpbmtfZm10KQoreworCXN0cnVjdCB0YzM1ODc0NiAqdGMzNTg3NDYg PSB0b190YzM1ODc0NihzZCk7CisJdW5zaWduZWQgbG9uZyBjc2lfYml0cmF0ZSwgc291cmNlX2Jp dHJhdGU7CisJc3RydWN0IHY0bDJfc3ViZGV2X3N0YXRlICpzaW5rX3N0YXRlOworCXN0cnVjdCB2 NGwyX21idXNfZnJhbWVmbXQgKm1idXNmbXQ7CisJY29uc3Qgc3RydWN0IHRjMzU4NzQ2X2Zvcm1h dCAqZm10OworCXVuc2lnbmVkIGludCBmaWZvX3N6LCB0bXAsIG47CisJc3RydWN0IHY0bDJfc3Vi ZGV2ICpzb3VyY2U7CisJczY0IHNvdXJjZV9saW5rX2ZyZXE7CisJaW50IGVycjsKKworCWVyciA9 IHY0bDJfc3ViZGV2X2xpbmtfdmFsaWRhdGVfZGVmYXVsdChzZCwgbGluaywgc291cmNlX2ZtdCwg c2lua19mbXQpOworCWlmIChlcnIpCisJCXJldHVybiBlcnI7CisKKwlzaW5rX3N0YXRlID0gdjRs Ml9zdWJkZXZfbG9ja19hbmRfZ2V0X2FjdGl2ZV9zdGF0ZShzZCk7CisJbWJ1c2ZtdCA9IHY0bDJf c3ViZGV2X2dldF9wYWRfZm9ybWF0KHNkLCBzaW5rX3N0YXRlLCBUQzM1ODc0Nl9TSU5LKTsKKwor CS8qIENoZWNrIHRoZSBGSUZPIHNldHRpbmdzICovCisJZm10ID0gdGMzNTg3NDZfZ2V0X2Zvcm1h dF9ieV9jb2RlKFRDMzU4NzQ2X1NJTkssIG1idXNmbXQtPmNvZGUpOworCisJc291cmNlID0gbWVk aWFfZW50aXR5X3RvX3Y0bDJfc3ViZGV2KGxpbmstPnNvdXJjZS0+ZW50aXR5KTsKKwlzb3VyY2Vf bGlua19mcmVxID0gdjRsMl9nZXRfbGlua19mcmVxKHNvdXJjZS0+Y3RybF9oYW5kbGVyLCAwLCAw KTsKKwlpZiAoc291cmNlX2xpbmtfZnJlcSA8PSAwKSB7CisJCWRldl9lcnIodGMzNTg3NDYtPnNk LmRldiwKKwkJCSJGYWlsZWQgdG8gcXVlcnkgb3IgaW52YWxpZCBzb3VyY2UgbGluayBmcmVxdWVu Y3lcbiIpOworCQl2NGwyX3N1YmRldl91bmxvY2tfc3RhdGUoc2lua19zdGF0ZSk7CisJCS8qIFJl dHVybiAtRUlOVkFMIGluIGNhc2Ugb2Ygc291cmNlX2xpbmtfZnJlcSBpcyAwICovCisJCXJldHVy biBzb3VyY2VfbGlua19mcmVxID8gOiAtRUlOVkFMOworCX0KKwlzb3VyY2VfYml0cmF0ZSA9IHNv dXJjZV9saW5rX2ZyZXEgKiBmbXQtPmJ1c193aWR0aDsKKworCWNzaV9iaXRyYXRlID0gdGMzNTg3 NDYtPmRwaHlfY2ZnLmxhbmVzICogdGMzNTg3NDYtPnBsbF9yYXRlOworCisJZGV2X2RiZyh0YzM1 ODc0Ni0+c2QuZGV2LAorCQkiRmlmbyBzZXR0aW5ncyBwYXJhbXM6IHNvdXJjZS1iaXRyYXRlOiVs dSBjc2ktYml0cmF0ZTolbHUiLAorCQlzb3VyY2VfYml0cmF0ZSwgY3NpX2JpdHJhdGUpOworCisJ LyogQXZvaWQgcG9zc2libGUgRklGTyBvdmVyZmxvd3MgKi8KKwlpZiAoY3NpX2JpdHJhdGUgPCBz b3VyY2VfYml0cmF0ZSkgeworCQl2NGwyX3N1YmRldl91bmxvY2tfc3RhdGUoc2lua19zdGF0ZSk7 CisJCXJldHVybiAtRUlOVkFMOworCX0KKworCS8qIEJlc3QgY2FzZSAqLworCWlmIChjc2lfYml0 cmF0ZSA9PSBzb3VyY2VfYml0cmF0ZSkgeworCQlmaWZvX3N6ID0gVEMzNTg3NDZfVkJfREVGQVVM VF9TSVpFOworCQl0YzM1ODc0Ni0+dmJfc2l6ZSA9IFRDMzU4NzQ2X1ZCX0RFRkFVTFRfU0laRTsK KwkJZ290byBvdXQ7CisJfQorCisJLyoKKwkgKiBBdm9pZCBwb3NzaWJsZSBGSUZPIHVuZGVyZmxv dyBpbiBjYXNlIG9mCisJICogY3NpX2JpdHJhdGUgPiBzb3VyY2VfYml0cmF0ZS4gRm9yIHN1Y2gg Y2FzZSB0aGUgY2hpcCBoYXMgYSBpbnRlcm5hbAorCSAqIGZpZm8gd2hpY2ggY2FuIGJlIHVzZWQg dG8gZGVsYXkgdGhlIGxpbmUgb3V0cHV0LgorCSAqCisJICogRmlmbyBzaXplIGNhbGN1bGF0aW9u IChleGNsdWRpbmcgcHJlY2lzaW9uKToKKwkgKgorCSAqIGZpZm8tc3osIGltYWdlLXdpZHRoIC0g aW4gYml0cworCSAqIHNiciAgICAgICAgICAgICAgICAgIC0gc291cmNlX2JpdHJhdGUgaW4gYml0 cy9zCisJICogY3NpciAgICAgICAgICAgICAgICAgLSBjc2lfYml0cmF0ZSBpbiBiaXRzL3MKKwkg KgorCSAqICAgICAgICAgICAgICAgIDEgICAgICAgICAgICAgICAxICAgICAgMQorCSAqIGltYWdl LXdpZHRoICogLS0tICsgZmlmby1zeiAqIC0tLSA+PSAtLS0tICogaW1hZ2Utd2lkdGgKKwkgKiAg ICAgICAgICAgICAgIHNiciAgICAgICAgICAgICBzYnIgICAgY3NpcgorCSAqCisJICogZmlmby1z eiA+PSBhYnMoc2JyL2NzaXIgKiBpbWFnZS13aWR0aCAtIGltYWdlLXdpZHRoKTsgd2l0aCBuID0g Y3Npci9zYnIKKwkgKgorCSAqIGZpZm8tc3ogPj0gYWJzKGltYWdlLXdpZHRoIC8gbiAtIGltYWdl LXdpZHRoKQorCSAqICAgICAgICAgPj0gaW1hZ2Utd2lkdGggLSBpbWFnZS13aWR0aCAvIG4KKwkg Ki8KKworCXNvdXJjZV9iaXRyYXRlIC89IFRDMzU4NzQ2X1BSRUNJU0lPTjsKKwluID0gY3NpX2Jp dHJhdGUgLyBzb3VyY2VfYml0cmF0ZTsKKwl0bXAgPSAobWJ1c2ZtdC0+d2lkdGggKiBUQzM1ODc0 Nl9QUkVDSVNJT04pIC8gbjsKKwlmaWZvX3N6ID0gbWJ1c2ZtdC0+d2lkdGggLSB0bXA7CisJZmlm b19zeiAqPSBmbXQtPmJwcDsKKwl0YzM1ODc0Ni0+dmJfc2l6ZSA9IHJvdW5kX3VwKGZpZm9fc3os IDMyKTsKKworb3V0OgorCWRldl9kYmcodGMzNTg3NDYtPnNkLmRldiwKKwkJIkZvdW5kIEZJRk8g c2l6ZVtiaXRzXToldSAtPiBhbGlnbmVkIHRvIHNpemVbYml0c106JXVcbiIsCisJCWZpZm9fc3os IHRjMzU4NzQ2LT52Yl9zaXplKTsKKworCXY0bDJfc3ViZGV2X3VubG9ja19zdGF0ZShzaW5rX3N0 YXRlKTsKKworCXJldHVybiB0YzM1ODc0Ni0+dmJfc2l6ZSA+IFRDMzU4NzQ2X1ZCX01BWF9TSVpF ID8gLUVJTlZBTCA6IDA7Cit9CisKK3N0YXRpYyBpbnQgdGMzNTg3NDZfZ2V0X21idXNfY29uZmln KHN0cnVjdCB2NGwyX3N1YmRldiAqc2QsIHVuc2lnbmVkIGludCBwYWQsCisJCQkJICAgIHN0cnVj dCB2NGwyX21idXNfY29uZmlnICpjb25maWcpCit7CisJc3RydWN0IHRjMzU4NzQ2ICp0YzM1ODc0 NiA9IHRvX3RjMzU4NzQ2KHNkKTsKKworCWlmIChwYWQgIT0gVEMzNTg3NDZfU09VUkNFKQorCQly ZXR1cm4gLUVJTlZBTDsKKworCWNvbmZpZy0+dHlwZSA9IFY0TDJfTUJVU19DU0kyX0RQSFk7CisJ Y29uZmlnLT5idXMubWlwaV9jc2kyID0gdGMzNTg3NDYtPmNzaV92ZXAuYnVzLm1pcGlfY3NpMjsK KworCXJldHVybiAwOworfQorCitzdGF0aWMgaW50IF9fbWF5YmVfdW51c2VkCit0YzM1ODc0Nl9n X3JlZ2lzdGVyKHN0cnVjdCB2NGwyX3N1YmRldiAqc2QsIHN0cnVjdCB2NGwyX2RiZ19yZWdpc3Rl ciAqcmVnKQoreworCXN0cnVjdCB0YzM1ODc0NiAqdGMzNTg3NDYgPSB0b190YzM1ODc0NihzZCk7 CisKKwkvKiAzMi1iaXQgcmVnaXN0ZXJzIHN0YXJ0aW5nIGZyb20gQ0xXX0RQSFlDT05UVFggKi8K KwlyZWctPnNpemUgPSByZWctPnJlZyA8IENMV19EUEhZQ09OVFRYX1JFRyA/IDIgOiA0OworCisJ aWYgKCFwbV9ydW50aW1lX2dldF9pZl9pbl91c2Uoc2QtPmRldikpCisJCXJldHVybiAwOworCisJ dGMzNTg3NDZfcmVhZCh0YzM1ODc0NiwgcmVnLT5yZWcsICh1MzIgKikmcmVnLT52YWwpOworCisJ cG1fcnVudGltZV9tYXJrX2xhc3RfYnVzeShzZC0+ZGV2KTsKKwlwbV9ydW50aW1lX3B1dF9zeW5j X2F1dG9zdXNwZW5kKHNkLT5kZXYpOworCisJcmV0dXJuIDA7Cit9CisKK3N0YXRpYyBpbnQgX19t YXliZV91bnVzZWQKK3RjMzU4NzQ2X3NfcmVnaXN0ZXIoc3RydWN0IHY0bDJfc3ViZGV2ICpzZCwg Y29uc3Qgc3RydWN0IHY0bDJfZGJnX3JlZ2lzdGVyICpyZWcpCit7CisJc3RydWN0IHRjMzU4NzQ2 ICp0YzM1ODc0NiA9IHRvX3RjMzU4NzQ2KHNkKTsKKworCWlmICghcG1fcnVudGltZV9nZXRfaWZf aW5fdXNlKHNkLT5kZXYpKQorCQlyZXR1cm4gMDsKKworCXRjMzU4NzQ2X3dyaXRlKHRjMzU4NzQ2 LCAodTMyKXJlZy0+cmVnLCAodTMyKXJlZy0+dmFsKTsKKworCXBtX3J1bnRpbWVfbWFya19sYXN0 X2J1c3koc2QtPmRldik7CisJcG1fcnVudGltZV9wdXRfc3luY19hdXRvc3VzcGVuZChzZC0+ZGV2 KTsKKworCXJldHVybiAwOworfQorCitzdGF0aWMgY29uc3Qgc3RydWN0IHY0bDJfc3ViZGV2X2Nv cmVfb3BzIHRjMzU4NzQ2X2NvcmVfb3BzID0geworI2lmZGVmIENPTkZJR19WSURFT19BRFZfREVC VUcKKwkuZ19yZWdpc3RlciA9IHRjMzU4NzQ2X2dfcmVnaXN0ZXIsCisJLnNfcmVnaXN0ZXIgPSB0 YzM1ODc0Nl9zX3JlZ2lzdGVyLAorI2VuZGlmCit9OworCitzdGF0aWMgY29uc3Qgc3RydWN0IHY0 bDJfc3ViZGV2X3ZpZGVvX29wcyB0YzM1ODc0Nl92aWRlb19vcHMgPSB7CisJLnNfc3RyZWFtID0g dGMzNTg3NDZfc19zdHJlYW0sCit9OworCitzdGF0aWMgY29uc3Qgc3RydWN0IHY0bDJfc3ViZGV2 X3BhZF9vcHMgdGMzNTg3NDZfcGFkX29wcyA9IHsKKwkuaW5pdF9jZmcgPSB0YzM1ODc0Nl9pbml0 X2NmZywKKwkuZW51bV9tYnVzX2NvZGUgPSB0YzM1ODc0Nl9lbnVtX21idXNfY29kZSwKKwkuc2V0 X2ZtdCA9IHRjMzU4NzQ2X3NldF9mbXQsCisJLmdldF9mbXQgPSB2NGwyX3N1YmRldl9nZXRfZm10 LAorCS5saW5rX3ZhbGlkYXRlID0gdGMzNTg3NDZfbGlua192YWxpZGF0ZSwKKwkuZ2V0X21idXNf Y29uZmlnID0gdGMzNTg3NDZfZ2V0X21idXNfY29uZmlnLAorfTsKKworc3RhdGljIGNvbnN0IHN0 cnVjdCB2NGwyX3N1YmRldl9vcHMgdGMzNTg3NDZfb3BzID0geworCS5jb3JlID0gJnRjMzU4NzQ2 X2NvcmVfb3BzLAorCS52aWRlbyA9ICZ0YzM1ODc0Nl92aWRlb19vcHMsCisJLnBhZCA9ICZ0YzM1 ODc0Nl9wYWRfb3BzLAorfTsKKworc3RhdGljIGNvbnN0IHN0cnVjdCBtZWRpYV9lbnRpdHlfb3Bl cmF0aW9ucyB0YzM1ODc0Nl9lbnRpdHlfb3BzID0geworCS5nZXRfZndub2RlX3BhZCA9IHY0bDJf c3ViZGV2X2dldF9md25vZGVfcGFkXzFfdG9fMSwKKwkubGlua192YWxpZGF0ZSA9IHY0bDJfc3Vi ZGV2X2xpbmtfdmFsaWRhdGUsCit9OworCitzdGF0aWMgaW50IHRjMzU4NzQ2X21jbGtfZW5hYmxl KHN0cnVjdCBjbGtfaHcgKmh3KQoreworCXN0cnVjdCB0YzM1ODc0NiAqdGMzNTg3NDYgPSBjbGtf aHdfdG9fdGMzNTg3NDYoaHcpOworCXVuc2lnbmVkIGludCBkaXY7CisJdTMyIHZhbDsKKwlpbnQg ZXJyOworCisJZGl2ID0gdGMzNTg3NDYtPm1jbGtfcG9zdGRpdiAvIDI7CisJdmFsID0gTUNMS19I SUdIKGRpdiAtIDEpIHwgTUNMS19MT1coZGl2IC0gMSk7CisJZGV2X2RiZyh0YzM1ODc0Ni0+c2Qu ZGV2LCAiTUNMS0NUTDogJXUgKDB4JXgpXG4iLCB2YWwsIHZhbCk7CisJZXJyID0gdGMzNTg3NDZf d3JpdGUodGMzNTg3NDYsIE1DTEtDVExfUkVHLCB2YWwpOworCWlmIChlcnIpCisJCXJldHVybiBl cnI7CisKKwlpZiAodGMzNTg3NDYtPm1jbGtfcHJlZGl2ID09IDgpCisJCXZhbCA9IE1DTEtESVYo TUNMS0RJVl84KTsKKwllbHNlIGlmICh0YzM1ODc0Ni0+bWNsa19wcmVkaXYgPT0gNCkKKwkJdmFs ID0gTUNMS0RJVihNQ0xLRElWXzQpOworCWVsc2UKKwkJdmFsID0gTUNMS0RJVihNQ0xLRElWXzIp OworCisJZGV2X2RiZyh0YzM1ODc0Ni0+c2QuZGV2LCAiQ0xLQ1RMW01DTEtESVZdOiAldSAoMHgl eClcbiIsIHZhbCwgdmFsKTsKKwlyZXR1cm4gdGMzNTg3NDZfdXBkYXRlX2JpdHModGMzNTg3NDYs IENMS0NUTF9SRUcsIE1DTEtESVZfTUFTSywgdmFsKTsKK30KKworc3RhdGljIHZvaWQgdGMzNTg3 NDZfbWNsa19kaXNhYmxlKHN0cnVjdCBjbGtfaHcgKmh3KQoreworCXN0cnVjdCB0YzM1ODc0NiAq dGMzNTg3NDYgPSBjbGtfaHdfdG9fdGMzNTg3NDYoaHcpOworCisJdGMzNTg3NDZfd3JpdGUodGMz NTg3NDYsIE1DTEtDVExfUkVHLCAwKTsKK30KKworc3RhdGljIGxvbmcKK3RjMzU4NzQ2X2ZpbmRf bWNsa19zZXR0aW5ncyhzdHJ1Y3QgdGMzNTg3NDYgKnRjMzU4NzQ2LCB1bnNpZ25lZCBsb25nIG1j bGtfcmF0ZSkKK3sKKwl1bnNpZ25lZCBsb25nIHBsbF9yYXRlID0gdGMzNTg3NDYtPnBsbF9yYXRl OworCWNvbnN0IHVuc2lnbmVkIGNoYXIgcHJlZGl2W10gPSB7IDIsIDQsIDggfTsKKwl1bnNpZ25l ZCBpbnQgbWNsa19wcmVkaXYsIG1jbGtfcG9zdGRpdjsKKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSB0 YzM1ODc0Ni0+c2QuZGV2OworCXVuc2lnbmVkIGludCBwb3N0ZGl2LCBtY2xrZGl2OworCXVuc2ln bmVkIGxvbmcgYmVzdF9tY2xrX3JhdGU7CisJdW5zaWduZWQgaW50IGk7CisKKwkvKgorCSAqICAg ICAgICAgICAgICAgICAgICAgICAgICBNQ0xLLURpdgorCSAqICAgICAgICAgICAtLS0tLS0tLS0t LS0tLS0tLS0twrRgLS0tLS0tLS0tLS0tLS0tLS0tLS0tCisJICogICAgICAgICAgwrQgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgCisJICogICAgICAgICArLS0tLS0t LS0tLS0tLSsgICAgICstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rCisJICogICAgICAgICB8IE1D TEstUHJlRGl2IHwgICAgIHwgICAgICAgTUNMSy1Qb3N0RGl2ICAgICB8CisJICogUExMIC0tPiB8 ICAgKDIvNC84KSAgIHwgLS0+IHwgKG1jbGtfbG93ICsgbWNsa19oaWdoKSB8IC0tPiBNQ0xLCisJ ICogICAgICAgICArLS0tLS0tLS0tLS0tLSsgICAgICstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0r CisJICoKKwkgKiBUaGUgcmVnaXN0ZXIgdmFsdWUgb2YgbWNsa19sb3cvaGlnaCBpcyBtY2xrX2xv dy9oaWdoKzEsIGkuZS46CisJICogICBtY2xrX2xvdy9oaWdoID0gMSAgIC0tPiAyIE1DTEstUmVm IENvdW50cworCSAqICAgbWNsa19sb3cvaGlnaCA9IDI1NSAtLT4gMjU2IE1DTEstUmVmIENvdW50 cyA9PSBtYXguCisJICogSWYgbWNsa19sb3cgYW5kIG1jbGtfaGlnaCBhcmUgMCB0aGVuIE1DTEsg aXMgZGlzYWJsZWQuCisJICoKKwkgKiBLZWVwIGl0IHNpbXBsZSBhbmQgc3VwcG9ydCA1MC81MCBk dXR5IGN5Y2xlcyBvbmx5IGZvciBub3csCisJICogc28gdGhlIGNhbGMgd2lsbCBiZToKKwkgKgor CSAqICAgTUNMSyA9IFBMTCAvIChNQ0xLLVByZURpdiAqIDIgKiBNQ0xLLVBvc3REaXYpCisJICov CisKKwlpZiAobWNsa19yYXRlID09IHRjMzU4NzQ2LT5tY2xrX3JhdGUpCisJCXJldHVybiBtY2xr X3JhdGU7CisKKwkvKiBIaWdoZXN0IHBvc3NpYmxlIHJhdGUgKi8KKwltY2xrZGl2ID0gcGxsX3Jh dGUgLyBtY2xrX3JhdGU7CisJaWYgKG1jbGtkaXYgPD0gOCkgeworCQltY2xrX3ByZWRpdiA9IDI7 CisJCW1jbGtfcG9zdGRpdiA9IDQ7CisJCWJlc3RfbWNsa19yYXRlID0gcGxsX3JhdGUgLyAoMiAq IDQpOworCQlnb3RvIG91dDsKKwl9CisKKwkvKiBGaXJzdCBjaGVjayB0aGUgcHJlZGl2ICovCisJ Zm9yIChpID0gMDsgaSA8IEFSUkFZX1NJWkUocHJlZGl2KTsgaSsrKSB7CisJCXBvc3RkaXYgPSBt Y2xrZGl2IC8gcHJlZGl2W2ldOworCisJCWlmIChwb3N0ZGl2ICUgMikKKwkJCWNvbnRpbnVlOwor CisJCWlmIChwb3N0ZGl2ID49IDQgJiYgcG9zdGRpdiA8PSA1MTIpIHsKKwkJCW1jbGtfcHJlZGl2 ID0gcHJlZGl2W2ldOworCQkJbWNsa19wb3N0ZGl2ID0gcG9zdGRpdjsKKwkJCWJlc3RfbWNsa19y YXRlID0gcGxsX3JhdGUgLyAocHJlZGl2W2ldICogcG9zdGRpdik7CisJCQlnb3RvIG91dDsKKwkJ fQorCX0KKworCS8qIE5vIHN1aXRhYmxlIHByZWRpdiBmb3VuZCwgc28gdHJ5IHRvIGFkanVzdCB0 aGUgcG9zdGRpdiAqLworCWZvciAocG9zdGRpdiA9IDQ7IHBvc3RkaXYgPD0gNTEyOyBwb3N0ZGl2 ICs9IDIpIHsKKwkJdW5zaWduZWQgaW50IHByZTsKKworCQlwcmUgPSBtY2xrZGl2IC8gcG9zdGRp djsKKwkJaWYgKHByZSA9PSAyIHx8IHByZSA9PSA0IHx8IHByZSA9PSA4KSB7CisJCQltY2xrX3By ZWRpdiA9IHByZTsKKwkJCW1jbGtfcG9zdGRpdiA9IHBvc3RkaXY7CisJCQliZXN0X21jbGtfcmF0 ZSA9IHBsbF9yYXRlIC8gKHByZSAqIHBvc3RkaXYpOworCQkJZ290byBvdXQ7CisJCX0KKwl9CisK KwkvKiBUaGUgTUNMSyA8LT4gUExMIGdhcCBpcyB0byBoaWdoIC0+IHVzZSBsYXJnZXN0IHBvc3Np YmxlIGRpdiAqLworCW1jbGtfcHJlZGl2ID0gODsKKwltY2xrX3Bvc3RkaXYgPSA1MTI7CisJYmVz dF9tY2xrX3JhdGUgPSBwbGxfcmF0ZSAvICg4ICogNTEyKTsKKworb3V0OgorCXRjMzU4NzQ2LT5t Y2xrX3ByZWRpdiA9IG1jbGtfcHJlZGl2OworCXRjMzU4NzQ2LT5tY2xrX3Bvc3RkaXYgPSBtY2xr X3Bvc3RkaXY7CisJdGMzNTg3NDYtPm1jbGtfcmF0ZSA9IGJlc3RfbWNsa19yYXRlOworCisJaWYg KGJlc3RfbWNsa19yYXRlICE9IG1jbGtfcmF0ZSkKKwkJZGV2X3dhcm4oZGV2LCAiUmVxdWVzdCBN Q0xLIGZyZXE6JWx1LCBmb3VuZCBNQ0xLIGZyZXE6JWx1XG4iLAorCQkJIG1jbGtfcmF0ZSwgYmVz dF9tY2xrX3JhdGUpOworCisJZGV2X2RiZyhkZXYsICJGb3VuZCBNQ0xLIHNldHRpbmdzOiBmcmVx OiVsdSBwcmVkaXY6JXUgcG9zdGRpdjoldVxuIiwKKwkJYmVzdF9tY2xrX3JhdGUsIG1jbGtfcHJl ZGl2LCBtY2xrX3Bvc3RkaXYpOworCisJcmV0dXJuIGJlc3RfbWNsa19yYXRlOworfQorCitzdGF0 aWMgdW5zaWduZWQgbG9uZwordGMzNTg3NDZfcmVjYWxjX3JhdGUoc3RydWN0IGNsa19odyAqaHcs IHVuc2lnbmVkIGxvbmcgcGFyZW50X3JhdGUpCit7CisJc3RydWN0IHRjMzU4NzQ2ICp0YzM1ODc0 NiA9IGNsa19od190b190YzM1ODc0Nihodyk7CisJdW5zaWduZWQgaW50IHByZWRpdiwgcG9zdGRp djsKKwl1MzIgdmFsOworCWludCBlcnI7CisKKwllcnIgPSB0YzM1ODc0Nl9yZWFkKHRjMzU4NzQ2 LCBNQ0xLQ1RMX1JFRywgJnZhbCk7CisJaWYgKGVycikKKwkJcmV0dXJuIDA7CisKKwlwb3N0ZGl2 ID0gRklFTERfR0VUKE1DTEtfTE9XX01BU0ssIHZhbCkgKyAxOworCXBvc3RkaXYgKz0gRklFTERf R0VUKE1DTEtfSElHSF9NQVNLLCB2YWwpICsgMTsKKworCWVyciA9IHRjMzU4NzQ2X3JlYWQodGMz NTg3NDYsIENMS0NUTF9SRUcsICZ2YWwpOworCWlmIChlcnIpCisJCXJldHVybiAwOworCisJcHJl ZGl2ID0gRklFTERfR0VUKE1DTEtESVZfTUFTSywgdmFsKTsKKwlpZiAocHJlZGl2ID09IE1DTEtE SVZfOCkKKwkJcHJlZGl2ID0gODsKKwllbHNlIGlmIChwcmVkaXYgPT0gTUNMS0RJVl80KQorCQlw cmVkaXYgPSA0OworCWVsc2UKKwkJcHJlZGl2ID0gMjsKKworCXJldHVybiB0YzM1ODc0Ni0+cGxs X3JhdGUgLyAocHJlZGl2ICogcG9zdGRpdik7Cit9CisKK3N0YXRpYyBsb25nIHRjMzU4NzQ2X21j bGtfcm91bmRfcmF0ZShzdHJ1Y3QgY2xrX2h3ICpodywgdW5zaWduZWQgbG9uZyByYXRlLAorCQkJ CSAgICAgdW5zaWduZWQgbG9uZyAqcGFyZW50X3JhdGUpCit7CisJc3RydWN0IHRjMzU4NzQ2ICp0 YzM1ODc0NiA9IGNsa19od190b190YzM1ODc0Nihodyk7CisKKwkqcGFyZW50X3JhdGUgPSB0YzM1 ODc0Ni0+cGxsX3JhdGU7CisKKwlyZXR1cm4gdGMzNTg3NDZfZmluZF9tY2xrX3NldHRpbmdzKHRj MzU4NzQ2LCByYXRlKTsKK30KKworc3RhdGljIGludCB0YzM1ODc0Nl9tY2xrX3NldF9yYXRlKHN0 cnVjdCBjbGtfaHcgKmh3LCB1bnNpZ25lZCBsb25nIHJhdGUsCisJCQkJICB1bnNpZ25lZCBsb25n IHBhcmVudF9yYXRlKQoreworCXN0cnVjdCB0YzM1ODc0NiAqdGMzNTg3NDYgPSBjbGtfaHdfdG9f dGMzNTg3NDYoaHcpOworCisJdGMzNTg3NDZfZmluZF9tY2xrX3NldHRpbmdzKHRjMzU4NzQ2LCBy YXRlKTsKKworCXJldHVybiB0YzM1ODc0Nl9tY2xrX2VuYWJsZShodyk7Cit9CisKK3N0YXRpYyBj b25zdCBzdHJ1Y3QgY2xrX29wcyB0YzM1ODc0Nl9tY2xrX29wcyA9IHsKKwkuZW5hYmxlID0gdGMz NTg3NDZfbWNsa19lbmFibGUsCisJLmRpc2FibGUgPSB0YzM1ODc0Nl9tY2xrX2Rpc2FibGUsCisJ LnJlY2FsY19yYXRlID0gdGMzNTg3NDZfcmVjYWxjX3JhdGUsCisJLnJvdW5kX3JhdGUgPSB0YzM1 ODc0Nl9tY2xrX3JvdW5kX3JhdGUsCisJLnNldF9yYXRlID0gdGMzNTg3NDZfbWNsa19zZXRfcmF0 ZSwKK307CisKK3N0YXRpYyBpbnQgdGMzNTg3NDZfc2V0dXBfbWNsa19wcm92aWRlcihzdHJ1Y3Qg dGMzNTg3NDYgKnRjMzU4NzQ2KQoreworCXN0cnVjdCBjbGtfaW5pdF9kYXRhIG1jbGtfaW5pdGRh dGEgPSB7IH07CisJc3RydWN0IGRldmljZSAqZGV2ID0gdGMzNTg3NDYtPnNkLmRldjsKKwljb25z dCBjaGFyICptY2xrX25hbWU7CisJaW50IGVycjsKKworCS8qIE1DTEsgY2xrIHByb3ZpZGVyIHN1 cHBvcnQgaXMgb3B0aW9uYWwgKi8KKwlpZiAoIWRldmljZV9wcm9wZXJ0eV9wcmVzZW50KGRldiwg IiNjbG9jay1jZWxscyIpKQorCQlyZXR1cm4gMDsKKworCS8qIEluaXQgdG8gaGlnaGVzdCBwb3Nz aWJlbCBNQ0xLICovCisJdGMzNTg3NDYtPm1jbGtfcG9zdGRpdiA9IDUxMjsKKwl0YzM1ODc0Ni0+ bWNsa19wcmVkaXYgPSA4OworCisJbWNsa19uYW1lID0gInRjMzU4NzQ2LW1jbGsiOworCWRldmlj ZV9wcm9wZXJ0eV9yZWFkX3N0cmluZyhkZXYsICJjbG9jay1vdXRwdXQtbmFtZXMiLCAmbWNsa19u YW1lKTsKKworCW1jbGtfaW5pdGRhdGEubmFtZSA9IG1jbGtfbmFtZTsKKwltY2xrX2luaXRkYXRh Lm9wcyA9ICZ0YzM1ODc0Nl9tY2xrX29wczsKKwl0YzM1ODc0Ni0+bWNsa19ody5pbml0ID0gJm1j bGtfaW5pdGRhdGE7CisKKwllcnIgPSBkZXZtX2Nsa19od19yZWdpc3RlcihkZXYsICZ0YzM1ODc0 Ni0+bWNsa19odyk7CisJaWYgKGVycikgeworCQlkZXZfZXJyKGRldiwgIkZhaWxlZCB0byByZWdp c3RlciBtY2xrIHByb3ZpZGVyXG4iKTsKKwkJcmV0dXJuIGVycjsKKwl9CisKKwllcnIgPSBkZXZt X29mX2Nsa19hZGRfaHdfcHJvdmlkZXIoZGV2LCBvZl9jbGtfaHdfc2ltcGxlX2dldCwKKwkJCQkJ ICAmdGMzNTg3NDYtPm1jbGtfaHcpOworCWlmIChlcnIpCisJCWRldl9lcnIoZGV2LCAiRmFpbGVk IHRvIGFkZCBtY2xrIHByb3ZpZGVyXG4iKTsKKworCXJldHVybiBlcnI7Cit9CisKK3N0YXRpYyBp bnQKK3RjMzU4NzQ2X2luaXRfc3ViZGV2KHN0cnVjdCB0YzM1ODc0NiAqdGMzNTg3NDYsIHN0cnVj dCBpMmNfY2xpZW50ICpjbGllbnQpCit7CisJc3RydWN0IHY0bDJfc3ViZGV2ICpzZCA9ICZ0YzM1 ODc0Ni0+c2Q7CisJaW50IGVycjsKKworCXY0bDJfaTJjX3N1YmRldl9pbml0KHNkLCBjbGllbnQs ICZ0YzM1ODc0Nl9vcHMpOworCXNkLT5mbGFncyB8PSBWNEwyX1NVQkRFVl9GTF9IQVNfREVWTk9E RTsKKwlzZC0+ZW50aXR5LmZ1bmN0aW9uID0gTUVESUFfRU5UX0ZfVklEX0lGX0JSSURHRTsKKwlz ZC0+ZW50aXR5Lm9wcyA9ICZ0YzM1ODc0Nl9lbnRpdHlfb3BzOworCisJdGMzNTg3NDYtPnBhZHNb VEMzNTg3NDZfU0lOS10uZmxhZ3MgPSBNRURJQV9QQURfRkxfU0lOSzsKKwl0YzM1ODc0Ni0+cGFk c1tUQzM1ODc0Nl9TT1VSQ0VdLmZsYWdzID0gTUVESUFfUEFEX0ZMX1NPVVJDRTsKKwllcnIgPSBt ZWRpYV9lbnRpdHlfcGFkc19pbml0KCZzZC0+ZW50aXR5LCBUQzM1ODc0Nl9OUl9QQURTLAorCQkJ CSAgICAgdGMzNTg3NDYtPnBhZHMpOworCWlmIChlcnIpCisJCXJldHVybiBlcnI7CisKKwllcnIg PSB2NGwyX3N1YmRldl9pbml0X2ZpbmFsaXplKHNkKTsKKwlpZiAoZXJyKQorCQltZWRpYV9lbnRp dHlfY2xlYW51cCgmc2QtPmVudGl0eSk7CisKKwlyZXR1cm4gZXJyOworfQorCitzdGF0aWMgaW50 Cit0YzM1ODc0Nl9pbml0X291dHB1dF9wb3J0KHN0cnVjdCB0YzM1ODc0NiAqdGMzNTg3NDYsIHVu c2lnbmVkIGxvbmcgcmVmY2xrKQoreworCXN0cnVjdCBkZXZpY2UgKmRldiA9IHRjMzU4NzQ2LT5z ZC5kZXY7CisJc3RydWN0IHY0bDJfZndub2RlX2VuZHBvaW50ICp2ZXA7CisJdW5zaWduZWQgbG9u ZyBjc2lfbGlua19yYXRlOworCXN0cnVjdCBmd25vZGVfaGFuZGxlICplcDsKKwl1bnNpZ25lZCBj aGFyIGNzaV9sYW5lczsKKwlpbnQgZXJyOworCisJZXAgPSBmd25vZGVfZ3JhcGhfZ2V0X2VuZHBv aW50X2J5X2lkKGRldl9md25vZGUoZGV2KSwgVEMzNTg3NDZfU09VUkNFLAorCQkJCQkgICAgIDAs IDApOworCWlmICghZXApIHsKKwkJZGV2X2VycihkZXYsICJNaXNzaW5nIGVuZHBvaW50IG5vZGVc biIpOworCQlyZXR1cm4gLUVJTlZBTDsKKwl9CisKKwkvKiBDdXJyZW50bHkgd2Ugb25seSBzdXBw b3J0ICdwYXJhbGxlbCBpbicgLT4gJ2NzaSBvdXQnICovCisJdmVwID0gJnRjMzU4NzQ2LT5jc2lf dmVwOworCXZlcC0+YnVzX3R5cGUgPSBWNEwyX01CVVNfQ1NJMl9EUEhZOworCWVyciA9IHY0bDJf Zndub2RlX2VuZHBvaW50X2FsbG9jX3BhcnNlKGVwLCB2ZXApOworCWZ3bm9kZV9oYW5kbGVfcHV0 KGVwKTsKKwlpZiAoZXJyKSB7CisJCWRldl9lcnIoZGV2LCAiRmFpbGVkIHRvIHBhcnNlIHNvdXJj ZSBlbmRwb2ludFxuIik7CisJCXJldHVybiBlcnI7CisJfQorCisJY3NpX2xhbmVzID0gdmVwLT5i dXMubWlwaV9jc2kyLm51bV9kYXRhX2xhbmVzOworCWlmIChjc2lfbGFuZXMgPT0gMCB8fCBjc2lf bGFuZXMgPiA0IHx8CisJICAgIHZlcC0+bnJfb2ZfbGlua19mcmVxdWVuY2llcyA9PSAwKSB7CisJ CWRldl9lcnIoZGV2LCAiZXJyb3I6IEludmFsaWQgQ1NJLTIgc2V0dGluZ3NcbiIpOworCQllcnIg PSAtRUlOVkFMOworCQlnb3RvIGVycjsKKwl9CisKKwkvKiBUT0RPOiBBZGQgc3VwcG9ydCB0byBo YW5kbGUgbXVsdGlwbGUgbGluayBmcmVxdWVuY2llcyAqLworCWNzaV9saW5rX3JhdGUgPSAodW5z aWduZWQgbG9uZyl2ZXAtPmxpbmtfZnJlcXVlbmNpZXNbMF07CisJdGMzNTg3NDYtPnBsbF9yYXRl ID0gdGMzNTg3NDZfZmluZF9wbGxfc2V0dGluZ3ModGMzNTg3NDYsIHJlZmNsaywKKwkJCQkJCQlj c2lfbGlua19yYXRlICogMik7CisJaWYgKCF0YzM1ODc0Ni0+cGxsX3JhdGUpIHsKKwkJZXJyID0g LUVJTlZBTDsKKwkJZ290byBlcnI7CisJfQorCisJZXJyID0gcGh5X21pcGlfZHBoeV9nZXRfZGVm YXVsdF9jb25maWdfZm9yX2hzY2xrKHRjMzU4NzQ2LT5wbGxfcmF0ZSwKKwkJCQkJCWNzaV9sYW5l cywgJnRjMzU4NzQ2LT5kcGh5X2NmZyk7CisJaWYgKGVycikKKwkJZ290byBlcnI7CisKKwl0YzM1 ODc0Ni0+dmJfc2l6ZSA9IFRDMzU4NzQ2X1ZCX0RFRkFVTFRfU0laRTsKKworCXJldHVybiAwOwor CitlcnI6CisJdjRsMl9md25vZGVfZW5kcG9pbnRfZnJlZSh2ZXApOworCisJcmV0dXJuIGVycjsK K30KKworc3RhdGljIGludCB0YzM1ODc0Nl9pbml0X2h3KHN0cnVjdCB0YzM1ODc0NiAqdGMzNTg3 NDYpCit7CisJc3RydWN0IGRldmljZSAqZGV2ID0gdGMzNTg3NDYtPnNkLmRldjsKKwl1bnNpZ25l ZCBpbnQgY2hpcGlkOworCXUzMiB2YWw7CisJaW50IGVycjsKKworCWVyciA9IHBtX3J1bnRpbWVf cmVzdW1lX2FuZF9nZXQoZGV2KTsKKwlpZiAoZXJyIDwgMCkgeworCQlkZXZfZXJyKGRldiwgIkZh aWxlZCB0byByZXN1bWUgdGhlIGRldmljZVxuIik7CisJCXJldHVybiBlcnI7CisJfQorCisJIC8q IEVuc3VyZSB0aGF0IENTSSBpbnRlcmZhY2UgaXMgcHV0IGludG8gTFAtMTEgc3RhdGUgKi8KKwll cnIgPSB0YzM1ODc0Nl9zd19yZXNldCh0YzM1ODc0Nik7CisJaWYgKGVycikgeworCQlwbV9ydW50 aW1lX3B1dF9zeW5jKGRldik7CisJCWRldl9lcnIoZGV2LCAiRmFpbGVkIHRvIHJlc2V0IHRoZSBk ZXZpY2VcbiIpOworCQlyZXR1cm4gZXJyOworCX0KKworCWVyciA9IHRjMzU4NzQ2X3JlYWQodGMz NTg3NDYsIENISVBJRF9SRUcsICZ2YWwpOworCXBtX3J1bnRpbWVfbWFya19sYXN0X2J1c3koZGV2 KTsKKwlwbV9ydW50aW1lX3B1dF9zeW5jX2F1dG9zdXNwZW5kKGRldik7CisJaWYgKGVycikKKwkJ cmV0dXJuIC1FTk9ERVY7CisKKwljaGlwaWQgPSBGSUVMRF9HRVQoQ0hJUElELCB2YWwpOworCWlm IChjaGlwaWQgIT0gMHg0NCkgeworCQlkZXZfZXJyKGRldiwgIkludmFsaWQgY2hpcGlkIDB4JTAy eFxuIiwgY2hpcGlkKTsKKwkJcmV0dXJuIC1FTk9ERVY7CisJfQorCisJcmV0dXJuIDA7Cit9CisK K3N0YXRpYyBpbnQgdGMzNTg3NDZfaW5pdF9jb250cm9scyhzdHJ1Y3QgdGMzNTg3NDYgKnRjMzU4 NzQ2KQoreworCXU2NCAqbGlua19mcmVxdWVuY2llcyA9IHRjMzU4NzQ2LT5jc2lfdmVwLmxpbmtf ZnJlcXVlbmNpZXM7CisJc3RydWN0IHY0bDJfY3RybCAqY3RybDsKKwlpbnQgZXJyOworCisJZXJy ID0gdjRsMl9jdHJsX2hhbmRsZXJfaW5pdCgmdGMzNTg3NDYtPmN0cmxfaGRsLCAxKTsKKwlpZiAo ZXJyKQorCQlyZXR1cm4gZXJyOworCisJLyoKKwkgKiBUaGUgZHJpdmVyIGN1cnJlbnRseSBzdXBw b3J0cyBvbmx5IG9uZSBsaW5rLWZyZXF1ZW5jeSwgcmVnYXJkbGVzcyBvZgorCSAqIHRoZSBpbnB1 dCBmcm9tIHRoZSBmaXJtd2FyZSwgc2VlOiB0YzM1ODc0Nl9pbml0X291dHB1dF9wb3J0KCkuIFNv CisJICogcmVwb3J0IG9ubHkgdGhlIGZpcnN0IGZyZXF1ZW5jeSBmcm9tIHRoZSBhcnJheSBvZiBw b3NzaWJsZSBnaXZlbgorCSAqIGZyZXF1ZW5jaWVzLgorCSAqLworCWN0cmwgPSB2NGwyX2N0cmxf bmV3X2ludF9tZW51KCZ0YzM1ODc0Ni0+Y3RybF9oZGwsIE5VTEwsCisJCQkJICAgICAgVjRMMl9D SURfTElOS19GUkVRLCAwLCAwLAorCQkJCSAgICAgIGxpbmtfZnJlcXVlbmNpZXMpOworCWlmIChj dHJsKQorCQljdHJsLT5mbGFncyB8PSBWNEwyX0NUUkxfRkxBR19SRUFEX09OTFk7CisKKwllcnIg PSB0YzM1ODc0Ni0+Y3RybF9oZGwuZXJyb3I7CisJaWYgKGVycikgeworCQl2NGwyX2N0cmxfaGFu ZGxlcl9mcmVlKCZ0YzM1ODc0Ni0+Y3RybF9oZGwpOworCQlyZXR1cm4gZXJyOworCX0KKworCXRj MzU4NzQ2LT5zZC5jdHJsX2hhbmRsZXIgPSAmdGMzNTg3NDYtPmN0cmxfaGRsOworCisJcmV0dXJu IDA7Cit9CisKK3N0YXRpYyBpbnQgdGMzNTg3NDZfbm90aWZ5X2JvdW5kKHN0cnVjdCB2NGwyX2Fz eW5jX25vdGlmaWVyICpub3RpZmllciwKKwkJCQkgc3RydWN0IHY0bDJfc3ViZGV2ICpzZCwKKwkJ CQkgc3RydWN0IHY0bDJfYXN5bmNfc3ViZGV2ICphc2QpCit7CisJc3RydWN0IHRjMzU4NzQ2ICp0 YzM1ODc0NiA9CisJCWNvbnRhaW5lcl9vZihub3RpZmllciwgc3RydWN0IHRjMzU4NzQ2LCBub3Rp Zmllcik7CisJdTMyIGZsYWdzID0gTUVESUFfTE5LX0ZMX0VOQUJMRUQgfCBNRURJQV9MTktfRkxf SU1NVVRBQkxFOworCXN0cnVjdCBtZWRpYV9wYWQgKnNpbmsgPSAmdGMzNTg3NDYtPnBhZHNbVEMz NTg3NDZfU0lOS107CisKKwlyZXR1cm4gdjRsMl9jcmVhdGVfZndub2RlX2xpbmtzX3RvX3BhZChz ZCwgc2luaywgZmxhZ3MpOworfQorCitzdGF0aWMgY29uc3Qgc3RydWN0IHY0bDJfYXN5bmNfbm90 aWZpZXJfb3BlcmF0aW9ucyB0YzM1ODc0Nl9ub3RpZnlfb3BzID0geworCS5ib3VuZCA9IHRjMzU4 NzQ2X25vdGlmeV9ib3VuZCwKK307CisKK3N0YXRpYyBpbnQgdGMzNTg3NDZfYXN5bmNfcmVnaXN0 ZXIoc3RydWN0IHRjMzU4NzQ2ICp0YzM1ODc0NikKK3sKKwlzdHJ1Y3QgdjRsMl9md25vZGVfZW5k cG9pbnQgdmVwID0geworCQkuYnVzX3R5cGUgPSBWNEwyX01CVVNfUEFSQUxMRUwsCisJfTsKKwlz dHJ1Y3QgdjRsMl9hc3luY19zdWJkZXYgKmFzZDsKKwlzdHJ1Y3QgZndub2RlX2hhbmRsZSAqZXA7 CisJaW50IGVycjsKKworCWVwID0gZndub2RlX2dyYXBoX2dldF9lbmRwb2ludF9ieV9pZChkZXZf Zndub2RlKHRjMzU4NzQ2LT5zZC5kZXYpLAorCQkJCQkgICAgIFRDMzU4NzQ2X1NJTkssIDAsIDAp OworCWlmICghZXApCisJCXJldHVybiAtRU5PVENPTk47CisKKwllcnIgPSB2NGwyX2Z3bm9kZV9l bmRwb2ludF9wYXJzZShlcCwgJnZlcCk7CisJaWYgKGVycikgeworCQlmd25vZGVfaGFuZGxlX3B1 dChlcCk7CisJCXJldHVybiBlcnI7CisJfQorCisJdjRsMl9hc3luY19uZl9pbml0KCZ0YzM1ODc0 Ni0+bm90aWZpZXIpOworCWFzZCA9IHY0bDJfYXN5bmNfbmZfYWRkX2Z3bm9kZV9yZW1vdGUoJnRj MzU4NzQ2LT5ub3RpZmllciwgZXAsCisJCQkJCSAgICAgIHN0cnVjdCB2NGwyX2FzeW5jX3N1YmRl dik7CisJZndub2RlX2hhbmRsZV9wdXQoZXApOworCisJaWYgKElTX0VSUihhc2QpKSB7CisJCWVy ciA9IFBUUl9FUlIoYXNkKTsKKwkJZ290byBlcnJfY2xlYW51cDsKKwl9CisKKwl0YzM1ODc0Ni0+ bm90aWZpZXIub3BzID0gJnRjMzU4NzQ2X25vdGlmeV9vcHM7CisKKwllcnIgPSB2NGwyX2FzeW5j X3N1YmRldl9uZl9yZWdpc3RlcigmdGMzNTg3NDYtPnNkLCAmdGMzNTg3NDYtPm5vdGlmaWVyKTsK KwlpZiAoZXJyKQorCQlnb3RvIGVycl9jbGVhbnVwOworCisJdGMzNTg3NDYtPnNkLmZ3bm9kZSA9 IGZ3bm9kZV9ncmFwaF9nZXRfZW5kcG9pbnRfYnlfaWQoCisJCWRldl9md25vZGUodGMzNTg3NDYt PnNkLmRldiksIFRDMzU4NzQ2X1NPVVJDRSwgMCwgMCk7CisKKwllcnIgPSB2NGwyX2FzeW5jX3Jl Z2lzdGVyX3N1YmRldigmdGMzNTg3NDYtPnNkKTsKKwlpZiAoZXJyKQorCQlnb3RvIGVycl91bnJl Z2lzdGVyOworCisJcmV0dXJuIDA7CisKK2Vycl91bnJlZ2lzdGVyOgorCWZ3bm9kZV9oYW5kbGVf cHV0KHRjMzU4NzQ2LT5zZC5md25vZGUpOworCXY0bDJfYXN5bmNfbmZfdW5yZWdpc3RlcigmdGMz NTg3NDYtPm5vdGlmaWVyKTsKK2Vycl9jbGVhbnVwOgorCXY0bDJfYXN5bmNfbmZfY2xlYW51cCgm dGMzNTg3NDYtPm5vdGlmaWVyKTsKKworCXJldHVybiBlcnI7Cit9CisKK3N0YXRpYyBpbnQgdGMz NTg3NDZfcHJvYmUoc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCkKK3sKKwlzdHJ1Y3QgZGV2aWNl ICpkZXYgPSAmY2xpZW50LT5kZXY7CisJc3RydWN0IHRjMzU4NzQ2ICp0YzM1ODc0NjsKKwl1bnNp Z25lZCBsb25nIHJlZmNsazsKKwl1bnNpZ25lZCBpbnQgaTsKKwlpbnQgZXJyOworCisJdGMzNTg3 NDYgPSBkZXZtX2t6YWxsb2MoJmNsaWVudC0+ZGV2LCBzaXplb2YoKnRjMzU4NzQ2KSwgR0ZQX0tF Uk5FTCk7CisJaWYgKCF0YzM1ODc0NikKKwkJcmV0dXJuIC1FTk9NRU07CisKKwl0YzM1ODc0Ni0+ cmVnbWFwID0gZGV2bV9yZWdtYXBfaW5pdF9pMmMoY2xpZW50LCAmdGMzNTg3NDZfcmVnbWFwX2Nv bmZpZyk7CisJaWYgKElTX0VSUih0YzM1ODc0Ni0+cmVnbWFwKSkKKwkJcmV0dXJuIGRldl9lcnJf cHJvYmUoZGV2LCBQVFJfRVJSKHRjMzU4NzQ2LT5yZWdtYXApLAorCQkJCSAgICAgIkZhaWxlZCB0 byBpbml0IHJlZ21hcFxuIik7CisKKwl0YzM1ODc0Ni0+cmVmY2xrID0gZGV2bV9jbGtfZ2V0KGRl diwgInJlZmNsayIpOworCWlmIChJU19FUlIodGMzNTg3NDYtPnJlZmNsaykpCisJCXJldHVybiBk ZXZfZXJyX3Byb2JlKGRldiwgUFRSX0VSUih0YzM1ODc0Ni0+cmVmY2xrKSwKKwkJCQkgICAgICJG YWlsZWQgdG8gZ2V0IHJlZmNsa1xuIik7CisKKwllcnIgPSBjbGtfcHJlcGFyZV9lbmFibGUodGMz NTg3NDYtPnJlZmNsayk7CisJaWYgKGVycikKKwkJcmV0dXJuIGRldl9lcnJfcHJvYmUoZGV2LCBl cnIsCisJCQkJICAgICAiRmFpbGVkIHRvIGVuYWJsZSByZWZjbGtcbiIpOworCisJcmVmY2xrID0g Y2xrX2dldF9yYXRlKHRjMzU4NzQ2LT5yZWZjbGspOworCWNsa19kaXNhYmxlX3VucHJlcGFyZSh0 YzM1ODc0Ni0+cmVmY2xrKTsKKworCWlmIChyZWZjbGsgPCA2ICogSFpfUEVSX01IWiB8fCByZWZj bGsgPiA0MCAqIEhaX1BFUl9NSFopCisJCXJldHVybiBkZXZfZXJyX3Byb2JlKGRldiwgLUVJTlZB TCwgIkludmFsaWQgcmVmY2xrIHJhbmdlXG4iKTsKKworCWZvciAoaSA9IDA7IGkgPCBBUlJBWV9T SVpFKHRjMzU4NzQ2X3N1cHBsaWVzKTsgaSsrKQorCQl0YzM1ODc0Ni0+c3VwcGxpZXNbaV0uc3Vw cGx5ID0gdGMzNTg3NDZfc3VwcGxpZXNbaV07CisKKwllcnIgPSBkZXZtX3JlZ3VsYXRvcl9idWxr X2dldChkZXYsIEFSUkFZX1NJWkUodGMzNTg3NDZfc3VwcGxpZXMpLAorCQkJCSAgICAgIHRjMzU4 NzQ2LT5zdXBwbGllcyk7CisJaWYgKGVycikKKwkJcmV0dXJuIGRldl9lcnJfcHJvYmUoZGV2LCBl cnIsICJGYWlsZWQgdG8gZ2V0IHN1cHBsaWVzXG4iKTsKKworCXRjMzU4NzQ2LT5yZXNldF9ncGlv ID0gZGV2bV9ncGlvZF9nZXRfb3B0aW9uYWwoZGV2LCAicmVzZXQiLAorCQkJCQkJICAgICAgIEdQ SU9EX09VVF9ISUdIKTsKKwlpZiAoSVNfRVJSKHRjMzU4NzQ2LT5yZXNldF9ncGlvKSkKKwkJcmV0 dXJuIGRldl9lcnJfcHJvYmUoZGV2LCBQVFJfRVJSKHRjMzU4NzQ2LT5yZXNldF9ncGlvKSwKKwkJ CQkgICAgICJGYWlsZWQgdG8gZ2V0IHJlc2V0LWdwaW9zXG4iKTsKKworCWVyciA9IHRjMzU4NzQ2 X2luaXRfc3ViZGV2KHRjMzU4NzQ2LCBjbGllbnQpOworCWlmIChlcnIpCisJCXJldHVybiBkZXZf ZXJyX3Byb2JlKGRldiwgZXJyLCAiRmFpbGVkIHRvIGluaXQgc3ViZGV2XG4iKTsKKworCWVyciA9 IHRjMzU4NzQ2X2luaXRfb3V0cHV0X3BvcnQodGMzNTg3NDYsIHJlZmNsayk7CisJaWYgKGVycikK KwkJZ290byBlcnJfc3ViZGV2OworCisJLyoKKwkgKiBLZWVwIHRoaXMgb3JkZXIgc2luY2Ugd2Ug bmVlZCB0aGUgb3V0cHV0IHBvcnQgbGluay1mcmVxdWVuY2llcworCSAqIGluZm9ybWF0aW9uLgor CSAqLworCWVyciA9IHRjMzU4NzQ2X2luaXRfY29udHJvbHModGMzNTg3NDYpOworCWlmIChlcnIp CisJCWdvdG8gZXJyX2Z3bm9kZTsKKworCWRldl9zZXRfZHJ2ZGF0YShkZXYsIHRjMzU4NzQ2KTsK KworCS8qIFNldCB0byAxc2VjIHRvIGdpdmUgdGhlIHN0cmVhbSByZWNvbmZpZ3VyYXRpb24gZW5v dWdoIHRpbWUgKi8KKwlwbV9ydW50aW1lX3NldF9hdXRvc3VzcGVuZF9kZWxheShkZXYsIDEwMDAp OworCXBtX3J1bnRpbWVfdXNlX2F1dG9zdXNwZW5kKGRldik7CisJcG1fcnVudGltZV9lbmFibGUo ZGV2KTsKKworCWVyciA9IHRjMzU4NzQ2X2luaXRfaHcodGMzNTg3NDYpOworCWlmIChlcnIpCisJ CWdvdG8gZXJyX3BtOworCisJZXJyID0gdGMzNTg3NDZfc2V0dXBfbWNsa19wcm92aWRlcih0YzM1 ODc0Nik7CisJaWYgKGVycikKKwkJZ290byBlcnJfcG07CisKKwllcnIgPSB0YzM1ODc0Nl9hc3lu Y19yZWdpc3Rlcih0YzM1ODc0Nik7CisJaWYgKGVyciA8IDApCisJCWdvdG8gZXJyX3BtOworCisJ ZGV2X2RiZyhkZXYsICIlcyBmb3VuZCBAIDB4JXggKCVzKVxuIiwgY2xpZW50LT5uYW1lLAorCQlj bGllbnQtPmFkZHIsIGNsaWVudC0+YWRhcHRlci0+bmFtZSk7CisKKwlyZXR1cm4gMDsKKworZXJy X3BtOgorCXBtX3J1bnRpbWVfZGlzYWJsZShkZXYpOworCXBtX3J1bnRpbWVfc2V0X3N1c3BlbmRl ZChkZXYpOworCXBtX3J1bnRpbWVfZG9udF91c2VfYXV0b3N1c3BlbmQoZGV2KTsKKwl2NGwyX2N0 cmxfaGFuZGxlcl9mcmVlKCZ0YzM1ODc0Ni0+Y3RybF9oZGwpOworZXJyX2Z3bm9kZToKKwl2NGwy X2Z3bm9kZV9lbmRwb2ludF9mcmVlKCZ0YzM1ODc0Ni0+Y3NpX3ZlcCk7CitlcnJfc3ViZGV2Ogor CXY0bDJfc3ViZGV2X2NsZWFudXAoJnRjMzU4NzQ2LT5zZCk7CisJbWVkaWFfZW50aXR5X2NsZWFu dXAoJnRjMzU4NzQ2LT5zZC5lbnRpdHkpOworCisJcmV0dXJuIGVycjsKK30KKworc3RhdGljIGlu dCB0YzM1ODc0Nl9yZW1vdmUoc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCkKK3sKKwlzdHJ1Y3Qg djRsMl9zdWJkZXYgKnNkID0gaTJjX2dldF9jbGllbnRkYXRhKGNsaWVudCk7CisJc3RydWN0IHRj MzU4NzQ2ICp0YzM1ODc0NiA9IHRvX3RjMzU4NzQ2KHNkKTsKKworCXY0bDJfc3ViZGV2X2NsZWFu dXAoc2QpOworCXY0bDJfY3RybF9oYW5kbGVyX2ZyZWUoJnRjMzU4NzQ2LT5jdHJsX2hkbCk7CisJ djRsMl9md25vZGVfZW5kcG9pbnRfZnJlZSgmdGMzNTg3NDYtPmNzaV92ZXApOworCXY0bDJfYXN5 bmNfbmZfdW5yZWdpc3RlcigmdGMzNTg3NDYtPm5vdGlmaWVyKTsKKwl2NGwyX2FzeW5jX25mX2Ns ZWFudXAoJnRjMzU4NzQ2LT5ub3RpZmllcik7CisJZndub2RlX2hhbmRsZV9wdXQoc2QtPmZ3bm9k ZSk7CisJdjRsMl9hc3luY191bnJlZ2lzdGVyX3N1YmRldihzZCk7CisJbWVkaWFfZW50aXR5X2Ns ZWFudXAoJnNkLT5lbnRpdHkpOworCisJcG1fcnVudGltZV9kaXNhYmxlKHNkLT5kZXYpOworCXBt X3J1bnRpbWVfc2V0X3N1c3BlbmRlZChzZC0+ZGV2KTsKKwlwbV9ydW50aW1lX2RvbnRfdXNlX2F1 dG9zdXNwZW5kKHNkLT5kZXYpOworCisJcmV0dXJuIDA7Cit9CisKK3N0YXRpYyBpbnQgdGMzNTg3 NDZfc3VzcGVuZChzdHJ1Y3QgZGV2aWNlICpkZXYpCit7CisJc3RydWN0IHRjMzU4NzQ2ICp0YzM1 ODc0NiA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOworCWludCBlcnI7CisKKwljbGtfZGlzYWJsZV91 bnByZXBhcmUodGMzNTg3NDYtPnJlZmNsayk7CisKKwllcnIgPSByZWd1bGF0b3JfYnVsa19kaXNh YmxlKEFSUkFZX1NJWkUodGMzNTg3NDZfc3VwcGxpZXMpLAorCQkJCSAgICAgdGMzNTg3NDYtPnN1 cHBsaWVzKTsKKwlpZiAoZXJyKQorCQljbGtfcHJlcGFyZV9lbmFibGUodGMzNTg3NDYtPnJlZmNs ayk7CisKKwlyZXR1cm4gZXJyOworfQorCitzdGF0aWMgaW50IHRjMzU4NzQ2X3Jlc3VtZShzdHJ1 Y3QgZGV2aWNlICpkZXYpCit7CisJc3RydWN0IHRjMzU4NzQ2ICp0YzM1ODc0NiA9IGRldl9nZXRf ZHJ2ZGF0YShkZXYpOworCWludCBlcnI7CisKKwlncGlvZF9zZXRfdmFsdWUodGMzNTg3NDYtPnJl c2V0X2dwaW8sIDEpOworCisJZXJyID0gcmVndWxhdG9yX2J1bGtfZW5hYmxlKEFSUkFZX1NJWkUo dGMzNTg3NDZfc3VwcGxpZXMpLAorCQkJCSAgICB0YzM1ODc0Ni0+c3VwcGxpZXMpOworCWlmIChl cnIpCisJCXJldHVybiBlcnI7CisKKwkvKiBtaW4uIDIwMG5zICovCisJdXNsZWVwX3JhbmdlKDEw LCAyMCk7CisKKwlncGlvZF9zZXRfdmFsdWUodGMzNTg3NDYtPnJlc2V0X2dwaW8sIDApOworCisJ ZXJyID0gY2xrX3ByZXBhcmVfZW5hYmxlKHRjMzU4NzQ2LT5yZWZjbGspOworCWlmIChlcnIpCisJ CWdvdG8gZXJyOworCisJLyogbWluLiA3MDB1cyAuLi4gMW1zICovCisJdXNsZWVwX3JhbmdlKDEw MDAsIDE1MDApOworCisJLyoKKwkgKiBFbmFibGUgdGhlIFBMTCBoZXJlIHNpbmNlIGl0IGNhbiBi ZSBjYWxsZWQgYnkgdGhlIGNsay1mcmFtZXdvcmsgb3IgYnkKKwkgKiB0aGUgLnNfc3RyZWFtKCkg Y2FsbGJhY2suIFNvIHRoaXMgaXMgdGhlIGNvbW1vbiBwbGFjZSBmb3IgYm90aC4KKwkgKi8KKwll cnIgPSB0YzM1ODc0Nl9hcHBseV9wbGxfY29uZmlnKHRjMzU4NzQ2KTsKKwlpZiAoZXJyKQorCQln b3RvIGVycl9jbGs7CisKKwlyZXR1cm4gMDsKKworZXJyX2NsazoKKwljbGtfZGlzYWJsZV91bnBy ZXBhcmUodGMzNTg3NDYtPnJlZmNsayk7CitlcnI6CisJcmVndWxhdG9yX2J1bGtfZGlzYWJsZShB UlJBWV9TSVpFKHRjMzU4NzQ2X3N1cHBsaWVzKSwKKwkJCSAgICAgICB0YzM1ODc0Ni0+c3VwcGxp ZXMpOworCXJldHVybiBlcnI7Cit9CisKK0RFRklORV9SVU5USU1FX0RFVl9QTV9PUFModGMzNTg3 NDZfcG1fb3BzLCB0YzM1ODc0Nl9zdXNwZW5kLAorCQkJICB0YzM1ODc0Nl9yZXN1bWUsIE5VTEwp OworCitzdGF0aWMgY29uc3Qgc3RydWN0IG9mX2RldmljZV9pZCBfX21heWJlX3VudXNlZCB0YzM1 ODc0Nl9vZl9tYXRjaFtdID0geworCXsgLmNvbXBhdGlibGUgPSAidG9zaGliYSx0YzM1ODc0NiIg fSwKKwl7IH0sCit9OworTU9EVUxFX0RFVklDRV9UQUJMRShvZiwgdGMzNTg3NDZfb2ZfbWF0Y2gp OworCitzdGF0aWMgc3RydWN0IGkyY19kcml2ZXIgdGMzNTg3NDZfZHJpdmVyID0geworCS5kcml2 ZXIgPSB7CisJCS5uYW1lID0gInRjMzU4NzQ2IiwKKwkJLnBtID0gcG1fcHRyKCZ0YzM1ODc0Nl9w bV9vcHMpLAorCQkub2ZfbWF0Y2hfdGFibGUgPSB0YzM1ODc0Nl9vZl9tYXRjaCwKKwl9LAorCS5w cm9iZV9uZXcgPSB0YzM1ODc0Nl9wcm9iZSwKKwkucmVtb3ZlID0gdGMzNTg3NDZfcmVtb3ZlLAor fTsKKworbW9kdWxlX2kyY19kcml2ZXIodGMzNTg3NDZfZHJpdmVyKTsKKworTU9EVUxFX0RFU0NS SVBUSU9OKCJUb3NoaWJhIFRDMzU4NzQ2IFBhcmFsbGVsIHRvIENTSS0yIGJyaWRnZSBkcml2ZXIi KTsKK01PRFVMRV9BVVRIT1IoIk1hcmNvIEZlbHNjaCA8a2VybmVsQHBlbmd1dHJvbml4LmRlPiIp OworTU9EVUxFX0xJQ0VOU0UoIkdQTCIpOwotLSAKMi4zMC4yCgoKLS0gCmxpbnV4LXBoeSBtYWls aW5nIGxpc3QKbGludXgtcGh5QGxpc3RzLmluZnJhZGVhZC5vcmcKaHR0cHM6Ly9saXN0cy5pbmZy YWRlYWQub3JnL21haWxtYW4vbGlzdGluZm8vbGludXgtcGh5Cg==