From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D0E1EC388F2 for ; Fri, 6 Nov 2020 16:58:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5713122202 for ; Fri, 6 Nov 2020 16:58:48 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=protonmail.com header.i=@protonmail.com header.b="DUwb13uO" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727676AbgKFQ6r (ORCPT ); Fri, 6 Nov 2020 11:58:47 -0500 Received: from mail-02.mail-europe.com ([51.89.119.103]:42924 "EHLO mail-02.mail-europe.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726953AbgKFQ6q (ORCPT ); Fri, 6 Nov 2020 11:58:46 -0500 Date: Fri, 06 Nov 2020 16:58:32 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com; s=protonmail; t=1604681914; bh=xsLf4nlDUCOrHrV/3/k0x1f+6hMboUUSPp1jdSsv+no=; h=Date:To:From:Cc:Reply-To:Subject:In-Reply-To:References:From; b=DUwb13uOJR9og0cykF/L+IpWlgwsipj1az9taG7IzIPY+3JWQi2i16lmGshdGoMew hGnkjYlKABniqvg6xeLjC6svCOMUXE0uO2AG+tTs6d2OxxfmUYhtD1I5Rw7M1dY0TT R0qbFHLEksBJ60mSDrjKp8QBs63pr3y9NqxeX3PU= To: Pavel Machek , Dan Murphy , Bjorn Andersson , Andy Gross , Rob Herring From: =?utf-8?Q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?= Cc: linux-leds@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, Brian Masney , Luca Weiss , Russell King , Georgi Djakov , linux-kernel@vger.kernel.org, lkcamp@lists.libreplanetbr.org, andrealmeid@collabora.com Reply-To: =?utf-8?Q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?= Subject: [RFC PATCH 1/3] leds: Add driver for QPNP flash led Message-ID: <20201106165737.1029106-2-nfraprado@protonmail.com> In-Reply-To: <20201106165737.1029106-1-nfraprado@protonmail.com> References: <20201106165737.1029106-1-nfraprado@protonmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org Add driver for the QPNP flash LED. It works over SPMI and is part of the PM8941 PMIC. Signed-off-by: N=C3=ADcolas F. R. A. Prado --- drivers/leds/Kconfig | 9 + drivers/leds/Makefile | 1 + drivers/leds/leds-qpnp.c | 1351 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 1361 insertions(+) create mode 100644 drivers/leds/leds-qpnp.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 849d3c5f908e..ca5f6e81c064 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -928,6 +928,15 @@ config LEDS_ACER_A500 =09 This option enables support for the Power Button LED of =09 Acer Iconia Tab A500. =20 +config LEDS_QPNP +=09tristate "Support for QPNP LEDs" +=09depends on SPMI +=09help +=09 This driver supports the flash/torch led of Qualcomm PNP PMIC. + +=09 To compile this driver as a module, choose M here: the module will +=09 be called leds-qpnp. + comment "LED Triggers" source "drivers/leds/trigger/Kconfig" =20 diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 73e603e1727e..055360240801 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -93,6 +93,7 @@ obj-$(CONFIG_LEDS_TURRIS_OMNIA)=09=09+=3D leds-turris-omn= ia.o obj-$(CONFIG_LEDS_WM831X_STATUS)=09+=3D leds-wm831x-status.o obj-$(CONFIG_LEDS_WM8350)=09=09+=3D leds-wm8350.o obj-$(CONFIG_LEDS_WRAP)=09=09=09+=3D leds-wrap.o +obj-$(CONFIG_LEDS_QPNP)=09=09=09+=3D leds-qpnp.o =20 # LED SPI Drivers obj-$(CONFIG_LEDS_CR0014114)=09=09+=3D leds-cr0014114.o diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c new file mode 100644 index 000000000000..9970688264aa --- /dev/null +++ b/drivers/leds/leds-qpnp.c @@ -0,0 +1,1351 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FLASH_SAFETY_TIMER=090x40 +#define FLASH_MAX_CURR=09=090x41 +#define FLASH_LED_0_CURR=090x42 +#define FLASH_LED_1_CURR=090x43 +#define FLASH_CLAMP_CURR=090x44 +#define FLASH_LED_TMR_CTRL=090x48 +#define FLASH_HEADROOM=09=090x4A +#define FLASH_STARTUP_DELAY=090x4B +#define FLASH_MASK_ENABLE=090x4C +#define FLASH_VREG_OK_FORCE=090x4F +#define FLASH_ENABLE_CONTROL=090x46 +#define FLASH_LED_STROBE_CTRL=090x47 +#define FLASH_LED_UNLOCK_SECURE=090xD0 +#define FLASH_LED_TORCH=09=090xE4 +#define FLASH_FAULT_DETECT=090x51 +#define FLASH_RAMP_RATE=09=090x54 +#define FLASH_PERIPHERAL_SUBTYPE=090x05 +#define FLASH_VPH_PWR_DROOP=090x5A + +#define FLASH_MAX_LEVEL=09=09=090x4F +#define TORCH_MAX_LEVEL=09=09=090x0F +#define=09FLASH_NO_MASK=09=09=090x00 + +#define FLASH_MASK_1=09=09=090x20 +#define FLASH_MASK_REG_MASK=09=090xE0 +#define FLASH_HEADROOM_MASK=09=090x03 +#define FLASH_SAFETY_TIMER_MASK=09=090x7F +#define FLASH_CURRENT_MASK=09=090xFF +#define FLASH_MAX_CURRENT_MASK=09=090x7F +#define FLASH_TMR_MASK=09=09=090x03 +#define FLASH_TMR_WATCHDOG=09=090x03 +#define FLASH_TMR_SAFETY=09=090x00 +#define FLASH_FAULT_DETECT_MASK=09=090X80 +#define FLASH_HW_VREG_OK=09=090x40 +#define FLASH_VREG_MASK=09=09=090xC0 +#define FLASH_STARTUP_DLY_MASK=09=090x02 +#define FLASH_RAMP_RATE_MASK=09=090xBF +#define FLASH_VPH_PWR_DROOP_MASK=090xF3 + +#define FLASH_ENABLE_ALL=09=090xE0 +#define FLASH_ENABLE_MODULE=09=090x80 +#define FLASH_ENABLE_MODULE_MASK=090x80 +#define FLASH_DISABLE_ALL=09=090x00 +#define FLASH_ENABLE_MASK=09=090xE0 +#define FLASH_ENABLE_LED_0=09=090xC0 +#define FLASH_ENABLE_LED_1=09=090xA0 +#define FLASH_INIT_MASK=09=09=090xE0 +#define FLASH_SELFCHECK_ENABLE=09=090x80 +#define FLASH_SELFCHECK_DISABLE=09=090x00 + +#define FLASH_STROBE_SW=09=09=090xC0 +#define FLASH_STROBE_HW=09=09=090x04 +#define FLASH_STROBE_MASK=09=090xC7 +#define FLASH_LED_0_OUTPUT=09=090x80 +#define FLASH_LED_1_OUTPUT=09=090x40 + +#define FLASH_CURRENT_PRGM_MIN=09=091 +#define FLASH_CURRENT_PRGM_SHIFT=091 +#define FLASH_CURRENT_MAX=09=090x4F +#define FLASH_CURRENT_TORCH=09=090x07 + +#define FLASH_DURATION_200ms=09=090x13 +#define FLASH_CLAMP_200mA=09=090x0F + +#define FLASH_TORCH_MASK=09=090x03 +#define FLASH_LED_TORCH_ENABLE=09=090x00 +#define FLASH_LED_TORCH_DISABLE=09=090x03 +#define FLASH_UNLOCK_SECURE=09=090xA5 +#define FLASH_SECURE_MASK=09=090xFF + +#define FLASH_SUBTYPE_DUAL=09=090x01 +#define FLASH_SUBTYPE_SINGLE=09=090x02 + +#define LED_TRIGGER_DEFAULT=09=09"none" + +/** + * enum qpnp_leds - QPNP supported led ids + * @QPNP_ID_WLED - White led backlight + */ +enum qpnp_leds { +=09QPNP_ID_FLASH1_LED0 =3D 1, +=09QPNP_ID_FLASH1_LED1, +=09QPNP_ID_MAX, +}; + +enum flash_headroom { +=09HEADROOM_250mV =3D 0, +=09HEADROOM_300mV, +=09HEADROOM_400mV, +=09HEADROOM_500mV, +}; + +enum flash_startup_dly { +=09DELAY_10us =3D 0, +=09DELAY_32us, +=09DELAY_64us, +=09DELAY_128us, +}; + +static u8 flash_debug_regs[] =3D { +=090x40, 0x41, 0x42, 0x43, 0x44, 0x48, 0x49, 0x4b, 0x4c, +=090x4f, 0x46, 0x47, +}; + +/** + * flash_config_data - flash configuration data + * @current_prgm - current to be programmed, scaled by max level + * @clamp_curr - clamp current to use + * @headroom - headroom value to use + * @duration - duration of the flash + * @enable_module - enable address for particular flash + * @trigger_flash - trigger flash + * @startup_dly - startup delay for flash + * @strobe_type - select between sw and hw strobe + * @peripheral_subtype - module peripheral subtype + * @current_addr - address to write for current + * @second_addr - address of secondary flash to be written + * @safety_timer - enable safety timer or watchdog timer + * @torch_enable - enable flash LED torch mode + * @flash_reg_get - flash regulator attached or not + * @flash_on - flash status, on or off + * @torch_on - torch status, on or off + * @flash_boost_reg - boost regulator for flash + * @torch_boost_reg - boost regulator for torch + */ +struct flash_config_data { +=09u8=09current_prgm; +=09u8=09clamp_curr; +=09u8=09headroom; +=09u8=09duration; +=09u8=09enable_module; +=09u8=09trigger_flash; +=09u8=09startup_dly; +=09u8=09strobe_type; +=09u8=09peripheral_subtype; +=09u16=09current_addr; +=09u16=09second_addr; +=09bool=09safety_timer; +=09bool=09torch_enable; +=09bool=09flash_reg_get; +=09bool=09flash_on; +=09bool=09torch_on; +=09struct regulator *flash_boost_reg; +=09struct regulator *torch_boost_reg; +}; + +/** + * struct qpnp_led_data - internal led data structure + * @led_classdev - led class device + * @delayed_work - delayed work for turning off the LED + * @work - workqueue for led + * @id - led index + * @base_reg - base register given in device tree + * @lock - to protect the transactions + * @reg - cached value of led register + * @num_leds - number of leds in the module + * @max_current - maximum current supported by LED + * @default_on - true: default state max, false, default state 0 + * @turn_off_delay_ms - number of msec before turning off the LED + */ +struct qpnp_led_data { +=09struct led_classdev=09cdev; +=09struct regmap=09=09*regmap; +=09struct device=09=09*dev; +=09struct delayed_work=09dwork; +=09struct work_struct=09work; +=09int=09=09=09id; +=09u16=09=09=09base; +=09u8=09=09=09reg; +=09u8=09=09=09num_leds; +=09struct mutex=09=09lock; +=09struct flash_config_data=09*flash_cfg; +=09int=09=09=09max_current; +=09bool=09=09=09default_on; +=09int=09=09=09turn_off_delay_ms; +}; + +static int led_read_reg(struct qpnp_led_data *led, u16 offset, u8 *data) +{ +=09unsigned int val; +=09int ret; + +=09ret =3D regmap_read(led->regmap, led->base + offset, &val); +=09if (ret < 0) +=09=09return ret; + +=09*data =3D val; +=09return 0; +} + +static int led_write_reg(struct qpnp_led_data *led, u16 offset, u8 data) +{ +=09return regmap_write(led->regmap, led->base + offset, data); +} + +static void qpnp_dump_regs(struct qpnp_led_data *led, u8 regs[], u8 array_= size) +{ +=09int i; +=09u8 val; + +=09pr_debug("=3D=3D=3D=3D=3D %s LED register dump start =3D=3D=3D=3D=3D\n"= , led->cdev.name); +=09for (i =3D 0; i < array_size; i++) { +=09=09led_read_reg(led, regs[i], &val); +=09=09pr_debug("%s: 0x%x =3D 0x%x\n", led->cdev.name, +=09=09=09=09=09led->base + regs[i], val); +=09} +=09pr_debug("=3D=3D=3D=3D=3D %s LED register dump end =3D=3D=3D=3D=3D\n", = led->cdev.name); +} + + +static int qpnp_get_common_configs(struct qpnp_led_data *led, +=09=09=09=09struct device_node *node) +{ +=09int rc; +=09u32 val; +=09const char *temp_string; + +=09led->cdev.default_trigger =3D LED_TRIGGER_DEFAULT; +=09rc =3D of_property_read_string(node, "linux,default-trigger", +=09=09&temp_string); +=09if (!rc) +=09=09led->cdev.default_trigger =3D temp_string; +=09else if (rc !=3D -EINVAL) +=09=09return rc; + +=09led->default_on =3D false; +=09rc =3D of_property_read_string(node, "qcom,default-state", +=09=09&temp_string); +=09if (!rc) { +=09=09if (strncmp(temp_string, "on", sizeof("on")) =3D=3D 0) +=09=09=09led->default_on =3D true; +=09} else if (rc !=3D -EINVAL) +=09=09return rc; + +=09led->turn_off_delay_ms =3D 0; +=09rc =3D of_property_read_u32(node, "qcom,turn-off-delay-ms", &val); +=09if (!rc) +=09=09led->turn_off_delay_ms =3D val; +=09else if (rc !=3D -EINVAL) +=09=09return rc; + +=09return 0; +} + +static void qpnp_led_set(struct led_classdev *led_cdev, +=09=09=09=09enum led_brightness value) +{ +=09struct qpnp_led_data *led; + +=09led =3D container_of(led_cdev, struct qpnp_led_data, cdev); +=09if (value < LED_OFF || value > led->cdev.max_brightness) { +=09=09dev_err(led->dev, "Invalid brightness value\n"); +=09=09return; +=09} + +=09led->cdev.brightness =3D value; +=09schedule_work(&led->work); +} + +static enum led_brightness qpnp_led_get(struct led_classdev *led_cdev) +{ +=09struct qpnp_led_data *led; + +=09led =3D container_of(led_cdev, struct qpnp_led_data, cdev); + +=09return led->cdev.brightness; +} + +static int qpnp_get_config_flash(struct qpnp_led_data *led, +=09=09=09=09struct device_node *node, bool *reg_set) +{ +=09int rc; +=09u32 val; + +=09led->flash_cfg =3D devm_kzalloc(led->dev, +=09=09=09=09sizeof(struct flash_config_data), GFP_KERNEL); +=09if (!led->flash_cfg) { +=09=09dev_err(led->dev, "Unable to allocate memory\n"); +=09=09return -ENOMEM; +=09} + +=09rc =3D led_read_reg(led, FLASH_PERIPHERAL_SUBTYPE, +=09=09=09&led->flash_cfg->peripheral_subtype); +=09if (rc) { +=09=09dev_err(led->dev, +=09=09=09"Unable to read from addr=3D%x, rc(%d)\n", +=09=09=09FLASH_PERIPHERAL_SUBTYPE, rc); +=09} + +=09led->flash_cfg->torch_enable =3D +=09=09of_property_read_bool(node, "qcom,torch-enable"); + +=09if (led->id =3D=3D QPNP_ID_FLASH1_LED0) { +=09=09led->flash_cfg->enable_module =3D FLASH_ENABLE_LED_0; +=09=09led->flash_cfg->current_addr =3D FLASH_LED_0_CURR; +=09=09led->flash_cfg->trigger_flash =3D FLASH_LED_0_OUTPUT; +=09=09if (!*reg_set) { +=09=09=09led->flash_cfg->flash_boost_reg =3D +=09=09=09=09regulator_get(led->dev, +=09=09=09=09=09=09=09"flash-boost"); +=09=09=09if (IS_ERR(led->flash_cfg->flash_boost_reg)) { +=09=09=09=09rc =3D PTR_ERR(led->flash_cfg->flash_boost_reg); +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Regulator get failed(%d)\n", rc); +=09=09=09=09goto error_get_flash_reg; +=09=09=09} +=09=09=09led->flash_cfg->flash_reg_get =3D true; +=09=09=09*reg_set =3D true; +=09=09} else +=09=09=09led->flash_cfg->flash_reg_get =3D false; + +=09=09if (led->flash_cfg->torch_enable) { +=09=09=09led->flash_cfg->second_addr =3D +=09=09=09=09=09=09FLASH_LED_1_CURR; +=09=09} +=09} else if (led->id =3D=3D QPNP_ID_FLASH1_LED1) { +=09=09led->flash_cfg->enable_module =3D FLASH_ENABLE_LED_1; +=09=09led->flash_cfg->current_addr =3D FLASH_LED_1_CURR; +=09=09led->flash_cfg->trigger_flash =3D FLASH_LED_1_OUTPUT; +=09=09if (!*reg_set) { +=09=09=09led->flash_cfg->flash_boost_reg =3D +=09=09=09=09=09regulator_get(led->dev, +=09=09=09=09=09=09=09=09"flash-boost"); +=09=09=09if (IS_ERR(led->flash_cfg->flash_boost_reg)) { +=09=09=09=09rc =3D PTR_ERR(led->flash_cfg->flash_boost_reg); +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Regulator get failed(%d)\n", rc); +=09=09=09=09goto error_get_flash_reg; +=09=09=09} +=09=09=09led->flash_cfg->flash_reg_get =3D true; +=09=09=09*reg_set =3D true; +=09=09} else +=09=09=09led->flash_cfg->flash_reg_get =3D false; + +=09=09if (led->flash_cfg->torch_enable) { +=09=09=09led->flash_cfg->second_addr =3D +=09=09=09=09=09=09FLASH_LED_0_CURR; +=09=09} +=09} else { +=09=09dev_err(led->dev, "Unknown flash LED name given\n"); +=09=09return -EINVAL; +=09} + +=09if (led->flash_cfg->torch_enable) { +=09=09if (of_find_property(of_get_parent(node), "torch-boost-supply", +=09=09=09=09=09=09=09=09=09NULL)) { +=09=09=09led->flash_cfg->torch_boost_reg =3D +=09=09=09=09regulator_get(led->dev, +=09=09=09=09=09=09=09=09"torch-boost"); +=09=09=09if (IS_ERR(led->flash_cfg->torch_boost_reg)) { +=09=09=09=09rc =3D PTR_ERR(led->flash_cfg->torch_boost_reg); +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Torch regulator get failed(%d)\n", rc); +=09=09=09=09goto error_get_torch_reg; +=09=09=09} +=09=09=09led->flash_cfg->enable_module =3D FLASH_ENABLE_MODULE; +=09=09} else +=09=09=09led->flash_cfg->enable_module =3D FLASH_ENABLE_ALL; +=09=09led->flash_cfg->trigger_flash =3D FLASH_STROBE_SW; +=09} + +=09rc =3D of_property_read_u32(node, "qcom,current", &val); +=09if (!rc) { +=09=09if (led->flash_cfg->torch_enable) { +=09=09=09led->flash_cfg->current_prgm =3D (val * +=09=09=09=09TORCH_MAX_LEVEL / led->max_current); +=09=09=09return 0; +=09=09} +=09=09else +=09=09=09led->flash_cfg->current_prgm =3D (val * +=09=09=09=09FLASH_MAX_LEVEL / led->max_current); +=09} else +=09=09if (led->flash_cfg->torch_enable) +=09=09=09goto error_get_torch_reg; +=09=09else +=09=09=09goto error_get_flash_reg; + +=09rc =3D of_property_read_u32(node, "qcom,headroom", &val); +=09if (!rc) +=09=09led->flash_cfg->headroom =3D (u8) val; +=09else if (rc =3D=3D -EINVAL) +=09=09led->flash_cfg->headroom =3D HEADROOM_500mV; +=09else +=09=09goto error_get_flash_reg; + +=09rc =3D of_property_read_u32(node, "qcom,duration", &val); +=09if (!rc) +=09=09led->flash_cfg->duration =3D (((u8) val) - 10) / 10; +=09else if (rc =3D=3D -EINVAL) +=09=09led->flash_cfg->duration =3D FLASH_DURATION_200ms; +=09else +=09=09goto error_get_flash_reg; + +=09rc =3D of_property_read_u32(node, "qcom,clamp-curr", &val); +=09if (!rc) +=09=09led->flash_cfg->clamp_curr =3D (val * +=09=09=09=09FLASH_MAX_LEVEL / led->max_current); +=09else if (rc =3D=3D -EINVAL) +=09=09led->flash_cfg->clamp_curr =3D FLASH_CLAMP_200mA; +=09else +=09=09goto error_get_flash_reg; + +=09rc =3D of_property_read_u32(node, "qcom,startup-dly", &val); +=09if (!rc) +=09=09led->flash_cfg->startup_dly =3D (u8) val; +=09else if (rc =3D=3D -EINVAL) +=09=09led->flash_cfg->startup_dly =3D DELAY_128us; +=09else +=09=09goto error_get_flash_reg; + +=09led->flash_cfg->safety_timer =3D +=09=09of_property_read_bool(node, "qcom,safety-timer"); + +=09return 0; + +error_get_torch_reg: +=09regulator_put(led->flash_cfg->torch_boost_reg); + +error_get_flash_reg: +=09regulator_put(led->flash_cfg->flash_boost_reg); +=09return rc; + +} + +static ssize_t led_mode_store(struct device *dev, +=09=09=09struct device_attribute *attr, +=09=09=09const char *buf, size_t count) +{ +=09struct qpnp_led_data *led; +=09unsigned long state; +=09struct led_classdev *led_cdev =3D dev_get_drvdata(dev); +=09ssize_t ret =3D -EINVAL; + +=09ret =3D kstrtoul(buf, 10, &state); +=09if (ret) +=09=09return ret; + +=09led =3D container_of(led_cdev, struct qpnp_led_data, cdev); + +=09/* '1' to enable torch mode; '0' to switch to flash mode */ +=09if (state =3D=3D 1) +=09=09led->flash_cfg->torch_enable =3D true; +=09else +=09=09led->flash_cfg->torch_enable =3D false; + +=09return count; +} + +static ssize_t led_strobe_type_store(struct device *dev, +=09=09=09struct device_attribute *attr, +=09=09=09const char *buf, size_t count) +{ +=09struct qpnp_led_data *led; +=09unsigned long state; +=09struct led_classdev *led_cdev =3D dev_get_drvdata(dev); +=09ssize_t ret =3D -EINVAL; + +=09ret =3D kstrtoul(buf, 10, &state); +=09if (ret) +=09=09return ret; + +=09led =3D container_of(led_cdev, struct qpnp_led_data, cdev); + +=09/* '0' for sw strobe; '1' for hw strobe */ +=09if (state =3D=3D 1) +=09=09led->flash_cfg->strobe_type =3D 1; +=09else +=09=09led->flash_cfg->strobe_type =3D 0; + +=09return count; +} + +static DEVICE_ATTR(led_mode, 0664, NULL, led_mode_store); +static DEVICE_ATTR(strobe, 0664, NULL, led_strobe_type_store); + +static struct attribute *led_attrs[] =3D { +=09&dev_attr_led_mode.attr, +=09&dev_attr_strobe.attr, +=09NULL +}; + +static const struct attribute_group led_attr_group =3D { +=09.attrs =3D led_attrs, +}; + +static int qpnp_led_set_max_brightness(struct qpnp_led_data *led) +{ +=09switch (led->id) { +=09case QPNP_ID_FLASH1_LED0: +=09case QPNP_ID_FLASH1_LED1: +=09=09led->cdev.max_brightness =3D led->max_current; +=09=09break; +=09default: +=09=09dev_err(led->dev, "Invalid LED(%d)\n", led->id); +=09=09return -EINVAL; +=09} + +=09return 0; +} + +static int +qpnp_led_masked_write(struct qpnp_led_data *led, u16 addr, u8 mask, u8 val= ) +{ +=09int rc; +=09u8 reg; + +=09rc =3D led_read_reg(led, addr, ®); +=09if (rc) { +=09=09dev_err(led->dev, +=09=09=09"Unable to read from addr=3D%x, rc(%d)\n", addr, rc); +=09} + +=09reg &=3D ~mask; +=09reg |=3D val; + +=09rc =3D led_write_reg(led, addr, reg); +=09if (rc) +=09=09dev_err(led->dev, +=09=09=09"Unable to write to addr=3D%x, rc(%d)\n", addr, rc); +=09return rc; +} + +static int qpnp_flash_init(struct qpnp_led_data *led) +{ +=09int rc; + +=09led->flash_cfg->flash_on =3D false; + +=09rc =3D qpnp_led_masked_write(led, +=09=09FLASH_LED_STROBE_CTRL, +=09=09FLASH_STROBE_MASK, FLASH_DISABLE_ALL); +=09if (rc) { +=09=09dev_err(led->dev, +=09=09=09"LED %d flash write failed(%d)\n", led->id, rc); +=09=09return rc; +=09} + +=09/* Disable flash LED module */ +=09rc =3D qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL, +=09=09FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL); +=09if (rc) { +=09=09dev_err(led->dev, +=09=09=09"Enable reg write failed(%d)\n", rc); +=09=09return rc; +=09} + +=09if (led->flash_cfg->torch_enable) +=09=09return 0; + +=09/* Set headroom */ +=09rc =3D qpnp_led_masked_write(led, FLASH_HEADROOM, +=09=09FLASH_HEADROOM_MASK, led->flash_cfg->headroom); +=09if (rc) { +=09=09dev_err(led->dev, +=09=09=09"Headroom reg write failed(%d)\n", rc); +=09=09return rc; +=09} + +=09/* Set startup delay */ +=09rc =3D qpnp_led_masked_write(led, +=09=09FLASH_STARTUP_DELAY, FLASH_STARTUP_DLY_MASK, +=09=09led->flash_cfg->startup_dly); +=09if (rc) { +=09=09dev_err(led->dev, +=09=09=09"Startup delay reg write failed(%d)\n", rc); +=09=09return rc; +=09} + +=09/* Set timer control - safety or watchdog */ +=09if (led->flash_cfg->safety_timer) { +=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09FLASH_LED_TMR_CTRL, +=09=09=09FLASH_TMR_MASK, FLASH_TMR_SAFETY); +=09=09if (rc) { +=09=09=09dev_err(led->dev, +=09=09=09=09"LED timer ctrl reg write failed(%d)\n", +=09=09=09=09rc); +=09=09=09return rc; +=09=09} +=09} + +=09/* Set Vreg force */ +=09rc =3D qpnp_led_masked_write(led,=09FLASH_VREG_OK_FORCE, +=09=09FLASH_VREG_MASK, FLASH_HW_VREG_OK); +=09if (rc) { +=09=09dev_err(led->dev, +=09=09=09"Vreg OK reg write failed(%d)\n", rc); +=09=09return rc; +=09} + +=09/* Set self fault check */ +=09rc =3D qpnp_led_masked_write(led, FLASH_FAULT_DETECT, +=09=09FLASH_FAULT_DETECT_MASK, FLASH_SELFCHECK_DISABLE); +=09if (rc) { +=09=09dev_err(led->dev, +=09=09=09"Fault detect reg write failed(%d)\n", rc); +=09=09return rc; +=09} + +=09/* Set mask enable */ +=09rc =3D qpnp_led_masked_write(led, FLASH_MASK_ENABLE, +=09=09FLASH_MASK_REG_MASK, FLASH_MASK_1); +=09if (rc) { +=09=09dev_err(led->dev, +=09=09=09"Mask enable reg write failed(%d)\n", rc); +=09=09return rc; +=09} + +=09/* Set ramp rate */ +=09rc =3D qpnp_led_masked_write(led, FLASH_RAMP_RATE, +=09=09FLASH_RAMP_RATE_MASK, 0xBF); +=09if (rc) { +=09=09dev_err(led->dev, +=09=09=09"Ramp rate reg write failed(%d)\n", rc); +=09=09return rc; +=09} + +=09/* Enable VPH_PWR_DROOP and set threshold to 2.9V */ +=09rc =3D qpnp_led_masked_write(led, FLASH_VPH_PWR_DROOP, +=09=09=09=09=09FLASH_VPH_PWR_DROOP_MASK, 0xC2); +=09if (rc) { +=09=09dev_err(led->dev, +=09=09=09"FLASH_VPH_PWR_DROOP reg write failed(%d)\n", rc); +=09=09return rc; +=09} + +=09led->flash_cfg->strobe_type =3D 0; + +=09/* dump flash registers */ +=09qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs)); + +=09return 0; +} + +static int qpnp_led_initialize(struct qpnp_led_data *led) +{ +=09int rc =3D 0; + +=09switch (led->id) { +=09case QPNP_ID_FLASH1_LED0: +=09case QPNP_ID_FLASH1_LED1: +=09=09rc =3D qpnp_flash_init(led); +=09=09if (rc) +=09=09=09dev_err(led->dev, +=09=09=09=09"FLASH initialize failed(%d)\n", rc); +=09=09break; +=09default: +=09=09dev_err(led->dev, "Invalid LED(%d)\n", led->id); +=09=09return -EINVAL; +=09} + +=09return rc; +} + +static int qpnp_flash_regulator_operate(struct qpnp_led_data *led, bool on= ) +{ +=09int rc, i; +=09struct qpnp_led_data *led_array; +=09bool regulator_on =3D false; + +=09led_array =3D dev_get_drvdata(led->dev); +=09if (!led_array) { +=09=09dev_err(led->dev, +=09=09=09=09"Unable to get LED array\n"); +=09=09return -EINVAL; +=09} + +=09for (i =3D 0; i < led->num_leds; i++) +=09=09regulator_on |=3D led_array[i].flash_cfg->flash_on; + +=09if (!on) +=09=09goto regulator_turn_off; + +=09if (!regulator_on && !led->flash_cfg->flash_on) { +=09=09for (i =3D 0; i < led->num_leds; i++) { +=09=09=09if (led_array[i].flash_cfg->flash_reg_get) { +=09=09=09=09rc =3D regulator_enable( +=09=09=09=09=09led_array[i].flash_cfg->\ +=09=09=09=09=09flash_boost_reg); +=09=09=09=09if (rc) { +=09=09=09=09=09dev_err(led->dev, +=09=09=09=09=09=09"Regulator enable failed(%d)\n", +=09=09=09=09=09=09=09=09=09rc); +=09=09=09=09=09return rc; +=09=09=09=09} +=09=09=09=09led->flash_cfg->flash_on =3D true; +=09=09=09} +=09=09=09break; +=09=09} +=09} + +=09return 0; + +regulator_turn_off: +=09if (regulator_on && led->flash_cfg->flash_on) { +=09=09for (i =3D 0; i < led->num_leds; i++) { +=09=09=09if (led_array[i].flash_cfg->flash_reg_get) { +=09=09=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09=09=09FLASH_ENABLE_CONTROL, +=09=09=09=09=09FLASH_ENABLE_MASK, +=09=09=09=09=09FLASH_DISABLE_ALL); +=09=09=09=09if (rc) { +=09=09=09=09=09dev_err(led->dev, +=09=09=09=09=09=09"Enable reg write failed(%d)\n", +=09=09=09=09=09=09rc); +=09=09=09=09} + +=09=09=09=09rc =3D regulator_disable(led_array[i].flash_cfg->\ +=09=09=09=09=09=09=09flash_boost_reg); +=09=09=09=09if (rc) { +=09=09=09=09=09dev_err(led->dev, +=09=09=09=09=09=09"Regulator disable failed(%d)\n", +=09=09=09=09=09=09=09=09=09rc); +=09=09=09=09=09return rc; +=09=09=09=09} +=09=09=09=09led->flash_cfg->flash_on =3D false; +=09=09=09} +=09=09=09break; +=09=09} +=09} + +=09return 0; +} + +static int qpnp_torch_regulator_operate(struct qpnp_led_data *led, bool on= ) +{ +=09int rc; + +=09if (!on) +=09=09goto regulator_turn_off; + +=09if (!led->flash_cfg->torch_on) { +=09=09rc =3D regulator_enable(led->flash_cfg->torch_boost_reg); +=09=09if (rc) { +=09=09=09dev_err(led->dev, +=09=09=09=09"Regulator enable failed(%d)\n", rc); +=09=09=09=09return rc; +=09=09} +=09=09led->flash_cfg->torch_on =3D true; +=09} +=09return 0; + +regulator_turn_off: +=09if (led->flash_cfg->torch_on) { +=09=09rc =3D qpnp_led_masked_write(led,=09FLASH_ENABLE_CONTROL, +=09=09=09=09FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL); +=09=09if (rc) { +=09=09=09dev_err(led->dev, +=09=09=09=09"Enable reg write failed(%d)\n", rc); +=09=09} + +=09=09rc =3D regulator_disable(led->flash_cfg->torch_boost_reg); +=09=09if (rc) { +=09=09=09dev_err(led->dev, +=09=09=09=09"Regulator disable failed(%d)\n", rc); +=09=09=09return rc; +=09=09} +=09=09led->flash_cfg->torch_on =3D false; +=09} +=09return 0; +} + +static int qpnp_flash_set(struct qpnp_led_data *led) +{ +=09int rc, error; +=09int val =3D led->cdev.brightness; + +=09if (led->flash_cfg->torch_enable) +=09=09led->flash_cfg->current_prgm =3D +=09=09=09(val * TORCH_MAX_LEVEL / led->max_current); +=09else +=09=09led->flash_cfg->current_prgm =3D +=09=09=09(val * FLASH_MAX_LEVEL / led->max_current); + +=09/* Set led current */ +=09if (val > 0) { +=09=09if (led->flash_cfg->torch_enable) { +=09=09=09if (led->flash_cfg->peripheral_subtype =3D=3D +=09=09=09=09=09=09=09FLASH_SUBTYPE_DUAL) { +=09=09=09=09rc =3D qpnp_torch_regulator_operate(led, true); +=09=09=09=09if (rc) { +=09=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Torch regulator operate failed(%d)\n", +=09=09=09=09=09rc); +=09=09=09=09=09return rc; +=09=09=09=09} +=09=09=09} else if (led->flash_cfg->peripheral_subtype =3D=3D +=09=09=09=09=09=09=09FLASH_SUBTYPE_SINGLE) { +=09=09=09=09rc =3D qpnp_flash_regulator_operate(led, true); +=09=09=09=09if (rc) { +=09=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Flash regulator operate failed(%d)\n", +=09=09=09=09=09rc); +=09=09=09=09=09goto error_flash_set; +=09=09=09=09} + +=09=09=09=09/* +=09=09=09=09 * Write 0x80 to MODULE_ENABLE before writing +=09=09=09=09 * 0xE0 in order to avoid a hardware bug caused +=09=09=09=09 * by register value going from 0x00 to 0xE0. +=09=09=09=09 */ +=09=09=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09=09=09FLASH_ENABLE_CONTROL, +=09=09=09=09=09FLASH_ENABLE_MODULE_MASK, +=09=09=09=09=09FLASH_ENABLE_MODULE); +=09=09=09=09if (rc) { +=09=09=09=09=09dev_err(led->dev, +=09=09=09=09=09=09"Enable reg write failed(%d)\n", +=09=09=09=09=09=09rc); +=09=09=09=09=09return rc; +=09=09=09=09} +=09=09=09} + +=09=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09=09FLASH_LED_UNLOCK_SECURE, +=09=09=09=09FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE); +=09=09=09if (rc) { +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Secure reg write failed(%d)\n", rc); +=09=09=09=09goto error_reg_write; +=09=09=09} + +=09=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09=09FLASH_LED_TORCH, +=09=09=09=09FLASH_TORCH_MASK, FLASH_LED_TORCH_ENABLE); +=09=09=09if (rc) { +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Torch reg write failed(%d)\n", rc); +=09=09=09=09goto error_reg_write; +=09=09=09} + +=09=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09=09led->flash_cfg->current_addr, +=09=09=09=09FLASH_CURRENT_MASK, +=09=09=09=09led->flash_cfg->current_prgm); +=09=09=09if (rc) { +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Current reg write failed(%d)\n", rc); +=09=09=09=09goto error_reg_write; +=09=09=09} + +=09=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09=09led->flash_cfg->second_addr, +=09=09=09=09FLASH_CURRENT_MASK, +=09=09=09=09led->flash_cfg->current_prgm); +=09=09=09if (rc) { +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"2nd Current reg write failed(%d)\n", +=09=09=09=09=09rc); +=09=09=09=09goto error_reg_write; +=09=09=09} + +=09=09=09qpnp_led_masked_write(led, FLASH_MAX_CURR, +=09=09=09=09FLASH_CURRENT_MASK, +=09=09=09=09TORCH_MAX_LEVEL); +=09=09=09if (rc) { +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Max current reg write failed(%d)\n", +=09=09=09=09=09rc); +=09=09=09=09goto error_reg_write; +=09=09=09} + +=09=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09=09FLASH_ENABLE_CONTROL, +=09=09=09=09FLASH_ENABLE_MASK, +=09=09=09=09led->flash_cfg->enable_module); +=09=09=09if (rc) { +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Enable reg write failed(%d)\n", +=09=09=09=09=09rc); +=09=09=09=09goto error_reg_write; +=09=09=09} + +=09=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09=09FLASH_LED_STROBE_CTRL, +=09=09=09=09led->flash_cfg->trigger_flash, +=09=09=09=09led->flash_cfg->trigger_flash); +=09=09=09if (rc) { +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"LED %d strobe reg write failed(%d)\n", +=09=09=09=09=09led->id, rc); +=09=09=09=09goto error_reg_write; +=09=09=09} +=09=09} else { +=09=09=09rc =3D qpnp_flash_regulator_operate(led, true); +=09=09=09if (rc) { +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Flash regulator operate failed(%d)\n", +=09=09=09=09=09rc); +=09=09=09=09goto error_flash_set; +=09=09=09} + +=09=09=09/* Set flash safety timer */ +=09=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09=09FLASH_SAFETY_TIMER, +=09=09=09=09FLASH_SAFETY_TIMER_MASK, +=09=09=09=09led->flash_cfg->duration); +=09=09=09if (rc) { +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Safety timer reg write failed(%d)\n", +=09=09=09=09=09rc); +=09=09=09=09goto error_flash_set; +=09=09=09} + +=09=09=09/* Set max current */ +=09=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09=09FLASH_MAX_CURR, FLASH_CURRENT_MASK, +=09=09=09=09FLASH_MAX_LEVEL); +=09=09=09if (rc) { +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Max current reg write failed(%d)\n", +=09=09=09=09=09rc); +=09=09=09=09goto error_flash_set; +=09=09=09} + +=09=09=09/* Set clamp current */ +=09=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09=09FLASH_CLAMP_CURR, +=09=09=09=09FLASH_CURRENT_MASK, +=09=09=09=09led->flash_cfg->clamp_curr); +=09=09=09if (rc) { +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Clamp current reg write failed(%d)\n", +=09=09=09=09=09rc); +=09=09=09=09goto error_flash_set; +=09=09=09} + +=09=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09=09led->flash_cfg->current_addr, +=09=09=09=09FLASH_CURRENT_MASK, +=09=09=09=09led->flash_cfg->current_prgm); +=09=09=09if (rc) { +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Current reg write failed(%d)\n", rc); +=09=09=09=09goto error_flash_set; +=09=09=09} + +=09=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09=09FLASH_ENABLE_CONTROL, +=09=09=09=09led->flash_cfg->enable_module, +=09=09=09=09led->flash_cfg->enable_module); +=09=09=09if (rc) { +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Enable reg write failed(%d)\n", rc); +=09=09=09=09goto error_flash_set; +=09=09=09} + +=09=09=09/* TODO try to not busy wait*/ +=09=09=09mdelay(1); + +=09=09=09if (!led->flash_cfg->strobe_type) { +=09=09=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09=09=09FLASH_LED_STROBE_CTRL, +=09=09=09=09=09led->flash_cfg->trigger_flash, +=09=09=09=09=09led->flash_cfg->trigger_flash); +=09=09=09=09if (rc) { +=09=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"LED %d strobe reg write failed(%d)\n", +=09=09=09=09=09led->id, rc); +=09=09=09=09=09goto error_flash_set; +=09=09=09=09} +=09=09=09} else { +=09=09=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09=09=09FLASH_LED_STROBE_CTRL, +=09=09=09=09=09(led->flash_cfg->trigger_flash | +=09=09=09=09=09FLASH_STROBE_HW), +=09=09=09=09=09(led->flash_cfg->trigger_flash | +=09=09=09=09=09FLASH_STROBE_HW)); +=09=09=09=09if (rc) { +=09=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"LED %d strobe reg write failed(%d)\n", +=09=09=09=09=09led->id, rc); +=09=09=09=09=09goto error_flash_set; +=09=09=09=09} +=09=09=09} +=09=09} +=09} else { +=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09FLASH_LED_STROBE_CTRL, +=09=09=09led->flash_cfg->trigger_flash, +=09=09=09FLASH_DISABLE_ALL); +=09=09if (rc) { +=09=09=09dev_err(led->dev, +=09=09=09=09"LED %d flash write failed(%d)\n", led->id, rc); +=09=09=09if (led->flash_cfg->torch_enable) +=09=09=09=09goto error_torch_set; +=09=09=09else +=09=09=09=09goto error_flash_set; +=09=09} + +=09=09/* TODO try to not busy wait*/ +=09=09mdelay(2); +=09=09udelay(160); + +=09=09if (led->flash_cfg->torch_enable) { +=09=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09=09FLASH_LED_UNLOCK_SECURE, +=09=09=09=09FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE); +=09=09=09if (rc) { +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Secure reg write failed(%d)\n", rc); +=09=09=09=09goto error_torch_set; +=09=09=09} + +=09=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09=09=09FLASH_LED_TORCH, +=09=09=09=09=09FLASH_TORCH_MASK, +=09=09=09=09=09FLASH_LED_TORCH_DISABLE); +=09=09=09if (rc) { +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Torch reg write failed(%d)\n", rc); +=09=09=09=09goto error_torch_set; +=09=09=09} + +=09=09=09if (led->flash_cfg->peripheral_subtype =3D=3D +=09=09=09=09=09=09=09FLASH_SUBTYPE_DUAL) { +=09=09=09=09rc =3D qpnp_torch_regulator_operate(led, false); +=09=09=09=09if (rc) { +=09=09=09=09=09dev_err(led->dev, +=09=09=09=09=09=09"Torch regulator operate failed(%d)\n", +=09=09=09=09=09=09rc); +=09=09=09=09=09return rc; +=09=09=09=09} +=09=09=09} else if (led->flash_cfg->peripheral_subtype =3D=3D +=09=09=09=09=09=09=09FLASH_SUBTYPE_SINGLE) { +=09=09=09=09rc =3D qpnp_flash_regulator_operate(led, false); +=09=09=09=09if (rc) { +=09=09=09=09=09dev_err(led->dev, +=09=09=09=09=09=09"Flash regulator operate failed(%d)\n", +=09=09=09=09=09=09rc); +=09=09=09=09=09return rc; +=09=09=09=09} +=09=09=09} +=09=09} else { +=09=09=09rc =3D qpnp_led_masked_write(led, +=09=09=09=09FLASH_ENABLE_CONTROL, +=09=09=09=09led->flash_cfg->enable_module & +=09=09=09=09~FLASH_ENABLE_MODULE_MASK, +=09=09=09=09FLASH_DISABLE_ALL); +=09=09=09if (rc) { +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Enable reg write failed(%d)\n", rc); +=09=09=09=09if (led->flash_cfg->torch_enable) +=09=09=09=09=09goto error_torch_set; +=09=09=09=09else +=09=09=09=09=09goto error_flash_set; +=09=09=09} + +=09=09=09rc =3D qpnp_flash_regulator_operate(led, false); +=09=09=09if (rc) { +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Flash regulator operate failed(%d)\n", +=09=09=09=09=09rc); +=09=09=09=09return rc; +=09=09=09} +=09=09} +=09} + +=09qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs)); + +=09return 0; + +error_reg_write: +=09if (led->flash_cfg->peripheral_subtype =3D=3D FLASH_SUBTYPE_SINGLE) +=09=09goto error_flash_set; + +error_torch_set: +=09error =3D qpnp_torch_regulator_operate(led, false); +=09if (error) { +=09=09dev_err(led->dev, +=09=09=09"Torch regulator operate failed(%d)\n", rc); +=09=09return error; +=09} +=09return rc; + +error_flash_set: +=09error =3D qpnp_flash_regulator_operate(led, false); +=09if (error) { +=09=09dev_err(led->dev, +=09=09=09"Flash regulator operate failed(%d)\n", rc); +=09=09return error; +=09} +=09return rc; +} + +static void __qpnp_led_work(struct qpnp_led_data *led, +=09=09=09=09enum led_brightness value) +{ +=09int rc; + +=09mutex_lock(&led->lock); + +=09switch (led->id) { +=09case QPNP_ID_FLASH1_LED0: +=09case QPNP_ID_FLASH1_LED1: +=09=09rc =3D qpnp_flash_set(led); +=09=09if (rc < 0) +=09=09=09dev_err(led->dev, +=09=09=09=09"FLASH set brightness failed (%d)\n", rc); +=09=09break; +=09default: +=09=09dev_err(led->dev, "Invalid LED(%d)\n", led->id); +=09=09break; +=09} +=09mutex_unlock(&led->lock); + +} + +static void qpnp_led_work(struct work_struct *work) +{ +=09struct qpnp_led_data *led =3D container_of(work, +=09=09=09=09=09struct qpnp_led_data, work); + +=09__qpnp_led_work(led, led->cdev.brightness); + +=09return; +} + +static void qpnp_led_turn_off_delayed(struct work_struct *work) +{ +=09struct delayed_work *dwork =3D to_delayed_work(work); +=09struct qpnp_led_data *led +=09=09=3D container_of(dwork, struct qpnp_led_data, dwork); + +=09led->cdev.brightness =3D LED_OFF; +=09qpnp_led_set(&led->cdev, led->cdev.brightness); +} + +static void qpnp_led_turn_off(struct qpnp_led_data *led) +{ +=09INIT_DELAYED_WORK(&led->dwork, qpnp_led_turn_off_delayed); +=09schedule_delayed_work(&led->dwork, +=09=09msecs_to_jiffies(led->turn_off_delay_ms)); +} + +static int qpnp_leds_probe(struct platform_device *pdev) +{ +=09struct qpnp_led_data *led, *led_array; +=09struct device_node *node, *temp; +=09int rc, i, num_leds =3D 0, parsed_leds =3D 0; +=09int reg; +=09const char *led_label; +=09bool regulator_probe =3D false; + +=09node =3D pdev->dev.of_node; +=09if (node =3D=3D NULL) +=09=09return -ENODEV; + +=09temp =3D NULL; +=09while ((temp =3D of_get_next_child(node, temp))) +=09=09num_leds++; + +=09if (!num_leds) +=09=09return -ECHILD; + +=09led_array =3D devm_kzalloc(&pdev->dev, +=09=09(sizeof(struct qpnp_led_data) * num_leds), GFP_KERNEL); +=09if (!led_array) { +=09=09dev_err(&pdev->dev, "Unable to allocate memory\n"); +=09=09return -ENOMEM; +=09} + +=09for_each_child_of_node(node, temp) { +=09=09led =3D &led_array[parsed_leds]; +=09=09led->num_leds =3D num_leds; +=09=09led->dev =3D &pdev->dev; +=09=09led->regmap =3D dev_get_regmap(pdev->dev.parent, NULL); +=09=09if (!led->regmap) +=09=09=09return -ENODEV; + +=09=09rc =3D of_property_read_u32(node, "reg", ®); +=09=09if (rc < 0) { +=09=09=09dev_err(led->dev, +=09=09=09=09"Failure reading reg, rc =3D %d\n", rc); +=09=09=09goto fail_id_check; +=09=09} +=09=09led->base =3D reg; + +=09=09rc =3D of_property_read_string(temp, "label", &led_label); +=09=09if (rc < 0) { +=09=09=09dev_err(led->dev, +=09=09=09=09"Failure reading label, rc =3D %d\n", rc); +=09=09=09goto fail_id_check; +=09=09} + +=09=09rc =3D of_property_read_string(temp, "linux,name", +=09=09=09&led->cdev.name); +=09=09if (rc < 0) { +=09=09=09dev_err(led->dev, +=09=09=09=09"Failure reading led name, rc =3D %d\n", rc); +=09=09=09goto fail_id_check; +=09=09} + +=09=09rc =3D of_property_read_u32(temp, "qcom,max-current", +=09=09=09&led->max_current); +=09=09if (rc < 0) { +=09=09=09dev_err(led->dev, +=09=09=09=09"Failure reading max_current, rc =3D %d\n", rc); +=09=09=09goto fail_id_check; +=09=09} + +=09=09rc =3D of_property_read_u32(temp, "qcom,id", &led->id); +=09=09if (rc < 0) { +=09=09=09dev_err(led->dev, +=09=09=09=09"Failure reading led id, rc =3D %d\n", rc); +=09=09=09goto fail_id_check; +=09=09} + +=09=09rc =3D qpnp_get_common_configs(led, temp); +=09=09if (rc) { +=09=09=09dev_err(led->dev, +=09=09=09=09"Failure reading common led configuration," \ +=09=09=09=09" rc =3D %d\n", rc); +=09=09=09goto fail_id_check; +=09=09} + +=09=09led->cdev.brightness_set =3D qpnp_led_set; +=09=09led->cdev.brightness_get =3D qpnp_led_get; + +=09=09if (strncmp(led_label, "flash", sizeof("flash")) =3D=3D 0) { +=09=09=09if (!of_find_property(node, "flash-boost-supply", NULL)) +=09=09=09=09regulator_probe =3D true; +=09=09=09rc =3D qpnp_get_config_flash(led, temp, ®ulator_probe); +=09=09=09if (rc < 0) { +=09=09=09=09dev_err(led->dev, +=09=09=09=09=09"Unable to read flash config data\n"); +=09=09=09=09goto fail_id_check; +=09=09=09} +=09=09} else { +=09=09=09dev_err(led->dev, "No LED matching label\n"); +=09=09=09rc =3D -EINVAL; +=09=09=09goto fail_id_check; +=09=09} + +=09=09mutex_init(&led->lock); +=09=09INIT_WORK(&led->work, qpnp_led_work); + +=09=09rc =3D qpnp_led_initialize(led); +=09=09if (rc < 0) +=09=09=09goto fail_id_check; + +=09=09rc =3D qpnp_led_set_max_brightness(led); +=09=09if (rc < 0) +=09=09=09goto fail_id_check; + +=09=09rc =3D led_classdev_register(&pdev->dev, &led->cdev); +=09=09if (rc) { +=09=09=09dev_err(&pdev->dev, "unable to register led %d,rc=3D%d\n", +=09=09=09=09=09=09 led->id, rc); +=09=09=09goto fail_id_check; +=09=09} + +=09=09if (led->id =3D=3D QPNP_ID_FLASH1_LED0 || +=09=09=09led->id =3D=3D QPNP_ID_FLASH1_LED1) { +=09=09=09rc =3D sysfs_create_group(&led->cdev.dev->kobj, +=09=09=09=09=09=09=09&led_attr_group); +=09=09=09if (rc) +=09=09=09=09goto fail_id_check; + +=09=09} + +=09=09/* configure default state */ +=09=09if (led->default_on) { +=09=09=09led->cdev.brightness =3D led->cdev.max_brightness; +=09=09=09__qpnp_led_work(led, led->cdev.brightness); +=09=09=09schedule_work(&led->work); +=09=09=09if (led->turn_off_delay_ms > 0) +=09=09=09=09qpnp_led_turn_off(led); +=09=09} else +=09=09=09led->cdev.brightness =3D LED_OFF; + +=09=09parsed_leds++; +=09} +=09dev_set_drvdata(&pdev->dev, led_array); +=09return 0; + +fail_id_check: +=09for (i =3D 0; i < parsed_leds; i++) { +=09=09mutex_destroy(&led_array[i].lock); +=09=09led_classdev_unregister(&led_array[i].cdev); +=09} + +=09return rc; +} + +static int qpnp_leds_remove(struct platform_device *pdev) +{ +=09struct qpnp_led_data *led_array =3D dev_get_drvdata(&pdev->dev); +=09int i, parsed_leds =3D led_array->num_leds; + +=09for (i =3D 0; i < parsed_leds; i++) { +=09=09cancel_work_sync(&led_array[i].work); +=09=09mutex_destroy(&led_array[i].lock); +=09=09led_classdev_unregister(&led_array[i].cdev); +=09=09switch (led_array[i].id) { +=09=09case QPNP_ID_FLASH1_LED0: +=09=09case QPNP_ID_FLASH1_LED1: +=09=09=09if (led_array[i].flash_cfg->flash_reg_get) +=09=09=09=09regulator_put(led_array[i].flash_cfg-> \ +=09=09=09=09=09=09=09flash_boost_reg); +=09=09=09if (led_array[i].flash_cfg->torch_enable) +=09=09=09=09regulator_put(led_array[i].flash_cfg->\ +=09=09=09=09=09=09=09torch_boost_reg); +=09=09=09sysfs_remove_group(&led_array[i].cdev.dev->kobj, +=09=09=09=09=09=09=09&led_attr_group); +=09=09=09break; +=09=09default: +=09=09=09dev_err(led_array[i].dev, +=09=09=09=09=09"Invalid LED(%d)\n", +=09=09=09=09=09led_array[i].id); +=09=09=09return -EINVAL; +=09=09} +=09} + +=09return 0; +} + +static const struct of_device_id qpnp_leds_spmi_of_match[] =3D { +=09{ .compatible =3D "qcom,leds-qpnp" }, +=09{}, +}; +MODULE_DEVICE_TABLE(of, qpnp_leds_spmi_of_match); + +static struct platform_driver qpnp_leds_driver =3D { +=09.driver=09=09=3D { +=09=09.name=09=3D "qcom,leds-qpnp", +=09=09.of_match_table =3D of_match_ptr(qpnp_leds_spmi_of_match), +=09}, +=09.probe=09=09=3D qpnp_leds_probe, +=09.remove=09=09=3D qpnp_leds_remove, +}; +module_platform_driver(qpnp_leds_driver); + +MODULE_DESCRIPTION("QPNP LED driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("leds:leds-qpnp"); --=20 2.29.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 X-Spam-Level: X-Spam-Status: No, score=-9.5 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4ADBAC2D0A3 for ; Fri, 6 Nov 2020 17:00:53 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2F145217A0 for ; Fri, 6 Nov 2020 17:00:52 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="ddbAetNZ"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=protonmail.com header.i=@protonmail.com header.b="DUwb13uO" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2F145217A0 Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=protonmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:Reply-To:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-ID: Subject:From:To:Date:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=IKwkhREoFarBMBlWn2W5XSWsdEWGcclwkUwRvmhVbZ0=; b=ddbAetNZr0S3IIPwcIXhWvFPLm LoMHdMpsCmQY2x4OeynBxYr7vj8v9rYqdyMtAZqb6KXDUP7xEOUsVzPjq0AKqBpW/P312RoDSLNzZ l3sjBh1b1Uqdrz/XMV1WjOf1zAuzjp6pXfCjrFN5chynHnCA7yNN+oEX0a3FQYl4+4KSpwYUZAGek 1acSDxAanNdgpHNML+9bLnYWh/RI/NoYXgVJfrUVEMP3vE+jzHv7G/ejlfOwwK9zXTfksrbqPC2Pn NPCc0JCg61HnPrMzcc53l96ejx2fJu78wIrjMwbQiOgZc416+O1icAlZ6qQlNsbP9gyfDA3TMvf6N fOiCx8xg==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kb54n-0008Aa-7t; Fri, 06 Nov 2020 16:59:01 +0000 Received: from mail-40131.protonmail.ch ([185.70.40.131]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kb54R-00080y-D5 for linux-arm-kernel@lists.infradead.org; Fri, 06 Nov 2020 16:58:43 +0000 Date: Fri, 06 Nov 2020 16:58:32 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com; s=protonmail; t=1604681914; bh=xsLf4nlDUCOrHrV/3/k0x1f+6hMboUUSPp1jdSsv+no=; h=Date:To:From:Cc:Reply-To:Subject:In-Reply-To:References:From; b=DUwb13uOJR9og0cykF/L+IpWlgwsipj1az9taG7IzIPY+3JWQi2i16lmGshdGoMew hGnkjYlKABniqvg6xeLjC6svCOMUXE0uO2AG+tTs6d2OxxfmUYhtD1I5Rw7M1dY0TT R0qbFHLEksBJ60mSDrjKp8QBs63pr3y9NqxeX3PU= To: Pavel Machek , Dan Murphy , Bjorn Andersson , Andy Gross , Rob Herring From: =?utf-8?Q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?= Subject: [RFC PATCH 1/3] leds: Add driver for QPNP flash led Message-ID: <20201106165737.1029106-2-nfraprado@protonmail.com> In-Reply-To: <20201106165737.1029106-1-nfraprado@protonmail.com> References: <20201106165737.1029106-1-nfraprado@protonmail.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20201106_115839_917376_D6CCFFF8 X-CRM114-Status: GOOD ( 19.20 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: =?utf-8?Q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?= Cc: devicetree@vger.kernel.org, linux-arm-msm@vger.kernel.org, Russell King , linux-kernel@vger.kernel.org, Luca Weiss , lkcamp@lists.libreplanetbr.org, linux-leds@vger.kernel.org, andrealmeid@collabora.com, Georgi Djakov , linux-arm-kernel@lists.infradead.org, Brian Masney Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org QWRkIGRyaXZlciBmb3IgdGhlIFFQTlAgZmxhc2ggTEVELiBJdCB3b3JrcyBvdmVyIFNQTUkgYW5k IGlzIHBhcnQgb2YgdGhlClBNODk0MSBQTUlDLgoKU2lnbmVkLW9mZi1ieTogTsOtY29sYXMgRi4g Ui4gQS4gUHJhZG8gPG5mcmFwcmFkb0Bwcm90b25tYWlsLmNvbT4KLS0tCiBkcml2ZXJzL2xlZHMv S2NvbmZpZyAgICAgfCAgICA5ICsKIGRyaXZlcnMvbGVkcy9NYWtlZmlsZSAgICB8ICAgIDEgKwog ZHJpdmVycy9sZWRzL2xlZHMtcXBucC5jIHwgMTM1MSArKysrKysrKysrKysrKysrKysrKysrKysr KysrKysrKysrKysrKwogMyBmaWxlcyBjaGFuZ2VkLCAxMzYxIGluc2VydGlvbnMoKykKIGNyZWF0 ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL2xlZHMvbGVkcy1xcG5wLmMKCmRpZmYgLS1naXQgYS9kcml2 ZXJzL2xlZHMvS2NvbmZpZyBiL2RyaXZlcnMvbGVkcy9LY29uZmlnCmluZGV4IDg0OWQzYzVmOTA4 ZS4uY2E1ZjZlODFjMDY0IDEwMDY0NAotLS0gYS9kcml2ZXJzL2xlZHMvS2NvbmZpZworKysgYi9k cml2ZXJzL2xlZHMvS2NvbmZpZwpAQCAtOTI4LDYgKzkyOCwxNSBAQCBjb25maWcgTEVEU19BQ0VS X0E1MDAKIAkgIFRoaXMgb3B0aW9uIGVuYWJsZXMgc3VwcG9ydCBmb3IgdGhlIFBvd2VyIEJ1dHRv biBMRUQgb2YKIAkgIEFjZXIgSWNvbmlhIFRhYiBBNTAwLgogCitjb25maWcgTEVEU19RUE5QCisJ dHJpc3RhdGUgIlN1cHBvcnQgZm9yIFFQTlAgTEVEcyIKKwlkZXBlbmRzIG9uIFNQTUkKKwloZWxw CisJICBUaGlzIGRyaXZlciBzdXBwb3J0cyB0aGUgZmxhc2gvdG9yY2ggbGVkIG9mIFF1YWxjb21t IFBOUCBQTUlDLgorCisJICBUbyBjb21waWxlIHRoaXMgZHJpdmVyIGFzIGEgbW9kdWxlLCBjaG9v c2UgTSBoZXJlOiB0aGUgbW9kdWxlIHdpbGwKKwkgIGJlIGNhbGxlZCBsZWRzLXFwbnAuCisKIGNv bW1lbnQgIkxFRCBUcmlnZ2VycyIKIHNvdXJjZSAiZHJpdmVycy9sZWRzL3RyaWdnZXIvS2NvbmZp ZyIKIApkaWZmIC0tZ2l0IGEvZHJpdmVycy9sZWRzL01ha2VmaWxlIGIvZHJpdmVycy9sZWRzL01h a2VmaWxlCmluZGV4IDczZTYwM2UxNzI3ZS4uMDU1MzYwMjQwODAxIDEwMDY0NAotLS0gYS9kcml2 ZXJzL2xlZHMvTWFrZWZpbGUKKysrIGIvZHJpdmVycy9sZWRzL01ha2VmaWxlCkBAIC05Myw2ICs5 Myw3IEBAIG9iai0kKENPTkZJR19MRURTX1RVUlJJU19PTU5JQSkJCSs9IGxlZHMtdHVycmlzLW9t bmlhLm8KIG9iai0kKENPTkZJR19MRURTX1dNODMxWF9TVEFUVVMpCSs9IGxlZHMtd204MzF4LXN0 YXR1cy5vCiBvYmotJChDT05GSUdfTEVEU19XTTgzNTApCQkrPSBsZWRzLXdtODM1MC5vCiBvYmot JChDT05GSUdfTEVEU19XUkFQKQkJCSs9IGxlZHMtd3JhcC5vCitvYmotJChDT05GSUdfTEVEU19R UE5QKQkJCSs9IGxlZHMtcXBucC5vCiAKICMgTEVEIFNQSSBEcml2ZXJzCiBvYmotJChDT05GSUdf TEVEU19DUjAwMTQxMTQpCQkrPSBsZWRzLWNyMDAxNDExNC5vCmRpZmYgLS1naXQgYS9kcml2ZXJz L2xlZHMvbGVkcy1xcG5wLmMgYi9kcml2ZXJzL2xlZHMvbGVkcy1xcG5wLmMKbmV3IGZpbGUgbW9k ZSAxMDA2NDQKaW5kZXggMDAwMDAwMDAwMDAwLi45OTcwNjg4MjY0YWEKLS0tIC9kZXYvbnVsbAor KysgYi9kcml2ZXJzL2xlZHMvbGVkcy1xcG5wLmMKQEAgLTAsMCArMSwxMzUxIEBACisjaW5jbHVk ZSA8bGludXgva2VybmVsLmg+CisjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+CisjaW5jbHVkZSA8 bGludXgvc3BtaS5oPgorI2luY2x1ZGUgPGxpbnV4L29mX2RldmljZS5oPgorI2luY2x1ZGUgPGxp bnV4L2RldmljZS5oPgorI2luY2x1ZGUgPGxpbnV4L3R5cGVzLmg+CisjaW5jbHVkZSA8bGludXgv c3RyaW5nLmg+CisjaW5jbHVkZSA8bGludXgvbXV0ZXguaD4KKyNpbmNsdWRlIDxsaW51eC9zeXNm cy5oPgorI2luY2x1ZGUgPGxpbnV4L3dvcmtxdWV1ZS5oPgorI2luY2x1ZGUgPGxpbnV4L2xlZHMu aD4KKyNpbmNsdWRlIDxsaW51eC9yZWd1bGF0b3IvY29uc3VtZXIuaD4KKyNpbmNsdWRlIDxsaW51 eC9kZWxheS5oPgorI2luY2x1ZGUgPGxpbnV4L3JlZ21hcC5oPgorCisjZGVmaW5lIEZMQVNIX1NB RkVUWV9USU1FUgkweDQwCisjZGVmaW5lIEZMQVNIX01BWF9DVVJSCQkweDQxCisjZGVmaW5lIEZM QVNIX0xFRF8wX0NVUlIJMHg0MgorI2RlZmluZSBGTEFTSF9MRURfMV9DVVJSCTB4NDMKKyNkZWZp bmUgRkxBU0hfQ0xBTVBfQ1VSUgkweDQ0CisjZGVmaW5lIEZMQVNIX0xFRF9UTVJfQ1RSTAkweDQ4 CisjZGVmaW5lIEZMQVNIX0hFQURST09NCQkweDRBCisjZGVmaW5lIEZMQVNIX1NUQVJUVVBfREVM QVkJMHg0QgorI2RlZmluZSBGTEFTSF9NQVNLX0VOQUJMRQkweDRDCisjZGVmaW5lIEZMQVNIX1ZS RUdfT0tfRk9SQ0UJMHg0RgorI2RlZmluZSBGTEFTSF9FTkFCTEVfQ09OVFJPTAkweDQ2CisjZGVm aW5lIEZMQVNIX0xFRF9TVFJPQkVfQ1RSTAkweDQ3CisjZGVmaW5lIEZMQVNIX0xFRF9VTkxPQ0tf U0VDVVJFCTB4RDAKKyNkZWZpbmUgRkxBU0hfTEVEX1RPUkNICQkweEU0CisjZGVmaW5lIEZMQVNI X0ZBVUxUX0RFVEVDVAkweDUxCisjZGVmaW5lIEZMQVNIX1JBTVBfUkFURQkJMHg1NAorI2RlZmlu ZSBGTEFTSF9QRVJJUEhFUkFMX1NVQlRZUEUJMHgwNQorI2RlZmluZSBGTEFTSF9WUEhfUFdSX0RS T09QCTB4NUEKKworI2RlZmluZSBGTEFTSF9NQVhfTEVWRUwJCQkweDRGCisjZGVmaW5lIFRPUkNI X01BWF9MRVZFTAkJCTB4MEYKKyNkZWZpbmUJRkxBU0hfTk9fTUFTSwkJCTB4MDAKKworI2RlZmlu ZSBGTEFTSF9NQVNLXzEJCQkweDIwCisjZGVmaW5lIEZMQVNIX01BU0tfUkVHX01BU0sJCTB4RTAK KyNkZWZpbmUgRkxBU0hfSEVBRFJPT01fTUFTSwkJMHgwMworI2RlZmluZSBGTEFTSF9TQUZFVFlf VElNRVJfTUFTSwkJMHg3RgorI2RlZmluZSBGTEFTSF9DVVJSRU5UX01BU0sJCTB4RkYKKyNkZWZp bmUgRkxBU0hfTUFYX0NVUlJFTlRfTUFTSwkJMHg3RgorI2RlZmluZSBGTEFTSF9UTVJfTUFTSwkJ CTB4MDMKKyNkZWZpbmUgRkxBU0hfVE1SX1dBVENIRE9HCQkweDAzCisjZGVmaW5lIEZMQVNIX1RN Ul9TQUZFVFkJCTB4MDAKKyNkZWZpbmUgRkxBU0hfRkFVTFRfREVURUNUX01BU0sJCTBYODAKKyNk ZWZpbmUgRkxBU0hfSFdfVlJFR19PSwkJMHg0MAorI2RlZmluZSBGTEFTSF9WUkVHX01BU0sJCQkw eEMwCisjZGVmaW5lIEZMQVNIX1NUQVJUVVBfRExZX01BU0sJCTB4MDIKKyNkZWZpbmUgRkxBU0hf UkFNUF9SQVRFX01BU0sJCTB4QkYKKyNkZWZpbmUgRkxBU0hfVlBIX1BXUl9EUk9PUF9NQVNLCTB4 RjMKKworI2RlZmluZSBGTEFTSF9FTkFCTEVfQUxMCQkweEUwCisjZGVmaW5lIEZMQVNIX0VOQUJM RV9NT0RVTEUJCTB4ODAKKyNkZWZpbmUgRkxBU0hfRU5BQkxFX01PRFVMRV9NQVNLCTB4ODAKKyNk ZWZpbmUgRkxBU0hfRElTQUJMRV9BTEwJCTB4MDAKKyNkZWZpbmUgRkxBU0hfRU5BQkxFX01BU0sJ CTB4RTAKKyNkZWZpbmUgRkxBU0hfRU5BQkxFX0xFRF8wCQkweEMwCisjZGVmaW5lIEZMQVNIX0VO QUJMRV9MRURfMQkJMHhBMAorI2RlZmluZSBGTEFTSF9JTklUX01BU0sJCQkweEUwCisjZGVmaW5l IEZMQVNIX1NFTEZDSEVDS19FTkFCTEUJCTB4ODAKKyNkZWZpbmUgRkxBU0hfU0VMRkNIRUNLX0RJ U0FCTEUJCTB4MDAKKworI2RlZmluZSBGTEFTSF9TVFJPQkVfU1cJCQkweEMwCisjZGVmaW5lIEZM QVNIX1NUUk9CRV9IVwkJCTB4MDQKKyNkZWZpbmUgRkxBU0hfU1RST0JFX01BU0sJCTB4QzcKKyNk ZWZpbmUgRkxBU0hfTEVEXzBfT1VUUFVUCQkweDgwCisjZGVmaW5lIEZMQVNIX0xFRF8xX09VVFBV VAkJMHg0MAorCisjZGVmaW5lIEZMQVNIX0NVUlJFTlRfUFJHTV9NSU4JCTEKKyNkZWZpbmUgRkxB U0hfQ1VSUkVOVF9QUkdNX1NISUZUCTEKKyNkZWZpbmUgRkxBU0hfQ1VSUkVOVF9NQVgJCTB4NEYK KyNkZWZpbmUgRkxBU0hfQ1VSUkVOVF9UT1JDSAkJMHgwNworCisjZGVmaW5lIEZMQVNIX0RVUkFU SU9OXzIwMG1zCQkweDEzCisjZGVmaW5lIEZMQVNIX0NMQU1QXzIwMG1BCQkweDBGCisKKyNkZWZp bmUgRkxBU0hfVE9SQ0hfTUFTSwkJMHgwMworI2RlZmluZSBGTEFTSF9MRURfVE9SQ0hfRU5BQkxF CQkweDAwCisjZGVmaW5lIEZMQVNIX0xFRF9UT1JDSF9ESVNBQkxFCQkweDAzCisjZGVmaW5lIEZM QVNIX1VOTE9DS19TRUNVUkUJCTB4QTUKKyNkZWZpbmUgRkxBU0hfU0VDVVJFX01BU0sJCTB4RkYK KworI2RlZmluZSBGTEFTSF9TVUJUWVBFX0RVQUwJCTB4MDEKKyNkZWZpbmUgRkxBU0hfU1VCVFlQ RV9TSU5HTEUJCTB4MDIKKworI2RlZmluZSBMRURfVFJJR0dFUl9ERUZBVUxUCQkibm9uZSIKKwor LyoqCisgKiBlbnVtIHFwbnBfbGVkcyAtIFFQTlAgc3VwcG9ydGVkIGxlZCBpZHMKKyAqIEBRUE5Q X0lEX1dMRUQgLSBXaGl0ZSBsZWQgYmFja2xpZ2h0CisgKi8KK2VudW0gcXBucF9sZWRzIHsKKwlR UE5QX0lEX0ZMQVNIMV9MRUQwID0gMSwKKwlRUE5QX0lEX0ZMQVNIMV9MRUQxLAorCVFQTlBfSURf TUFYLAorfTsKKworZW51bSBmbGFzaF9oZWFkcm9vbSB7CisJSEVBRFJPT01fMjUwbVYgPSAwLAor CUhFQURST09NXzMwMG1WLAorCUhFQURST09NXzQwMG1WLAorCUhFQURST09NXzUwMG1WLAorfTsK KworZW51bSBmbGFzaF9zdGFydHVwX2RseSB7CisJREVMQVlfMTB1cyA9IDAsCisJREVMQVlfMzJ1 cywKKwlERUxBWV82NHVzLAorCURFTEFZXzEyOHVzLAorfTsKKworc3RhdGljIHU4IGZsYXNoX2Rl YnVnX3JlZ3NbXSA9IHsKKwkweDQwLCAweDQxLCAweDQyLCAweDQzLCAweDQ0LCAweDQ4LCAweDQ5 LCAweDRiLCAweDRjLAorCTB4NGYsIDB4NDYsIDB4NDcsCit9OworCisvKioKKyAqICBmbGFzaF9j b25maWdfZGF0YSAtIGZsYXNoIGNvbmZpZ3VyYXRpb24gZGF0YQorICogIEBjdXJyZW50X3ByZ20g LSBjdXJyZW50IHRvIGJlIHByb2dyYW1tZWQsIHNjYWxlZCBieSBtYXggbGV2ZWwKKyAqICBAY2xh bXBfY3VyciAtIGNsYW1wIGN1cnJlbnQgdG8gdXNlCisgKiAgQGhlYWRyb29tIC0gaGVhZHJvb20g dmFsdWUgdG8gdXNlCisgKiAgQGR1cmF0aW9uIC0gZHVyYXRpb24gb2YgdGhlIGZsYXNoCisgKiAg QGVuYWJsZV9tb2R1bGUgLSBlbmFibGUgYWRkcmVzcyBmb3IgcGFydGljdWxhciBmbGFzaAorICog IEB0cmlnZ2VyX2ZsYXNoIC0gdHJpZ2dlciBmbGFzaAorICogIEBzdGFydHVwX2RseSAtIHN0YXJ0 dXAgZGVsYXkgZm9yIGZsYXNoCisgKiAgQHN0cm9iZV90eXBlIC0gc2VsZWN0IGJldHdlZW4gc3cg YW5kIGh3IHN0cm9iZQorICogIEBwZXJpcGhlcmFsX3N1YnR5cGUgLSBtb2R1bGUgcGVyaXBoZXJh bCBzdWJ0eXBlCisgKiAgQGN1cnJlbnRfYWRkciAtIGFkZHJlc3MgdG8gd3JpdGUgZm9yIGN1cnJl bnQKKyAqICBAc2Vjb25kX2FkZHIgLSBhZGRyZXNzIG9mIHNlY29uZGFyeSBmbGFzaCB0byBiZSB3 cml0dGVuCisgKiAgQHNhZmV0eV90aW1lciAtIGVuYWJsZSBzYWZldHkgdGltZXIgb3Igd2F0Y2hk b2cgdGltZXIKKyAqICBAdG9yY2hfZW5hYmxlIC0gZW5hYmxlIGZsYXNoIExFRCB0b3JjaCBtb2Rl CisgKiAgQGZsYXNoX3JlZ19nZXQgLSBmbGFzaCByZWd1bGF0b3IgYXR0YWNoZWQgb3Igbm90Cisg KiAgQGZsYXNoX29uIC0gZmxhc2ggc3RhdHVzLCBvbiBvciBvZmYKKyAqICBAdG9yY2hfb24gLSB0 b3JjaCBzdGF0dXMsIG9uIG9yIG9mZgorICogIEBmbGFzaF9ib29zdF9yZWcgLSBib29zdCByZWd1 bGF0b3IgZm9yIGZsYXNoCisgKiAgQHRvcmNoX2Jvb3N0X3JlZyAtIGJvb3N0IHJlZ3VsYXRvciBm b3IgdG9yY2gKKyAqLworc3RydWN0IGZsYXNoX2NvbmZpZ19kYXRhIHsKKwl1OAljdXJyZW50X3By Z207CisJdTgJY2xhbXBfY3VycjsKKwl1OAloZWFkcm9vbTsKKwl1OAlkdXJhdGlvbjsKKwl1OAll bmFibGVfbW9kdWxlOworCXU4CXRyaWdnZXJfZmxhc2g7CisJdTgJc3RhcnR1cF9kbHk7CisJdTgJ c3Ryb2JlX3R5cGU7CisJdTgJcGVyaXBoZXJhbF9zdWJ0eXBlOworCXUxNgljdXJyZW50X2FkZHI7 CisJdTE2CXNlY29uZF9hZGRyOworCWJvb2wJc2FmZXR5X3RpbWVyOworCWJvb2wJdG9yY2hfZW5h YmxlOworCWJvb2wJZmxhc2hfcmVnX2dldDsKKwlib29sCWZsYXNoX29uOworCWJvb2wJdG9yY2hf b247CisJc3RydWN0IHJlZ3VsYXRvciAqZmxhc2hfYm9vc3RfcmVnOworCXN0cnVjdCByZWd1bGF0 b3IgKnRvcmNoX2Jvb3N0X3JlZzsKK307CisKKy8qKgorICogc3RydWN0IHFwbnBfbGVkX2RhdGEg LSBpbnRlcm5hbCBsZWQgZGF0YSBzdHJ1Y3R1cmUKKyAqIEBsZWRfY2xhc3NkZXYgLSBsZWQgY2xh c3MgZGV2aWNlCisgKiBAZGVsYXllZF93b3JrIC0gZGVsYXllZCB3b3JrIGZvciB0dXJuaW5nIG9m ZiB0aGUgTEVECisgKiBAd29yayAtIHdvcmtxdWV1ZSBmb3IgbGVkCisgKiBAaWQgLSBsZWQgaW5k ZXgKKyAqIEBiYXNlX3JlZyAtIGJhc2UgcmVnaXN0ZXIgZ2l2ZW4gaW4gZGV2aWNlIHRyZWUKKyAq IEBsb2NrIC0gdG8gcHJvdGVjdCB0aGUgdHJhbnNhY3Rpb25zCisgKiBAcmVnIC0gY2FjaGVkIHZh bHVlIG9mIGxlZCByZWdpc3RlcgorICogQG51bV9sZWRzIC0gbnVtYmVyIG9mIGxlZHMgaW4gdGhl IG1vZHVsZQorICogQG1heF9jdXJyZW50IC0gbWF4aW11bSBjdXJyZW50IHN1cHBvcnRlZCBieSBM RUQKKyAqIEBkZWZhdWx0X29uIC0gdHJ1ZTogZGVmYXVsdCBzdGF0ZSBtYXgsIGZhbHNlLCBkZWZh dWx0IHN0YXRlIDAKKyAqIEB0dXJuX29mZl9kZWxheV9tcyAtIG51bWJlciBvZiBtc2VjIGJlZm9y ZSB0dXJuaW5nIG9mZiB0aGUgTEVECisgKi8KK3N0cnVjdCBxcG5wX2xlZF9kYXRhIHsKKwlzdHJ1 Y3QgbGVkX2NsYXNzZGV2CWNkZXY7CisJc3RydWN0IHJlZ21hcAkJKnJlZ21hcDsKKwlzdHJ1Y3Qg ZGV2aWNlCQkqZGV2OworCXN0cnVjdCBkZWxheWVkX3dvcmsJZHdvcms7CisJc3RydWN0IHdvcmtf c3RydWN0CXdvcms7CisJaW50CQkJaWQ7CisJdTE2CQkJYmFzZTsKKwl1OAkJCXJlZzsKKwl1OAkJ CW51bV9sZWRzOworCXN0cnVjdCBtdXRleAkJbG9jazsKKwlzdHJ1Y3QgZmxhc2hfY29uZmlnX2Rh dGEJKmZsYXNoX2NmZzsKKwlpbnQJCQltYXhfY3VycmVudDsKKwlib29sCQkJZGVmYXVsdF9vbjsK KwlpbnQJCQl0dXJuX29mZl9kZWxheV9tczsKK307CisKK3N0YXRpYyBpbnQgbGVkX3JlYWRfcmVn KHN0cnVjdCBxcG5wX2xlZF9kYXRhICpsZWQsIHUxNiBvZmZzZXQsIHU4ICpkYXRhKQoreworCXVu c2lnbmVkIGludCB2YWw7CisJaW50IHJldDsKKworCXJldCA9IHJlZ21hcF9yZWFkKGxlZC0+cmVn bWFwLCBsZWQtPmJhc2UgKyBvZmZzZXQsICZ2YWwpOworCWlmIChyZXQgPCAwKQorCQlyZXR1cm4g cmV0OworCisJKmRhdGEgPSB2YWw7CisJcmV0dXJuIDA7Cit9CisKK3N0YXRpYyBpbnQgbGVkX3dy aXRlX3JlZyhzdHJ1Y3QgcXBucF9sZWRfZGF0YSAqbGVkLCB1MTYgb2Zmc2V0LCB1OCBkYXRhKQor eworCXJldHVybiByZWdtYXBfd3JpdGUobGVkLT5yZWdtYXAsIGxlZC0+YmFzZSArIG9mZnNldCwg ZGF0YSk7Cit9CisKK3N0YXRpYyB2b2lkIHFwbnBfZHVtcF9yZWdzKHN0cnVjdCBxcG5wX2xlZF9k YXRhICpsZWQsIHU4IHJlZ3NbXSwgdTggYXJyYXlfc2l6ZSkKK3sKKwlpbnQgaTsKKwl1OCB2YWw7 CisKKwlwcl9kZWJ1ZygiPT09PT0gJXMgTEVEIHJlZ2lzdGVyIGR1bXAgc3RhcnQgPT09PT1cbiIs IGxlZC0+Y2Rldi5uYW1lKTsKKwlmb3IgKGkgPSAwOyBpIDwgYXJyYXlfc2l6ZTsgaSsrKSB7CisJ CWxlZF9yZWFkX3JlZyhsZWQsIHJlZ3NbaV0sICZ2YWwpOworCQlwcl9kZWJ1ZygiJXM6IDB4JXgg PSAweCV4XG4iLCBsZWQtPmNkZXYubmFtZSwKKwkJCQkJbGVkLT5iYXNlICsgcmVnc1tpXSwgdmFs KTsKKwl9CisJcHJfZGVidWcoIj09PT09ICVzIExFRCByZWdpc3RlciBkdW1wIGVuZCA9PT09PVxu IiwgbGVkLT5jZGV2Lm5hbWUpOworfQorCisKK3N0YXRpYyBpbnQgcXBucF9nZXRfY29tbW9uX2Nv bmZpZ3Moc3RydWN0IHFwbnBfbGVkX2RhdGEgKmxlZCwKKwkJCQlzdHJ1Y3QgZGV2aWNlX25vZGUg Km5vZGUpCit7CisJaW50IHJjOworCXUzMiB2YWw7CisJY29uc3QgY2hhciAqdGVtcF9zdHJpbmc7 CisKKwlsZWQtPmNkZXYuZGVmYXVsdF90cmlnZ2VyID0gTEVEX1RSSUdHRVJfREVGQVVMVDsKKwly YyA9IG9mX3Byb3BlcnR5X3JlYWRfc3RyaW5nKG5vZGUsICJsaW51eCxkZWZhdWx0LXRyaWdnZXIi LAorCQkmdGVtcF9zdHJpbmcpOworCWlmICghcmMpCisJCWxlZC0+Y2Rldi5kZWZhdWx0X3RyaWdn ZXIgPSB0ZW1wX3N0cmluZzsKKwllbHNlIGlmIChyYyAhPSAtRUlOVkFMKQorCQlyZXR1cm4gcmM7 CisKKwlsZWQtPmRlZmF1bHRfb24gPSBmYWxzZTsKKwlyYyA9IG9mX3Byb3BlcnR5X3JlYWRfc3Ry aW5nKG5vZGUsICJxY29tLGRlZmF1bHQtc3RhdGUiLAorCQkmdGVtcF9zdHJpbmcpOworCWlmICgh cmMpIHsKKwkJaWYgKHN0cm5jbXAodGVtcF9zdHJpbmcsICJvbiIsIHNpemVvZigib24iKSkgPT0g MCkKKwkJCWxlZC0+ZGVmYXVsdF9vbiA9IHRydWU7CisJfSBlbHNlIGlmIChyYyAhPSAtRUlOVkFM KQorCQlyZXR1cm4gcmM7CisKKwlsZWQtPnR1cm5fb2ZmX2RlbGF5X21zID0gMDsKKwlyYyA9IG9m X3Byb3BlcnR5X3JlYWRfdTMyKG5vZGUsICJxY29tLHR1cm4tb2ZmLWRlbGF5LW1zIiwgJnZhbCk7 CisJaWYgKCFyYykKKwkJbGVkLT50dXJuX29mZl9kZWxheV9tcyA9IHZhbDsKKwllbHNlIGlmIChy YyAhPSAtRUlOVkFMKQorCQlyZXR1cm4gcmM7CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIHZv aWQgcXBucF9sZWRfc2V0KHN0cnVjdCBsZWRfY2xhc3NkZXYgKmxlZF9jZGV2LAorCQkJCWVudW0g bGVkX2JyaWdodG5lc3MgdmFsdWUpCit7CisJc3RydWN0IHFwbnBfbGVkX2RhdGEgKmxlZDsKKwor CWxlZCA9IGNvbnRhaW5lcl9vZihsZWRfY2Rldiwgc3RydWN0IHFwbnBfbGVkX2RhdGEsIGNkZXYp OworCWlmICh2YWx1ZSA8IExFRF9PRkYgfHwgdmFsdWUgPiBsZWQtPmNkZXYubWF4X2JyaWdodG5l c3MpIHsKKwkJZGV2X2VycihsZWQtPmRldiwgIkludmFsaWQgYnJpZ2h0bmVzcyB2YWx1ZVxuIik7 CisJCXJldHVybjsKKwl9CisKKwlsZWQtPmNkZXYuYnJpZ2h0bmVzcyA9IHZhbHVlOworCXNjaGVk dWxlX3dvcmsoJmxlZC0+d29yayk7Cit9CisKK3N0YXRpYyBlbnVtIGxlZF9icmlnaHRuZXNzIHFw bnBfbGVkX2dldChzdHJ1Y3QgbGVkX2NsYXNzZGV2ICpsZWRfY2RldikKK3sKKwlzdHJ1Y3QgcXBu cF9sZWRfZGF0YSAqbGVkOworCisJbGVkID0gY29udGFpbmVyX29mKGxlZF9jZGV2LCBzdHJ1Y3Qg cXBucF9sZWRfZGF0YSwgY2Rldik7CisKKwlyZXR1cm4gbGVkLT5jZGV2LmJyaWdodG5lc3M7Cit9 CisKK3N0YXRpYyBpbnQgcXBucF9nZXRfY29uZmlnX2ZsYXNoKHN0cnVjdCBxcG5wX2xlZF9kYXRh ICpsZWQsCisJCQkJc3RydWN0IGRldmljZV9ub2RlICpub2RlLCBib29sICpyZWdfc2V0KQorewor CWludCByYzsKKwl1MzIgdmFsOworCisJbGVkLT5mbGFzaF9jZmcgPSBkZXZtX2t6YWxsb2MobGVk LT5kZXYsCisJCQkJc2l6ZW9mKHN0cnVjdCBmbGFzaF9jb25maWdfZGF0YSksIEdGUF9LRVJORUwp OworCWlmICghbGVkLT5mbGFzaF9jZmcpIHsKKwkJZGV2X2VycihsZWQtPmRldiwgIlVuYWJsZSB0 byBhbGxvY2F0ZSBtZW1vcnlcbiIpOworCQlyZXR1cm4gLUVOT01FTTsKKwl9CisKKwlyYyA9IGxl ZF9yZWFkX3JlZyhsZWQsIEZMQVNIX1BFUklQSEVSQUxfU1VCVFlQRSwKKwkJCSZsZWQtPmZsYXNo X2NmZy0+cGVyaXBoZXJhbF9zdWJ0eXBlKTsKKwlpZiAocmMpIHsKKwkJZGV2X2VycihsZWQtPmRl diwKKwkJCSJVbmFibGUgdG8gcmVhZCBmcm9tIGFkZHI9JXgsIHJjKCVkKVxuIiwKKwkJCUZMQVNI X1BFUklQSEVSQUxfU1VCVFlQRSwgcmMpOworCX0KKworCWxlZC0+Zmxhc2hfY2ZnLT50b3JjaF9l bmFibGUgPQorCQlvZl9wcm9wZXJ0eV9yZWFkX2Jvb2wobm9kZSwgInFjb20sdG9yY2gtZW5hYmxl Iik7CisKKwlpZiAobGVkLT5pZCA9PSBRUE5QX0lEX0ZMQVNIMV9MRUQwKSB7CisJCWxlZC0+Zmxh c2hfY2ZnLT5lbmFibGVfbW9kdWxlID0gRkxBU0hfRU5BQkxFX0xFRF8wOworCQlsZWQtPmZsYXNo X2NmZy0+Y3VycmVudF9hZGRyID0gRkxBU0hfTEVEXzBfQ1VSUjsKKwkJbGVkLT5mbGFzaF9jZmct PnRyaWdnZXJfZmxhc2ggPSBGTEFTSF9MRURfMF9PVVRQVVQ7CisJCWlmICghKnJlZ19zZXQpIHsK KwkJCWxlZC0+Zmxhc2hfY2ZnLT5mbGFzaF9ib29zdF9yZWcgPQorCQkJCXJlZ3VsYXRvcl9nZXQo bGVkLT5kZXYsCisJCQkJCQkJImZsYXNoLWJvb3N0Iik7CisJCQlpZiAoSVNfRVJSKGxlZC0+Zmxh c2hfY2ZnLT5mbGFzaF9ib29zdF9yZWcpKSB7CisJCQkJcmMgPSBQVFJfRVJSKGxlZC0+Zmxhc2hf Y2ZnLT5mbGFzaF9ib29zdF9yZWcpOworCQkJCWRldl9lcnIobGVkLT5kZXYsCisJCQkJCSJSZWd1 bGF0b3IgZ2V0IGZhaWxlZCglZClcbiIsIHJjKTsKKwkJCQlnb3RvIGVycm9yX2dldF9mbGFzaF9y ZWc7CisJCQl9CisJCQlsZWQtPmZsYXNoX2NmZy0+Zmxhc2hfcmVnX2dldCA9IHRydWU7CisJCQkq cmVnX3NldCA9IHRydWU7CisJCX0gZWxzZQorCQkJbGVkLT5mbGFzaF9jZmctPmZsYXNoX3JlZ19n ZXQgPSBmYWxzZTsKKworCQlpZiAobGVkLT5mbGFzaF9jZmctPnRvcmNoX2VuYWJsZSkgeworCQkJ bGVkLT5mbGFzaF9jZmctPnNlY29uZF9hZGRyID0KKwkJCQkJCUZMQVNIX0xFRF8xX0NVUlI7CisJ CX0KKwl9IGVsc2UgaWYgKGxlZC0+aWQgPT0gUVBOUF9JRF9GTEFTSDFfTEVEMSkgeworCQlsZWQt PmZsYXNoX2NmZy0+ZW5hYmxlX21vZHVsZSA9IEZMQVNIX0VOQUJMRV9MRURfMTsKKwkJbGVkLT5m bGFzaF9jZmctPmN1cnJlbnRfYWRkciA9IEZMQVNIX0xFRF8xX0NVUlI7CisJCWxlZC0+Zmxhc2hf Y2ZnLT50cmlnZ2VyX2ZsYXNoID0gRkxBU0hfTEVEXzFfT1VUUFVUOworCQlpZiAoISpyZWdfc2V0 KSB7CisJCQlsZWQtPmZsYXNoX2NmZy0+Zmxhc2hfYm9vc3RfcmVnID0KKwkJCQkJcmVndWxhdG9y X2dldChsZWQtPmRldiwKKwkJCQkJCQkJImZsYXNoLWJvb3N0Iik7CisJCQlpZiAoSVNfRVJSKGxl ZC0+Zmxhc2hfY2ZnLT5mbGFzaF9ib29zdF9yZWcpKSB7CisJCQkJcmMgPSBQVFJfRVJSKGxlZC0+ Zmxhc2hfY2ZnLT5mbGFzaF9ib29zdF9yZWcpOworCQkJCWRldl9lcnIobGVkLT5kZXYsCisJCQkJ CSJSZWd1bGF0b3IgZ2V0IGZhaWxlZCglZClcbiIsIHJjKTsKKwkJCQlnb3RvIGVycm9yX2dldF9m bGFzaF9yZWc7CisJCQl9CisJCQlsZWQtPmZsYXNoX2NmZy0+Zmxhc2hfcmVnX2dldCA9IHRydWU7 CisJCQkqcmVnX3NldCA9IHRydWU7CisJCX0gZWxzZQorCQkJbGVkLT5mbGFzaF9jZmctPmZsYXNo X3JlZ19nZXQgPSBmYWxzZTsKKworCQlpZiAobGVkLT5mbGFzaF9jZmctPnRvcmNoX2VuYWJsZSkg eworCQkJbGVkLT5mbGFzaF9jZmctPnNlY29uZF9hZGRyID0KKwkJCQkJCUZMQVNIX0xFRF8wX0NV UlI7CisJCX0KKwl9IGVsc2UgeworCQlkZXZfZXJyKGxlZC0+ZGV2LCAiVW5rbm93biBmbGFzaCBM RUQgbmFtZSBnaXZlblxuIik7CisJCXJldHVybiAtRUlOVkFMOworCX0KKworCWlmIChsZWQtPmZs YXNoX2NmZy0+dG9yY2hfZW5hYmxlKSB7CisJCWlmIChvZl9maW5kX3Byb3BlcnR5KG9mX2dldF9w YXJlbnQobm9kZSksICJ0b3JjaC1ib29zdC1zdXBwbHkiLAorCQkJCQkJCQkJTlVMTCkpIHsKKwkJ CWxlZC0+Zmxhc2hfY2ZnLT50b3JjaF9ib29zdF9yZWcgPQorCQkJCXJlZ3VsYXRvcl9nZXQobGVk LT5kZXYsCisJCQkJCQkJCSJ0b3JjaC1ib29zdCIpOworCQkJaWYgKElTX0VSUihsZWQtPmZsYXNo X2NmZy0+dG9yY2hfYm9vc3RfcmVnKSkgeworCQkJCXJjID0gUFRSX0VSUihsZWQtPmZsYXNoX2Nm Zy0+dG9yY2hfYm9vc3RfcmVnKTsKKwkJCQlkZXZfZXJyKGxlZC0+ZGV2LAorCQkJCQkiVG9yY2gg cmVndWxhdG9yIGdldCBmYWlsZWQoJWQpXG4iLCByYyk7CisJCQkJZ290byBlcnJvcl9nZXRfdG9y Y2hfcmVnOworCQkJfQorCQkJbGVkLT5mbGFzaF9jZmctPmVuYWJsZV9tb2R1bGUgPSBGTEFTSF9F TkFCTEVfTU9EVUxFOworCQl9IGVsc2UKKwkJCWxlZC0+Zmxhc2hfY2ZnLT5lbmFibGVfbW9kdWxl ID0gRkxBU0hfRU5BQkxFX0FMTDsKKwkJbGVkLT5mbGFzaF9jZmctPnRyaWdnZXJfZmxhc2ggPSBG TEFTSF9TVFJPQkVfU1c7CisJfQorCisJcmMgPSBvZl9wcm9wZXJ0eV9yZWFkX3UzMihub2RlLCAi cWNvbSxjdXJyZW50IiwgJnZhbCk7CisJaWYgKCFyYykgeworCQlpZiAobGVkLT5mbGFzaF9jZmct PnRvcmNoX2VuYWJsZSkgeworCQkJbGVkLT5mbGFzaF9jZmctPmN1cnJlbnRfcHJnbSA9ICh2YWwg KgorCQkJCVRPUkNIX01BWF9MRVZFTCAvIGxlZC0+bWF4X2N1cnJlbnQpOworCQkJcmV0dXJuIDA7 CisJCX0KKwkJZWxzZQorCQkJbGVkLT5mbGFzaF9jZmctPmN1cnJlbnRfcHJnbSA9ICh2YWwgKgor CQkJCUZMQVNIX01BWF9MRVZFTCAvIGxlZC0+bWF4X2N1cnJlbnQpOworCX0gZWxzZQorCQlpZiAo bGVkLT5mbGFzaF9jZmctPnRvcmNoX2VuYWJsZSkKKwkJCWdvdG8gZXJyb3JfZ2V0X3RvcmNoX3Jl ZzsKKwkJZWxzZQorCQkJZ290byBlcnJvcl9nZXRfZmxhc2hfcmVnOworCisJcmMgPSBvZl9wcm9w ZXJ0eV9yZWFkX3UzMihub2RlLCAicWNvbSxoZWFkcm9vbSIsICZ2YWwpOworCWlmICghcmMpCisJ CWxlZC0+Zmxhc2hfY2ZnLT5oZWFkcm9vbSA9ICh1OCkgdmFsOworCWVsc2UgaWYgKHJjID09IC1F SU5WQUwpCisJCWxlZC0+Zmxhc2hfY2ZnLT5oZWFkcm9vbSA9IEhFQURST09NXzUwMG1WOworCWVs c2UKKwkJZ290byBlcnJvcl9nZXRfZmxhc2hfcmVnOworCisJcmMgPSBvZl9wcm9wZXJ0eV9yZWFk X3UzMihub2RlLCAicWNvbSxkdXJhdGlvbiIsICZ2YWwpOworCWlmICghcmMpCisJCWxlZC0+Zmxh c2hfY2ZnLT5kdXJhdGlvbiA9ICgoKHU4KSB2YWwpIC0gMTApIC8gMTA7CisJZWxzZSBpZiAocmMg PT0gLUVJTlZBTCkKKwkJbGVkLT5mbGFzaF9jZmctPmR1cmF0aW9uID0gRkxBU0hfRFVSQVRJT05f MjAwbXM7CisJZWxzZQorCQlnb3RvIGVycm9yX2dldF9mbGFzaF9yZWc7CisKKwlyYyA9IG9mX3By b3BlcnR5X3JlYWRfdTMyKG5vZGUsICJxY29tLGNsYW1wLWN1cnIiLCAmdmFsKTsKKwlpZiAoIXJj KQorCQlsZWQtPmZsYXNoX2NmZy0+Y2xhbXBfY3VyciA9ICh2YWwgKgorCQkJCUZMQVNIX01BWF9M RVZFTCAvIGxlZC0+bWF4X2N1cnJlbnQpOworCWVsc2UgaWYgKHJjID09IC1FSU5WQUwpCisJCWxl ZC0+Zmxhc2hfY2ZnLT5jbGFtcF9jdXJyID0gRkxBU0hfQ0xBTVBfMjAwbUE7CisJZWxzZQorCQln b3RvIGVycm9yX2dldF9mbGFzaF9yZWc7CisKKwlyYyA9IG9mX3Byb3BlcnR5X3JlYWRfdTMyKG5v ZGUsICJxY29tLHN0YXJ0dXAtZGx5IiwgJnZhbCk7CisJaWYgKCFyYykKKwkJbGVkLT5mbGFzaF9j ZmctPnN0YXJ0dXBfZGx5ID0gKHU4KSB2YWw7CisJZWxzZSBpZiAocmMgPT0gLUVJTlZBTCkKKwkJ bGVkLT5mbGFzaF9jZmctPnN0YXJ0dXBfZGx5ID0gREVMQVlfMTI4dXM7CisJZWxzZQorCQlnb3Rv IGVycm9yX2dldF9mbGFzaF9yZWc7CisKKwlsZWQtPmZsYXNoX2NmZy0+c2FmZXR5X3RpbWVyID0K KwkJb2ZfcHJvcGVydHlfcmVhZF9ib29sKG5vZGUsICJxY29tLHNhZmV0eS10aW1lciIpOworCisJ cmV0dXJuIDA7CisKK2Vycm9yX2dldF90b3JjaF9yZWc6CisJcmVndWxhdG9yX3B1dChsZWQtPmZs YXNoX2NmZy0+dG9yY2hfYm9vc3RfcmVnKTsKKworZXJyb3JfZ2V0X2ZsYXNoX3JlZzoKKwlyZWd1 bGF0b3JfcHV0KGxlZC0+Zmxhc2hfY2ZnLT5mbGFzaF9ib29zdF9yZWcpOworCXJldHVybiByYzsK KworfQorCitzdGF0aWMgc3NpemVfdCBsZWRfbW9kZV9zdG9yZShzdHJ1Y3QgZGV2aWNlICpkZXYs CisJCQlzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwKKwkJCWNvbnN0IGNoYXIgKmJ1Ziwg c2l6ZV90IGNvdW50KQoreworCXN0cnVjdCBxcG5wX2xlZF9kYXRhICpsZWQ7CisJdW5zaWduZWQg bG9uZyBzdGF0ZTsKKwlzdHJ1Y3QgbGVkX2NsYXNzZGV2ICpsZWRfY2RldiA9IGRldl9nZXRfZHJ2 ZGF0YShkZXYpOworCXNzaXplX3QgcmV0ID0gLUVJTlZBTDsKKworCXJldCA9IGtzdHJ0b3VsKGJ1 ZiwgMTAsICZzdGF0ZSk7CisJaWYgKHJldCkKKwkJcmV0dXJuIHJldDsKKworCWxlZCA9IGNvbnRh aW5lcl9vZihsZWRfY2Rldiwgc3RydWN0IHFwbnBfbGVkX2RhdGEsIGNkZXYpOworCisJLyogJzEn IHRvIGVuYWJsZSB0b3JjaCBtb2RlOyAnMCcgdG8gc3dpdGNoIHRvIGZsYXNoIG1vZGUgKi8KKwlp ZiAoc3RhdGUgPT0gMSkKKwkJbGVkLT5mbGFzaF9jZmctPnRvcmNoX2VuYWJsZSA9IHRydWU7CisJ ZWxzZQorCQlsZWQtPmZsYXNoX2NmZy0+dG9yY2hfZW5hYmxlID0gZmFsc2U7CisKKwlyZXR1cm4g Y291bnQ7Cit9CisKK3N0YXRpYyBzc2l6ZV90IGxlZF9zdHJvYmVfdHlwZV9zdG9yZShzdHJ1Y3Qg ZGV2aWNlICpkZXYsCisJCQlzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwKKwkJCWNvbnN0 IGNoYXIgKmJ1Ziwgc2l6ZV90IGNvdW50KQoreworCXN0cnVjdCBxcG5wX2xlZF9kYXRhICpsZWQ7 CisJdW5zaWduZWQgbG9uZyBzdGF0ZTsKKwlzdHJ1Y3QgbGVkX2NsYXNzZGV2ICpsZWRfY2RldiA9 IGRldl9nZXRfZHJ2ZGF0YShkZXYpOworCXNzaXplX3QgcmV0ID0gLUVJTlZBTDsKKworCXJldCA9 IGtzdHJ0b3VsKGJ1ZiwgMTAsICZzdGF0ZSk7CisJaWYgKHJldCkKKwkJcmV0dXJuIHJldDsKKwor CWxlZCA9IGNvbnRhaW5lcl9vZihsZWRfY2Rldiwgc3RydWN0IHFwbnBfbGVkX2RhdGEsIGNkZXYp OworCisJLyogJzAnIGZvciBzdyBzdHJvYmU7ICcxJyBmb3IgaHcgc3Ryb2JlICovCisJaWYgKHN0 YXRlID09IDEpCisJCWxlZC0+Zmxhc2hfY2ZnLT5zdHJvYmVfdHlwZSA9IDE7CisJZWxzZQorCQls ZWQtPmZsYXNoX2NmZy0+c3Ryb2JlX3R5cGUgPSAwOworCisJcmV0dXJuIGNvdW50OworfQorCitz dGF0aWMgREVWSUNFX0FUVFIobGVkX21vZGUsIDA2NjQsIE5VTEwsIGxlZF9tb2RlX3N0b3JlKTsK K3N0YXRpYyBERVZJQ0VfQVRUUihzdHJvYmUsIDA2NjQsIE5VTEwsIGxlZF9zdHJvYmVfdHlwZV9z dG9yZSk7CisKK3N0YXRpYyBzdHJ1Y3QgYXR0cmlidXRlICpsZWRfYXR0cnNbXSA9IHsKKwkmZGV2 X2F0dHJfbGVkX21vZGUuYXR0ciwKKwkmZGV2X2F0dHJfc3Ryb2JlLmF0dHIsCisJTlVMTAorfTsK Kworc3RhdGljIGNvbnN0IHN0cnVjdCBhdHRyaWJ1dGVfZ3JvdXAgbGVkX2F0dHJfZ3JvdXAgPSB7 CisJLmF0dHJzID0gbGVkX2F0dHJzLAorfTsKKworc3RhdGljIGludCBxcG5wX2xlZF9zZXRfbWF4 X2JyaWdodG5lc3Moc3RydWN0IHFwbnBfbGVkX2RhdGEgKmxlZCkKK3sKKwlzd2l0Y2ggKGxlZC0+ aWQpIHsKKwljYXNlIFFQTlBfSURfRkxBU0gxX0xFRDA6CisJY2FzZSBRUE5QX0lEX0ZMQVNIMV9M RUQxOgorCQlsZWQtPmNkZXYubWF4X2JyaWdodG5lc3MgPSBsZWQtPm1heF9jdXJyZW50OworCQli cmVhazsKKwlkZWZhdWx0OgorCQlkZXZfZXJyKGxlZC0+ZGV2LCAiSW52YWxpZCBMRUQoJWQpXG4i LCBsZWQtPmlkKTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCisJcmV0dXJuIDA7Cit9CisKK3N0 YXRpYyBpbnQKK3FwbnBfbGVkX21hc2tlZF93cml0ZShzdHJ1Y3QgcXBucF9sZWRfZGF0YSAqbGVk LCB1MTYgYWRkciwgdTggbWFzaywgdTggdmFsKQoreworCWludCByYzsKKwl1OCByZWc7CisKKwly YyA9IGxlZF9yZWFkX3JlZyhsZWQsIGFkZHIsICZyZWcpOworCWlmIChyYykgeworCQlkZXZfZXJy KGxlZC0+ZGV2LAorCQkJIlVuYWJsZSB0byByZWFkIGZyb20gYWRkcj0leCwgcmMoJWQpXG4iLCBh ZGRyLCByYyk7CisJfQorCisJcmVnICY9IH5tYXNrOworCXJlZyB8PSB2YWw7CisKKwlyYyA9IGxl ZF93cml0ZV9yZWcobGVkLCBhZGRyLCByZWcpOworCWlmIChyYykKKwkJZGV2X2VycihsZWQtPmRl diwKKwkJCSJVbmFibGUgdG8gd3JpdGUgdG8gYWRkcj0leCwgcmMoJWQpXG4iLCBhZGRyLCByYyk7 CisJcmV0dXJuIHJjOworfQorCitzdGF0aWMgaW50IHFwbnBfZmxhc2hfaW5pdChzdHJ1Y3QgcXBu cF9sZWRfZGF0YSAqbGVkKQoreworCWludCByYzsKKworCWxlZC0+Zmxhc2hfY2ZnLT5mbGFzaF9v biA9IGZhbHNlOworCisJcmMgPSBxcG5wX2xlZF9tYXNrZWRfd3JpdGUobGVkLAorCQlGTEFTSF9M RURfU1RST0JFX0NUUkwsCisJCUZMQVNIX1NUUk9CRV9NQVNLLCBGTEFTSF9ESVNBQkxFX0FMTCk7 CisJaWYgKHJjKSB7CisJCWRldl9lcnIobGVkLT5kZXYsCisJCQkiTEVEICVkIGZsYXNoIHdyaXRl IGZhaWxlZCglZClcbiIsIGxlZC0+aWQsIHJjKTsKKwkJcmV0dXJuIHJjOworCX0KKworCS8qIERp c2FibGUgZmxhc2ggTEVEIG1vZHVsZSAqLworCXJjID0gcXBucF9sZWRfbWFza2VkX3dyaXRlKGxl ZCwgRkxBU0hfRU5BQkxFX0NPTlRST0wsCisJCUZMQVNIX0VOQUJMRV9NT0RVTEVfTUFTSywgRkxB U0hfRElTQUJMRV9BTEwpOworCWlmIChyYykgeworCQlkZXZfZXJyKGxlZC0+ZGV2LAorCQkJIkVu YWJsZSByZWcgd3JpdGUgZmFpbGVkKCVkKVxuIiwgcmMpOworCQlyZXR1cm4gcmM7CisJfQorCisJ aWYgKGxlZC0+Zmxhc2hfY2ZnLT50b3JjaF9lbmFibGUpCisJCXJldHVybiAwOworCisJLyogU2V0 IGhlYWRyb29tICovCisJcmMgPSBxcG5wX2xlZF9tYXNrZWRfd3JpdGUobGVkLCBGTEFTSF9IRUFE Uk9PTSwKKwkJRkxBU0hfSEVBRFJPT01fTUFTSywgbGVkLT5mbGFzaF9jZmctPmhlYWRyb29tKTsK KwlpZiAocmMpIHsKKwkJZGV2X2VycihsZWQtPmRldiwKKwkJCSJIZWFkcm9vbSByZWcgd3JpdGUg ZmFpbGVkKCVkKVxuIiwgcmMpOworCQlyZXR1cm4gcmM7CisJfQorCisJLyogU2V0IHN0YXJ0dXAg ZGVsYXkgKi8KKwlyYyA9IHFwbnBfbGVkX21hc2tlZF93cml0ZShsZWQsCisJCUZMQVNIX1NUQVJU VVBfREVMQVksIEZMQVNIX1NUQVJUVVBfRExZX01BU0ssCisJCWxlZC0+Zmxhc2hfY2ZnLT5zdGFy dHVwX2RseSk7CisJaWYgKHJjKSB7CisJCWRldl9lcnIobGVkLT5kZXYsCisJCQkiU3RhcnR1cCBk ZWxheSByZWcgd3JpdGUgZmFpbGVkKCVkKVxuIiwgcmMpOworCQlyZXR1cm4gcmM7CisJfQorCisJ LyogU2V0IHRpbWVyIGNvbnRyb2wgLSBzYWZldHkgb3Igd2F0Y2hkb2cgKi8KKwlpZiAobGVkLT5m bGFzaF9jZmctPnNhZmV0eV90aW1lcikgeworCQlyYyA9IHFwbnBfbGVkX21hc2tlZF93cml0ZShs ZWQsCisJCQlGTEFTSF9MRURfVE1SX0NUUkwsCisJCQlGTEFTSF9UTVJfTUFTSywgRkxBU0hfVE1S X1NBRkVUWSk7CisJCWlmIChyYykgeworCQkJZGV2X2VycihsZWQtPmRldiwKKwkJCQkiTEVEIHRp bWVyIGN0cmwgcmVnIHdyaXRlIGZhaWxlZCglZClcbiIsCisJCQkJcmMpOworCQkJcmV0dXJuIHJj OworCQl9CisJfQorCisJLyogU2V0IFZyZWcgZm9yY2UgKi8KKwlyYyA9IHFwbnBfbGVkX21hc2tl ZF93cml0ZShsZWQsCUZMQVNIX1ZSRUdfT0tfRk9SQ0UsCisJCUZMQVNIX1ZSRUdfTUFTSywgRkxB U0hfSFdfVlJFR19PSyk7CisJaWYgKHJjKSB7CisJCWRldl9lcnIobGVkLT5kZXYsCisJCQkiVnJl ZyBPSyByZWcgd3JpdGUgZmFpbGVkKCVkKVxuIiwgcmMpOworCQlyZXR1cm4gcmM7CisJfQorCisJ LyogU2V0IHNlbGYgZmF1bHQgY2hlY2sgKi8KKwlyYyA9IHFwbnBfbGVkX21hc2tlZF93cml0ZShs ZWQsIEZMQVNIX0ZBVUxUX0RFVEVDVCwKKwkJRkxBU0hfRkFVTFRfREVURUNUX01BU0ssIEZMQVNI X1NFTEZDSEVDS19ESVNBQkxFKTsKKwlpZiAocmMpIHsKKwkJZGV2X2VycihsZWQtPmRldiwKKwkJ CSJGYXVsdCBkZXRlY3QgcmVnIHdyaXRlIGZhaWxlZCglZClcbiIsIHJjKTsKKwkJcmV0dXJuIHJj OworCX0KKworCS8qIFNldCBtYXNrIGVuYWJsZSAqLworCXJjID0gcXBucF9sZWRfbWFza2VkX3dy aXRlKGxlZCwgRkxBU0hfTUFTS19FTkFCTEUsCisJCUZMQVNIX01BU0tfUkVHX01BU0ssIEZMQVNI X01BU0tfMSk7CisJaWYgKHJjKSB7CisJCWRldl9lcnIobGVkLT5kZXYsCisJCQkiTWFzayBlbmFi bGUgcmVnIHdyaXRlIGZhaWxlZCglZClcbiIsIHJjKTsKKwkJcmV0dXJuIHJjOworCX0KKworCS8q IFNldCByYW1wIHJhdGUgKi8KKwlyYyA9IHFwbnBfbGVkX21hc2tlZF93cml0ZShsZWQsIEZMQVNI X1JBTVBfUkFURSwKKwkJRkxBU0hfUkFNUF9SQVRFX01BU0ssIDB4QkYpOworCWlmIChyYykgewor CQlkZXZfZXJyKGxlZC0+ZGV2LAorCQkJIlJhbXAgcmF0ZSByZWcgd3JpdGUgZmFpbGVkKCVkKVxu IiwgcmMpOworCQlyZXR1cm4gcmM7CisJfQorCisJLyogRW5hYmxlIFZQSF9QV1JfRFJPT1AgYW5k IHNldCB0aHJlc2hvbGQgdG8gMi45ViAqLworCXJjID0gcXBucF9sZWRfbWFza2VkX3dyaXRlKGxl ZCwgRkxBU0hfVlBIX1BXUl9EUk9PUCwKKwkJCQkJRkxBU0hfVlBIX1BXUl9EUk9PUF9NQVNLLCAw eEMyKTsKKwlpZiAocmMpIHsKKwkJZGV2X2VycihsZWQtPmRldiwKKwkJCSJGTEFTSF9WUEhfUFdS X0RST09QIHJlZyB3cml0ZSBmYWlsZWQoJWQpXG4iLCByYyk7CisJCXJldHVybiByYzsKKwl9CisK KwlsZWQtPmZsYXNoX2NmZy0+c3Ryb2JlX3R5cGUgPSAwOworCisJLyogZHVtcCBmbGFzaCByZWdp c3RlcnMgKi8KKwlxcG5wX2R1bXBfcmVncyhsZWQsIGZsYXNoX2RlYnVnX3JlZ3MsIEFSUkFZX1NJ WkUoZmxhc2hfZGVidWdfcmVncykpOworCisJcmV0dXJuIDA7Cit9CisKK3N0YXRpYyBpbnQgcXBu cF9sZWRfaW5pdGlhbGl6ZShzdHJ1Y3QgcXBucF9sZWRfZGF0YSAqbGVkKQoreworCWludCByYyA9 IDA7CisKKwlzd2l0Y2ggKGxlZC0+aWQpIHsKKwljYXNlIFFQTlBfSURfRkxBU0gxX0xFRDA6CisJ Y2FzZSBRUE5QX0lEX0ZMQVNIMV9MRUQxOgorCQlyYyA9IHFwbnBfZmxhc2hfaW5pdChsZWQpOwor CQlpZiAocmMpCisJCQlkZXZfZXJyKGxlZC0+ZGV2LAorCQkJCSJGTEFTSCBpbml0aWFsaXplIGZh aWxlZCglZClcbiIsIHJjKTsKKwkJYnJlYWs7CisJZGVmYXVsdDoKKwkJZGV2X2VycihsZWQtPmRl diwgIkludmFsaWQgTEVEKCVkKVxuIiwgbGVkLT5pZCk7CisJCXJldHVybiAtRUlOVkFMOworCX0K KworCXJldHVybiByYzsKK30KKworc3RhdGljIGludCBxcG5wX2ZsYXNoX3JlZ3VsYXRvcl9vcGVy YXRlKHN0cnVjdCBxcG5wX2xlZF9kYXRhICpsZWQsIGJvb2wgb24pCit7CisJaW50IHJjLCBpOwor CXN0cnVjdCBxcG5wX2xlZF9kYXRhICpsZWRfYXJyYXk7CisJYm9vbCByZWd1bGF0b3Jfb24gPSBm YWxzZTsKKworCWxlZF9hcnJheSA9IGRldl9nZXRfZHJ2ZGF0YShsZWQtPmRldik7CisJaWYgKCFs ZWRfYXJyYXkpIHsKKwkJZGV2X2VycihsZWQtPmRldiwKKwkJCQkiVW5hYmxlIHRvIGdldCBMRUQg YXJyYXlcbiIpOworCQlyZXR1cm4gLUVJTlZBTDsKKwl9CisKKwlmb3IgKGkgPSAwOyBpIDwgbGVk LT5udW1fbGVkczsgaSsrKQorCQlyZWd1bGF0b3Jfb24gfD0gbGVkX2FycmF5W2ldLmZsYXNoX2Nm Zy0+Zmxhc2hfb247CisKKwlpZiAoIW9uKQorCQlnb3RvIHJlZ3VsYXRvcl90dXJuX29mZjsKKwor CWlmICghcmVndWxhdG9yX29uICYmICFsZWQtPmZsYXNoX2NmZy0+Zmxhc2hfb24pIHsKKwkJZm9y IChpID0gMDsgaSA8IGxlZC0+bnVtX2xlZHM7IGkrKykgeworCQkJaWYgKGxlZF9hcnJheVtpXS5m bGFzaF9jZmctPmZsYXNoX3JlZ19nZXQpIHsKKwkJCQlyYyA9IHJlZ3VsYXRvcl9lbmFibGUoCisJ CQkJCWxlZF9hcnJheVtpXS5mbGFzaF9jZmctPlwKKwkJCQkJZmxhc2hfYm9vc3RfcmVnKTsKKwkJ CQlpZiAocmMpIHsKKwkJCQkJZGV2X2VycihsZWQtPmRldiwKKwkJCQkJCSJSZWd1bGF0b3IgZW5h YmxlIGZhaWxlZCglZClcbiIsCisJCQkJCQkJCQlyYyk7CisJCQkJCXJldHVybiByYzsKKwkJCQl9 CisJCQkJbGVkLT5mbGFzaF9jZmctPmZsYXNoX29uID0gdHJ1ZTsKKwkJCX0KKwkJCWJyZWFrOwor CQl9CisJfQorCisJcmV0dXJuIDA7CisKK3JlZ3VsYXRvcl90dXJuX29mZjoKKwlpZiAocmVndWxh dG9yX29uICYmIGxlZC0+Zmxhc2hfY2ZnLT5mbGFzaF9vbikgeworCQlmb3IgKGkgPSAwOyBpIDwg bGVkLT5udW1fbGVkczsgaSsrKSB7CisJCQlpZiAobGVkX2FycmF5W2ldLmZsYXNoX2NmZy0+Zmxh c2hfcmVnX2dldCkgeworCQkJCXJjID0gcXBucF9sZWRfbWFza2VkX3dyaXRlKGxlZCwKKwkJCQkJ RkxBU0hfRU5BQkxFX0NPTlRST0wsCisJCQkJCUZMQVNIX0VOQUJMRV9NQVNLLAorCQkJCQlGTEFT SF9ESVNBQkxFX0FMTCk7CisJCQkJaWYgKHJjKSB7CisJCQkJCWRldl9lcnIobGVkLT5kZXYsCisJ CQkJCQkiRW5hYmxlIHJlZyB3cml0ZSBmYWlsZWQoJWQpXG4iLAorCQkJCQkJcmMpOworCQkJCX0K KworCQkJCXJjID0gcmVndWxhdG9yX2Rpc2FibGUobGVkX2FycmF5W2ldLmZsYXNoX2NmZy0+XAor CQkJCQkJCWZsYXNoX2Jvb3N0X3JlZyk7CisJCQkJaWYgKHJjKSB7CisJCQkJCWRldl9lcnIobGVk LT5kZXYsCisJCQkJCQkiUmVndWxhdG9yIGRpc2FibGUgZmFpbGVkKCVkKVxuIiwKKwkJCQkJCQkJ CXJjKTsKKwkJCQkJcmV0dXJuIHJjOworCQkJCX0KKwkJCQlsZWQtPmZsYXNoX2NmZy0+Zmxhc2hf b24gPSBmYWxzZTsKKwkJCX0KKwkJCWJyZWFrOworCQl9CisJfQorCisJcmV0dXJuIDA7Cit9CisK K3N0YXRpYyBpbnQgcXBucF90b3JjaF9yZWd1bGF0b3Jfb3BlcmF0ZShzdHJ1Y3QgcXBucF9sZWRf ZGF0YSAqbGVkLCBib29sIG9uKQoreworCWludCByYzsKKworCWlmICghb24pCisJCWdvdG8gcmVn dWxhdG9yX3R1cm5fb2ZmOworCisJaWYgKCFsZWQtPmZsYXNoX2NmZy0+dG9yY2hfb24pIHsKKwkJ cmMgPSByZWd1bGF0b3JfZW5hYmxlKGxlZC0+Zmxhc2hfY2ZnLT50b3JjaF9ib29zdF9yZWcpOwor CQlpZiAocmMpIHsKKwkJCWRldl9lcnIobGVkLT5kZXYsCisJCQkJIlJlZ3VsYXRvciBlbmFibGUg ZmFpbGVkKCVkKVxuIiwgcmMpOworCQkJCXJldHVybiByYzsKKwkJfQorCQlsZWQtPmZsYXNoX2Nm Zy0+dG9yY2hfb24gPSB0cnVlOworCX0KKwlyZXR1cm4gMDsKKworcmVndWxhdG9yX3R1cm5fb2Zm OgorCWlmIChsZWQtPmZsYXNoX2NmZy0+dG9yY2hfb24pIHsKKwkJcmMgPSBxcG5wX2xlZF9tYXNr ZWRfd3JpdGUobGVkLAlGTEFTSF9FTkFCTEVfQ09OVFJPTCwKKwkJCQlGTEFTSF9FTkFCTEVfTU9E VUxFX01BU0ssIEZMQVNIX0RJU0FCTEVfQUxMKTsKKwkJaWYgKHJjKSB7CisJCQlkZXZfZXJyKGxl ZC0+ZGV2LAorCQkJCSJFbmFibGUgcmVnIHdyaXRlIGZhaWxlZCglZClcbiIsIHJjKTsKKwkJfQor CisJCXJjID0gcmVndWxhdG9yX2Rpc2FibGUobGVkLT5mbGFzaF9jZmctPnRvcmNoX2Jvb3N0X3Jl Zyk7CisJCWlmIChyYykgeworCQkJZGV2X2VycihsZWQtPmRldiwKKwkJCQkiUmVndWxhdG9yIGRp c2FibGUgZmFpbGVkKCVkKVxuIiwgcmMpOworCQkJcmV0dXJuIHJjOworCQl9CisJCWxlZC0+Zmxh c2hfY2ZnLT50b3JjaF9vbiA9IGZhbHNlOworCX0KKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGlu dCBxcG5wX2ZsYXNoX3NldChzdHJ1Y3QgcXBucF9sZWRfZGF0YSAqbGVkKQoreworCWludCByYywg ZXJyb3I7CisJaW50IHZhbCA9IGxlZC0+Y2Rldi5icmlnaHRuZXNzOworCisJaWYgKGxlZC0+Zmxh c2hfY2ZnLT50b3JjaF9lbmFibGUpCisJCWxlZC0+Zmxhc2hfY2ZnLT5jdXJyZW50X3ByZ20gPQor CQkJKHZhbCAqIFRPUkNIX01BWF9MRVZFTCAvIGxlZC0+bWF4X2N1cnJlbnQpOworCWVsc2UKKwkJ bGVkLT5mbGFzaF9jZmctPmN1cnJlbnRfcHJnbSA9CisJCQkodmFsICogRkxBU0hfTUFYX0xFVkVM IC8gbGVkLT5tYXhfY3VycmVudCk7CisKKwkvKiBTZXQgbGVkIGN1cnJlbnQgKi8KKwlpZiAodmFs ID4gMCkgeworCQlpZiAobGVkLT5mbGFzaF9jZmctPnRvcmNoX2VuYWJsZSkgeworCQkJaWYgKGxl ZC0+Zmxhc2hfY2ZnLT5wZXJpcGhlcmFsX3N1YnR5cGUgPT0KKwkJCQkJCQlGTEFTSF9TVUJUWVBF X0RVQUwpIHsKKwkJCQlyYyA9IHFwbnBfdG9yY2hfcmVndWxhdG9yX29wZXJhdGUobGVkLCB0cnVl KTsKKwkJCQlpZiAocmMpIHsKKwkJCQkJZGV2X2VycihsZWQtPmRldiwKKwkJCQkJIlRvcmNoIHJl Z3VsYXRvciBvcGVyYXRlIGZhaWxlZCglZClcbiIsCisJCQkJCXJjKTsKKwkJCQkJcmV0dXJuIHJj OworCQkJCX0KKwkJCX0gZWxzZSBpZiAobGVkLT5mbGFzaF9jZmctPnBlcmlwaGVyYWxfc3VidHlw ZSA9PQorCQkJCQkJCUZMQVNIX1NVQlRZUEVfU0lOR0xFKSB7CisJCQkJcmMgPSBxcG5wX2ZsYXNo X3JlZ3VsYXRvcl9vcGVyYXRlKGxlZCwgdHJ1ZSk7CisJCQkJaWYgKHJjKSB7CisJCQkJCWRldl9l cnIobGVkLT5kZXYsCisJCQkJCSJGbGFzaCByZWd1bGF0b3Igb3BlcmF0ZSBmYWlsZWQoJWQpXG4i LAorCQkJCQlyYyk7CisJCQkJCWdvdG8gZXJyb3JfZmxhc2hfc2V0OworCQkJCX0KKworCQkJCS8q CisJCQkJICogV3JpdGUgMHg4MCB0byBNT0RVTEVfRU5BQkxFIGJlZm9yZSB3cml0aW5nCisJCQkJ ICogMHhFMCBpbiBvcmRlciB0byBhdm9pZCBhIGhhcmR3YXJlIGJ1ZyBjYXVzZWQKKwkJCQkgKiBi eSByZWdpc3RlciB2YWx1ZSBnb2luZyBmcm9tIDB4MDAgdG8gMHhFMC4KKwkJCQkgKi8KKwkJCQly YyA9IHFwbnBfbGVkX21hc2tlZF93cml0ZShsZWQsCisJCQkJCUZMQVNIX0VOQUJMRV9DT05UUk9M LAorCQkJCQlGTEFTSF9FTkFCTEVfTU9EVUxFX01BU0ssCisJCQkJCUZMQVNIX0VOQUJMRV9NT0RV TEUpOworCQkJCWlmIChyYykgeworCQkJCQlkZXZfZXJyKGxlZC0+ZGV2LAorCQkJCQkJIkVuYWJs ZSByZWcgd3JpdGUgZmFpbGVkKCVkKVxuIiwKKwkJCQkJCXJjKTsKKwkJCQkJcmV0dXJuIHJjOwor CQkJCX0KKwkJCX0KKworCQkJcmMgPSBxcG5wX2xlZF9tYXNrZWRfd3JpdGUobGVkLAorCQkJCUZM QVNIX0xFRF9VTkxPQ0tfU0VDVVJFLAorCQkJCUZMQVNIX1NFQ1VSRV9NQVNLLCBGTEFTSF9VTkxP Q0tfU0VDVVJFKTsKKwkJCWlmIChyYykgeworCQkJCWRldl9lcnIobGVkLT5kZXYsCisJCQkJCSJT ZWN1cmUgcmVnIHdyaXRlIGZhaWxlZCglZClcbiIsIHJjKTsKKwkJCQlnb3RvIGVycm9yX3JlZ193 cml0ZTsKKwkJCX0KKworCQkJcmMgPSBxcG5wX2xlZF9tYXNrZWRfd3JpdGUobGVkLAorCQkJCUZM QVNIX0xFRF9UT1JDSCwKKwkJCQlGTEFTSF9UT1JDSF9NQVNLLCBGTEFTSF9MRURfVE9SQ0hfRU5B QkxFKTsKKwkJCWlmIChyYykgeworCQkJCWRldl9lcnIobGVkLT5kZXYsCisJCQkJCSJUb3JjaCBy ZWcgd3JpdGUgZmFpbGVkKCVkKVxuIiwgcmMpOworCQkJCWdvdG8gZXJyb3JfcmVnX3dyaXRlOwor CQkJfQorCisJCQlyYyA9IHFwbnBfbGVkX21hc2tlZF93cml0ZShsZWQsCisJCQkJbGVkLT5mbGFz aF9jZmctPmN1cnJlbnRfYWRkciwKKwkJCQlGTEFTSF9DVVJSRU5UX01BU0ssCisJCQkJbGVkLT5m bGFzaF9jZmctPmN1cnJlbnRfcHJnbSk7CisJCQlpZiAocmMpIHsKKwkJCQlkZXZfZXJyKGxlZC0+ ZGV2LAorCQkJCQkiQ3VycmVudCByZWcgd3JpdGUgZmFpbGVkKCVkKVxuIiwgcmMpOworCQkJCWdv dG8gZXJyb3JfcmVnX3dyaXRlOworCQkJfQorCisJCQlyYyA9IHFwbnBfbGVkX21hc2tlZF93cml0 ZShsZWQsCisJCQkJbGVkLT5mbGFzaF9jZmctPnNlY29uZF9hZGRyLAorCQkJCUZMQVNIX0NVUlJF TlRfTUFTSywKKwkJCQlsZWQtPmZsYXNoX2NmZy0+Y3VycmVudF9wcmdtKTsKKwkJCWlmIChyYykg eworCQkJCWRldl9lcnIobGVkLT5kZXYsCisJCQkJCSIybmQgQ3VycmVudCByZWcgd3JpdGUgZmFp bGVkKCVkKVxuIiwKKwkJCQkJcmMpOworCQkJCWdvdG8gZXJyb3JfcmVnX3dyaXRlOworCQkJfQor CisJCQlxcG5wX2xlZF9tYXNrZWRfd3JpdGUobGVkLCBGTEFTSF9NQVhfQ1VSUiwKKwkJCQlGTEFT SF9DVVJSRU5UX01BU0ssCisJCQkJVE9SQ0hfTUFYX0xFVkVMKTsKKwkJCWlmIChyYykgeworCQkJ CWRldl9lcnIobGVkLT5kZXYsCisJCQkJCSJNYXggY3VycmVudCByZWcgd3JpdGUgZmFpbGVkKCVk KVxuIiwKKwkJCQkJcmMpOworCQkJCWdvdG8gZXJyb3JfcmVnX3dyaXRlOworCQkJfQorCisJCQly YyA9IHFwbnBfbGVkX21hc2tlZF93cml0ZShsZWQsCisJCQkJRkxBU0hfRU5BQkxFX0NPTlRST0ws CisJCQkJRkxBU0hfRU5BQkxFX01BU0ssCisJCQkJbGVkLT5mbGFzaF9jZmctPmVuYWJsZV9tb2R1 bGUpOworCQkJaWYgKHJjKSB7CisJCQkJZGV2X2VycihsZWQtPmRldiwKKwkJCQkJIkVuYWJsZSBy ZWcgd3JpdGUgZmFpbGVkKCVkKVxuIiwKKwkJCQkJcmMpOworCQkJCWdvdG8gZXJyb3JfcmVnX3dy aXRlOworCQkJfQorCisJCQlyYyA9IHFwbnBfbGVkX21hc2tlZF93cml0ZShsZWQsCisJCQkJRkxB U0hfTEVEX1NUUk9CRV9DVFJMLAorCQkJCWxlZC0+Zmxhc2hfY2ZnLT50cmlnZ2VyX2ZsYXNoLAor CQkJCWxlZC0+Zmxhc2hfY2ZnLT50cmlnZ2VyX2ZsYXNoKTsKKwkJCWlmIChyYykgeworCQkJCWRl dl9lcnIobGVkLT5kZXYsCisJCQkJCSJMRUQgJWQgc3Ryb2JlIHJlZyB3cml0ZSBmYWlsZWQoJWQp XG4iLAorCQkJCQlsZWQtPmlkLCByYyk7CisJCQkJZ290byBlcnJvcl9yZWdfd3JpdGU7CisJCQl9 CisJCX0gZWxzZSB7CisJCQlyYyA9IHFwbnBfZmxhc2hfcmVndWxhdG9yX29wZXJhdGUobGVkLCB0 cnVlKTsKKwkJCWlmIChyYykgeworCQkJCWRldl9lcnIobGVkLT5kZXYsCisJCQkJCSJGbGFzaCBy ZWd1bGF0b3Igb3BlcmF0ZSBmYWlsZWQoJWQpXG4iLAorCQkJCQlyYyk7CisJCQkJZ290byBlcnJv cl9mbGFzaF9zZXQ7CisJCQl9CisKKwkJCS8qIFNldCBmbGFzaCBzYWZldHkgdGltZXIgKi8KKwkJ CXJjID0gcXBucF9sZWRfbWFza2VkX3dyaXRlKGxlZCwKKwkJCQlGTEFTSF9TQUZFVFlfVElNRVIs CisJCQkJRkxBU0hfU0FGRVRZX1RJTUVSX01BU0ssCisJCQkJbGVkLT5mbGFzaF9jZmctPmR1cmF0 aW9uKTsKKwkJCWlmIChyYykgeworCQkJCWRldl9lcnIobGVkLT5kZXYsCisJCQkJCSJTYWZldHkg dGltZXIgcmVnIHdyaXRlIGZhaWxlZCglZClcbiIsCisJCQkJCXJjKTsKKwkJCQlnb3RvIGVycm9y X2ZsYXNoX3NldDsKKwkJCX0KKworCQkJLyogU2V0IG1heCBjdXJyZW50ICovCisJCQlyYyA9IHFw bnBfbGVkX21hc2tlZF93cml0ZShsZWQsCisJCQkJRkxBU0hfTUFYX0NVUlIsIEZMQVNIX0NVUlJF TlRfTUFTSywKKwkJCQlGTEFTSF9NQVhfTEVWRUwpOworCQkJaWYgKHJjKSB7CisJCQkJZGV2X2Vy cihsZWQtPmRldiwKKwkJCQkJIk1heCBjdXJyZW50IHJlZyB3cml0ZSBmYWlsZWQoJWQpXG4iLAor CQkJCQlyYyk7CisJCQkJZ290byBlcnJvcl9mbGFzaF9zZXQ7CisJCQl9CisKKwkJCS8qIFNldCBj bGFtcCBjdXJyZW50ICovCisJCQlyYyA9IHFwbnBfbGVkX21hc2tlZF93cml0ZShsZWQsCisJCQkJ RkxBU0hfQ0xBTVBfQ1VSUiwKKwkJCQlGTEFTSF9DVVJSRU5UX01BU0ssCisJCQkJbGVkLT5mbGFz aF9jZmctPmNsYW1wX2N1cnIpOworCQkJaWYgKHJjKSB7CisJCQkJZGV2X2VycihsZWQtPmRldiwK KwkJCQkJIkNsYW1wIGN1cnJlbnQgcmVnIHdyaXRlIGZhaWxlZCglZClcbiIsCisJCQkJCXJjKTsK KwkJCQlnb3RvIGVycm9yX2ZsYXNoX3NldDsKKwkJCX0KKworCQkJcmMgPSBxcG5wX2xlZF9tYXNr ZWRfd3JpdGUobGVkLAorCQkJCWxlZC0+Zmxhc2hfY2ZnLT5jdXJyZW50X2FkZHIsCisJCQkJRkxB U0hfQ1VSUkVOVF9NQVNLLAorCQkJCWxlZC0+Zmxhc2hfY2ZnLT5jdXJyZW50X3ByZ20pOworCQkJ aWYgKHJjKSB7CisJCQkJZGV2X2VycihsZWQtPmRldiwKKwkJCQkJIkN1cnJlbnQgcmVnIHdyaXRl IGZhaWxlZCglZClcbiIsIHJjKTsKKwkJCQlnb3RvIGVycm9yX2ZsYXNoX3NldDsKKwkJCX0KKwor CQkJcmMgPSBxcG5wX2xlZF9tYXNrZWRfd3JpdGUobGVkLAorCQkJCUZMQVNIX0VOQUJMRV9DT05U Uk9MLAorCQkJCWxlZC0+Zmxhc2hfY2ZnLT5lbmFibGVfbW9kdWxlLAorCQkJCWxlZC0+Zmxhc2hf Y2ZnLT5lbmFibGVfbW9kdWxlKTsKKwkJCWlmIChyYykgeworCQkJCWRldl9lcnIobGVkLT5kZXYs CisJCQkJCSJFbmFibGUgcmVnIHdyaXRlIGZhaWxlZCglZClcbiIsIHJjKTsKKwkJCQlnb3RvIGVy cm9yX2ZsYXNoX3NldDsKKwkJCX0KKworCQkJLyogVE9ETyB0cnkgdG8gbm90IGJ1c3kgd2FpdCov CisJCQltZGVsYXkoMSk7CisKKwkJCWlmICghbGVkLT5mbGFzaF9jZmctPnN0cm9iZV90eXBlKSB7 CisJCQkJcmMgPSBxcG5wX2xlZF9tYXNrZWRfd3JpdGUobGVkLAorCQkJCQlGTEFTSF9MRURfU1RS T0JFX0NUUkwsCisJCQkJCWxlZC0+Zmxhc2hfY2ZnLT50cmlnZ2VyX2ZsYXNoLAorCQkJCQlsZWQt PmZsYXNoX2NmZy0+dHJpZ2dlcl9mbGFzaCk7CisJCQkJaWYgKHJjKSB7CisJCQkJCWRldl9lcnIo bGVkLT5kZXYsCisJCQkJCSJMRUQgJWQgc3Ryb2JlIHJlZyB3cml0ZSBmYWlsZWQoJWQpXG4iLAor CQkJCQlsZWQtPmlkLCByYyk7CisJCQkJCWdvdG8gZXJyb3JfZmxhc2hfc2V0OworCQkJCX0KKwkJ CX0gZWxzZSB7CisJCQkJcmMgPSBxcG5wX2xlZF9tYXNrZWRfd3JpdGUobGVkLAorCQkJCQlGTEFT SF9MRURfU1RST0JFX0NUUkwsCisJCQkJCShsZWQtPmZsYXNoX2NmZy0+dHJpZ2dlcl9mbGFzaCB8 CisJCQkJCUZMQVNIX1NUUk9CRV9IVyksCisJCQkJCShsZWQtPmZsYXNoX2NmZy0+dHJpZ2dlcl9m bGFzaCB8CisJCQkJCUZMQVNIX1NUUk9CRV9IVykpOworCQkJCWlmIChyYykgeworCQkJCQlkZXZf ZXJyKGxlZC0+ZGV2LAorCQkJCQkiTEVEICVkIHN0cm9iZSByZWcgd3JpdGUgZmFpbGVkKCVkKVxu IiwKKwkJCQkJbGVkLT5pZCwgcmMpOworCQkJCQlnb3RvIGVycm9yX2ZsYXNoX3NldDsKKwkJCQl9 CisJCQl9CisJCX0KKwl9IGVsc2UgeworCQlyYyA9IHFwbnBfbGVkX21hc2tlZF93cml0ZShsZWQs CisJCQlGTEFTSF9MRURfU1RST0JFX0NUUkwsCisJCQlsZWQtPmZsYXNoX2NmZy0+dHJpZ2dlcl9m bGFzaCwKKwkJCUZMQVNIX0RJU0FCTEVfQUxMKTsKKwkJaWYgKHJjKSB7CisJCQlkZXZfZXJyKGxl ZC0+ZGV2LAorCQkJCSJMRUQgJWQgZmxhc2ggd3JpdGUgZmFpbGVkKCVkKVxuIiwgbGVkLT5pZCwg cmMpOworCQkJaWYgKGxlZC0+Zmxhc2hfY2ZnLT50b3JjaF9lbmFibGUpCisJCQkJZ290byBlcnJv cl90b3JjaF9zZXQ7CisJCQllbHNlCisJCQkJZ290byBlcnJvcl9mbGFzaF9zZXQ7CisJCX0KKwor CQkvKiBUT0RPIHRyeSB0byBub3QgYnVzeSB3YWl0Ki8KKwkJbWRlbGF5KDIpOworCQl1ZGVsYXko MTYwKTsKKworCQlpZiAobGVkLT5mbGFzaF9jZmctPnRvcmNoX2VuYWJsZSkgeworCQkJcmMgPSBx cG5wX2xlZF9tYXNrZWRfd3JpdGUobGVkLAorCQkJCUZMQVNIX0xFRF9VTkxPQ0tfU0VDVVJFLAor CQkJCUZMQVNIX1NFQ1VSRV9NQVNLLCBGTEFTSF9VTkxPQ0tfU0VDVVJFKTsKKwkJCWlmIChyYykg eworCQkJCWRldl9lcnIobGVkLT5kZXYsCisJCQkJCSJTZWN1cmUgcmVnIHdyaXRlIGZhaWxlZCgl ZClcbiIsIHJjKTsKKwkJCQlnb3RvIGVycm9yX3RvcmNoX3NldDsKKwkJCX0KKworCQkJcmMgPSBx cG5wX2xlZF9tYXNrZWRfd3JpdGUobGVkLAorCQkJCQlGTEFTSF9MRURfVE9SQ0gsCisJCQkJCUZM QVNIX1RPUkNIX01BU0ssCisJCQkJCUZMQVNIX0xFRF9UT1JDSF9ESVNBQkxFKTsKKwkJCWlmIChy YykgeworCQkJCWRldl9lcnIobGVkLT5kZXYsCisJCQkJCSJUb3JjaCByZWcgd3JpdGUgZmFpbGVk KCVkKVxuIiwgcmMpOworCQkJCWdvdG8gZXJyb3JfdG9yY2hfc2V0OworCQkJfQorCisJCQlpZiAo bGVkLT5mbGFzaF9jZmctPnBlcmlwaGVyYWxfc3VidHlwZSA9PQorCQkJCQkJCUZMQVNIX1NVQlRZ UEVfRFVBTCkgeworCQkJCXJjID0gcXBucF90b3JjaF9yZWd1bGF0b3Jfb3BlcmF0ZShsZWQsIGZh bHNlKTsKKwkJCQlpZiAocmMpIHsKKwkJCQkJZGV2X2VycihsZWQtPmRldiwKKwkJCQkJCSJUb3Jj aCByZWd1bGF0b3Igb3BlcmF0ZSBmYWlsZWQoJWQpXG4iLAorCQkJCQkJcmMpOworCQkJCQlyZXR1 cm4gcmM7CisJCQkJfQorCQkJfSBlbHNlIGlmIChsZWQtPmZsYXNoX2NmZy0+cGVyaXBoZXJhbF9z dWJ0eXBlID09CisJCQkJCQkJRkxBU0hfU1VCVFlQRV9TSU5HTEUpIHsKKwkJCQlyYyA9IHFwbnBf Zmxhc2hfcmVndWxhdG9yX29wZXJhdGUobGVkLCBmYWxzZSk7CisJCQkJaWYgKHJjKSB7CisJCQkJ CWRldl9lcnIobGVkLT5kZXYsCisJCQkJCQkiRmxhc2ggcmVndWxhdG9yIG9wZXJhdGUgZmFpbGVk KCVkKVxuIiwKKwkJCQkJCXJjKTsKKwkJCQkJcmV0dXJuIHJjOworCQkJCX0KKwkJCX0KKwkJfSBl bHNlIHsKKwkJCXJjID0gcXBucF9sZWRfbWFza2VkX3dyaXRlKGxlZCwKKwkJCQlGTEFTSF9FTkFC TEVfQ09OVFJPTCwKKwkJCQlsZWQtPmZsYXNoX2NmZy0+ZW5hYmxlX21vZHVsZSAmCisJCQkJfkZM QVNIX0VOQUJMRV9NT0RVTEVfTUFTSywKKwkJCQlGTEFTSF9ESVNBQkxFX0FMTCk7CisJCQlpZiAo cmMpIHsKKwkJCQlkZXZfZXJyKGxlZC0+ZGV2LAorCQkJCQkiRW5hYmxlIHJlZyB3cml0ZSBmYWls ZWQoJWQpXG4iLCByYyk7CisJCQkJaWYgKGxlZC0+Zmxhc2hfY2ZnLT50b3JjaF9lbmFibGUpCisJ CQkJCWdvdG8gZXJyb3JfdG9yY2hfc2V0OworCQkJCWVsc2UKKwkJCQkJZ290byBlcnJvcl9mbGFz aF9zZXQ7CisJCQl9CisKKwkJCXJjID0gcXBucF9mbGFzaF9yZWd1bGF0b3Jfb3BlcmF0ZShsZWQs IGZhbHNlKTsKKwkJCWlmIChyYykgeworCQkJCWRldl9lcnIobGVkLT5kZXYsCisJCQkJCSJGbGFz aCByZWd1bGF0b3Igb3BlcmF0ZSBmYWlsZWQoJWQpXG4iLAorCQkJCQlyYyk7CisJCQkJcmV0dXJu IHJjOworCQkJfQorCQl9CisJfQorCisJcXBucF9kdW1wX3JlZ3MobGVkLCBmbGFzaF9kZWJ1Z19y ZWdzLCBBUlJBWV9TSVpFKGZsYXNoX2RlYnVnX3JlZ3MpKTsKKworCXJldHVybiAwOworCitlcnJv cl9yZWdfd3JpdGU6CisJaWYgKGxlZC0+Zmxhc2hfY2ZnLT5wZXJpcGhlcmFsX3N1YnR5cGUgPT0g RkxBU0hfU1VCVFlQRV9TSU5HTEUpCisJCWdvdG8gZXJyb3JfZmxhc2hfc2V0OworCitlcnJvcl90 b3JjaF9zZXQ6CisJZXJyb3IgPSBxcG5wX3RvcmNoX3JlZ3VsYXRvcl9vcGVyYXRlKGxlZCwgZmFs c2UpOworCWlmIChlcnJvcikgeworCQlkZXZfZXJyKGxlZC0+ZGV2LAorCQkJIlRvcmNoIHJlZ3Vs YXRvciBvcGVyYXRlIGZhaWxlZCglZClcbiIsIHJjKTsKKwkJcmV0dXJuIGVycm9yOworCX0KKwly ZXR1cm4gcmM7CisKK2Vycm9yX2ZsYXNoX3NldDoKKwllcnJvciA9IHFwbnBfZmxhc2hfcmVndWxh dG9yX29wZXJhdGUobGVkLCBmYWxzZSk7CisJaWYgKGVycm9yKSB7CisJCWRldl9lcnIobGVkLT5k ZXYsCisJCQkiRmxhc2ggcmVndWxhdG9yIG9wZXJhdGUgZmFpbGVkKCVkKVxuIiwgcmMpOworCQly ZXR1cm4gZXJyb3I7CisJfQorCXJldHVybiByYzsKK30KKworc3RhdGljIHZvaWQgX19xcG5wX2xl ZF93b3JrKHN0cnVjdCBxcG5wX2xlZF9kYXRhICpsZWQsCisJCQkJZW51bSBsZWRfYnJpZ2h0bmVz cyB2YWx1ZSkKK3sKKwlpbnQgcmM7CisKKwltdXRleF9sb2NrKCZsZWQtPmxvY2spOworCisJc3dp dGNoIChsZWQtPmlkKSB7CisJY2FzZSBRUE5QX0lEX0ZMQVNIMV9MRUQwOgorCWNhc2UgUVBOUF9J RF9GTEFTSDFfTEVEMToKKwkJcmMgPSBxcG5wX2ZsYXNoX3NldChsZWQpOworCQlpZiAocmMgPCAw KQorCQkJZGV2X2VycihsZWQtPmRldiwKKwkJCQkiRkxBU0ggc2V0IGJyaWdodG5lc3MgZmFpbGVk ICglZClcbiIsIHJjKTsKKwkJYnJlYWs7CisJZGVmYXVsdDoKKwkJZGV2X2VycihsZWQtPmRldiwg IkludmFsaWQgTEVEKCVkKVxuIiwgbGVkLT5pZCk7CisJCWJyZWFrOworCX0KKwltdXRleF91bmxv Y2soJmxlZC0+bG9jayk7CisKK30KKworc3RhdGljIHZvaWQgcXBucF9sZWRfd29yayhzdHJ1Y3Qg d29ya19zdHJ1Y3QgKndvcmspCit7CisJc3RydWN0IHFwbnBfbGVkX2RhdGEgKmxlZCA9IGNvbnRh aW5lcl9vZih3b3JrLAorCQkJCQlzdHJ1Y3QgcXBucF9sZWRfZGF0YSwgd29yayk7CisKKwlfX3Fw bnBfbGVkX3dvcmsobGVkLCBsZWQtPmNkZXYuYnJpZ2h0bmVzcyk7CisKKwlyZXR1cm47Cit9CisK K3N0YXRpYyB2b2lkIHFwbnBfbGVkX3R1cm5fb2ZmX2RlbGF5ZWQoc3RydWN0IHdvcmtfc3RydWN0 ICp3b3JrKQoreworCXN0cnVjdCBkZWxheWVkX3dvcmsgKmR3b3JrID0gdG9fZGVsYXllZF93b3Jr KHdvcmspOworCXN0cnVjdCBxcG5wX2xlZF9kYXRhICpsZWQKKwkJPSBjb250YWluZXJfb2YoZHdv cmssIHN0cnVjdCBxcG5wX2xlZF9kYXRhLCBkd29yayk7CisKKwlsZWQtPmNkZXYuYnJpZ2h0bmVz cyA9IExFRF9PRkY7CisJcXBucF9sZWRfc2V0KCZsZWQtPmNkZXYsIGxlZC0+Y2Rldi5icmlnaHRu ZXNzKTsKK30KKworc3RhdGljIHZvaWQgcXBucF9sZWRfdHVybl9vZmYoc3RydWN0IHFwbnBfbGVk X2RhdGEgKmxlZCkKK3sKKwlJTklUX0RFTEFZRURfV09SSygmbGVkLT5kd29yaywgcXBucF9sZWRf dHVybl9vZmZfZGVsYXllZCk7CisJc2NoZWR1bGVfZGVsYXllZF93b3JrKCZsZWQtPmR3b3JrLAor CQltc2Vjc190b19qaWZmaWVzKGxlZC0+dHVybl9vZmZfZGVsYXlfbXMpKTsKK30KKworc3RhdGlj IGludCBxcG5wX2xlZHNfcHJvYmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldikKK3sKKwlz dHJ1Y3QgcXBucF9sZWRfZGF0YSAqbGVkLCAqbGVkX2FycmF5OworCXN0cnVjdCBkZXZpY2Vfbm9k ZSAqbm9kZSwgKnRlbXA7CisJaW50IHJjLCBpLCBudW1fbGVkcyA9IDAsIHBhcnNlZF9sZWRzID0g MDsKKwlpbnQgcmVnOworCWNvbnN0IGNoYXIgKmxlZF9sYWJlbDsKKwlib29sIHJlZ3VsYXRvcl9w cm9iZSA9IGZhbHNlOworCisJbm9kZSA9IHBkZXYtPmRldi5vZl9ub2RlOworCWlmIChub2RlID09 IE5VTEwpCisJCXJldHVybiAtRU5PREVWOworCisJdGVtcCA9IE5VTEw7CisJd2hpbGUgKCh0ZW1w ID0gb2ZfZ2V0X25leHRfY2hpbGQobm9kZSwgdGVtcCkpKQorCQludW1fbGVkcysrOworCisJaWYg KCFudW1fbGVkcykKKwkJcmV0dXJuIC1FQ0hJTEQ7CisKKwlsZWRfYXJyYXkgPSBkZXZtX2t6YWxs b2MoJnBkZXYtPmRldiwKKwkJKHNpemVvZihzdHJ1Y3QgcXBucF9sZWRfZGF0YSkgKiBudW1fbGVk cyksIEdGUF9LRVJORUwpOworCWlmICghbGVkX2FycmF5KSB7CisJCWRldl9lcnIoJnBkZXYtPmRl diwgIlVuYWJsZSB0byBhbGxvY2F0ZSBtZW1vcnlcbiIpOworCQlyZXR1cm4gLUVOT01FTTsKKwl9 CisKKwlmb3JfZWFjaF9jaGlsZF9vZl9ub2RlKG5vZGUsIHRlbXApIHsKKwkJbGVkID0gJmxlZF9h cnJheVtwYXJzZWRfbGVkc107CisJCWxlZC0+bnVtX2xlZHMgPSBudW1fbGVkczsKKwkJbGVkLT5k ZXYgPSAmcGRldi0+ZGV2OworCQlsZWQtPnJlZ21hcCA9IGRldl9nZXRfcmVnbWFwKHBkZXYtPmRl di5wYXJlbnQsIE5VTEwpOworCQlpZiAoIWxlZC0+cmVnbWFwKQorCQkJcmV0dXJuIC1FTk9ERVY7 CisKKwkJcmMgPSBvZl9wcm9wZXJ0eV9yZWFkX3UzMihub2RlLCAicmVnIiwgJnJlZyk7CisJCWlm IChyYyA8IDApIHsKKwkJCWRldl9lcnIobGVkLT5kZXYsCisJCQkJIkZhaWx1cmUgcmVhZGluZyBy ZWcsIHJjID0gJWRcbiIsIHJjKTsKKwkJCWdvdG8gZmFpbF9pZF9jaGVjazsKKwkJfQorCQlsZWQt PmJhc2UgPSByZWc7CisKKwkJcmMgPSBvZl9wcm9wZXJ0eV9yZWFkX3N0cmluZyh0ZW1wLCAibGFi ZWwiLCAmbGVkX2xhYmVsKTsKKwkJaWYgKHJjIDwgMCkgeworCQkJZGV2X2VycihsZWQtPmRldiwK KwkJCQkiRmFpbHVyZSByZWFkaW5nIGxhYmVsLCByYyA9ICVkXG4iLCByYyk7CisJCQlnb3RvIGZh aWxfaWRfY2hlY2s7CisJCX0KKworCQlyYyA9IG9mX3Byb3BlcnR5X3JlYWRfc3RyaW5nKHRlbXAs ICJsaW51eCxuYW1lIiwKKwkJCSZsZWQtPmNkZXYubmFtZSk7CisJCWlmIChyYyA8IDApIHsKKwkJ CWRldl9lcnIobGVkLT5kZXYsCisJCQkJIkZhaWx1cmUgcmVhZGluZyBsZWQgbmFtZSwgcmMgPSAl ZFxuIiwgcmMpOworCQkJZ290byBmYWlsX2lkX2NoZWNrOworCQl9CisKKwkJcmMgPSBvZl9wcm9w ZXJ0eV9yZWFkX3UzMih0ZW1wLCAicWNvbSxtYXgtY3VycmVudCIsCisJCQkmbGVkLT5tYXhfY3Vy cmVudCk7CisJCWlmIChyYyA8IDApIHsKKwkJCWRldl9lcnIobGVkLT5kZXYsCisJCQkJIkZhaWx1 cmUgcmVhZGluZyBtYXhfY3VycmVudCwgcmMgPSAgJWRcbiIsIHJjKTsKKwkJCWdvdG8gZmFpbF9p ZF9jaGVjazsKKwkJfQorCisJCXJjID0gb2ZfcHJvcGVydHlfcmVhZF91MzIodGVtcCwgInFjb20s aWQiLCAmbGVkLT5pZCk7CisJCWlmIChyYyA8IDApIHsKKwkJCWRldl9lcnIobGVkLT5kZXYsCisJ CQkJIkZhaWx1cmUgcmVhZGluZyBsZWQgaWQsIHJjID0gICVkXG4iLCByYyk7CisJCQlnb3RvIGZh aWxfaWRfY2hlY2s7CisJCX0KKworCQlyYyA9IHFwbnBfZ2V0X2NvbW1vbl9jb25maWdzKGxlZCwg dGVtcCk7CisJCWlmIChyYykgeworCQkJZGV2X2VycihsZWQtPmRldiwKKwkJCQkiRmFpbHVyZSBy ZWFkaW5nIGNvbW1vbiBsZWQgY29uZmlndXJhdGlvbiwiIFwKKwkJCQkiIHJjID0gJWRcbiIsIHJj KTsKKwkJCWdvdG8gZmFpbF9pZF9jaGVjazsKKwkJfQorCisJCWxlZC0+Y2Rldi5icmlnaHRuZXNz X3NldCAgICA9IHFwbnBfbGVkX3NldDsKKwkJbGVkLT5jZGV2LmJyaWdodG5lc3NfZ2V0ICAgID0g cXBucF9sZWRfZ2V0OworCisJCWlmIChzdHJuY21wKGxlZF9sYWJlbCwgImZsYXNoIiwgc2l6ZW9m KCJmbGFzaCIpKSA9PSAwKSB7CisJCQlpZiAoIW9mX2ZpbmRfcHJvcGVydHkobm9kZSwgImZsYXNo LWJvb3N0LXN1cHBseSIsIE5VTEwpKQorCQkJCXJlZ3VsYXRvcl9wcm9iZSA9IHRydWU7CisJCQly YyA9IHFwbnBfZ2V0X2NvbmZpZ19mbGFzaChsZWQsIHRlbXAsICZyZWd1bGF0b3JfcHJvYmUpOwor CQkJaWYgKHJjIDwgMCkgeworCQkJCWRldl9lcnIobGVkLT5kZXYsCisJCQkJCSJVbmFibGUgdG8g cmVhZCBmbGFzaCBjb25maWcgZGF0YVxuIik7CisJCQkJZ290byBmYWlsX2lkX2NoZWNrOworCQkJ fQorCQl9IGVsc2UgeworCQkJZGV2X2VycihsZWQtPmRldiwgIk5vIExFRCBtYXRjaGluZyBsYWJl bFxuIik7CisJCQlyYyA9IC1FSU5WQUw7CisJCQlnb3RvIGZhaWxfaWRfY2hlY2s7CisJCX0KKwor CQltdXRleF9pbml0KCZsZWQtPmxvY2spOworCQlJTklUX1dPUksoJmxlZC0+d29yaywgcXBucF9s ZWRfd29yayk7CisKKwkJcmMgPSAgcXBucF9sZWRfaW5pdGlhbGl6ZShsZWQpOworCQlpZiAocmMg PCAwKQorCQkJZ290byBmYWlsX2lkX2NoZWNrOworCisJCXJjID0gcXBucF9sZWRfc2V0X21heF9i cmlnaHRuZXNzKGxlZCk7CisJCWlmIChyYyA8IDApCisJCQlnb3RvIGZhaWxfaWRfY2hlY2s7CisK KwkJcmMgPSBsZWRfY2xhc3NkZXZfcmVnaXN0ZXIoJnBkZXYtPmRldiwgJmxlZC0+Y2Rldik7CisJ CWlmIChyYykgeworCQkJZGV2X2VycigmcGRldi0+ZGV2LCAidW5hYmxlIHRvIHJlZ2lzdGVyIGxl ZCAlZCxyYz0lZFxuIiwKKwkJCQkJCSBsZWQtPmlkLCByYyk7CisJCQlnb3RvIGZhaWxfaWRfY2hl Y2s7CisJCX0KKworCQlpZiAobGVkLT5pZCA9PSBRUE5QX0lEX0ZMQVNIMV9MRUQwIHx8CisJCQls ZWQtPmlkID09IFFQTlBfSURfRkxBU0gxX0xFRDEpIHsKKwkJCXJjID0gc3lzZnNfY3JlYXRlX2dy b3VwKCZsZWQtPmNkZXYuZGV2LT5rb2JqLAorCQkJCQkJCSZsZWRfYXR0cl9ncm91cCk7CisJCQlp ZiAocmMpCisJCQkJZ290byBmYWlsX2lkX2NoZWNrOworCisJCX0KKworCQkvKiBjb25maWd1cmUg ZGVmYXVsdCBzdGF0ZSAqLworCQlpZiAobGVkLT5kZWZhdWx0X29uKSB7CisJCQlsZWQtPmNkZXYu YnJpZ2h0bmVzcyA9IGxlZC0+Y2Rldi5tYXhfYnJpZ2h0bmVzczsKKwkJCV9fcXBucF9sZWRfd29y ayhsZWQsIGxlZC0+Y2Rldi5icmlnaHRuZXNzKTsKKwkJCXNjaGVkdWxlX3dvcmsoJmxlZC0+d29y ayk7CisJCQlpZiAobGVkLT50dXJuX29mZl9kZWxheV9tcyA+IDApCisJCQkJcXBucF9sZWRfdHVy bl9vZmYobGVkKTsKKwkJfSBlbHNlCisJCQlsZWQtPmNkZXYuYnJpZ2h0bmVzcyA9IExFRF9PRkY7 CisKKwkJcGFyc2VkX2xlZHMrKzsKKwl9CisJZGV2X3NldF9kcnZkYXRhKCZwZGV2LT5kZXYsIGxl ZF9hcnJheSk7CisJcmV0dXJuIDA7CisKK2ZhaWxfaWRfY2hlY2s6CisJZm9yIChpID0gMDsgaSA8 IHBhcnNlZF9sZWRzOyBpKyspIHsKKwkJbXV0ZXhfZGVzdHJveSgmbGVkX2FycmF5W2ldLmxvY2sp OworCQlsZWRfY2xhc3NkZXZfdW5yZWdpc3RlcigmbGVkX2FycmF5W2ldLmNkZXYpOworCX0KKwor CXJldHVybiByYzsKK30KKworc3RhdGljIGludCBxcG5wX2xlZHNfcmVtb3ZlKHN0cnVjdCBwbGF0 Zm9ybV9kZXZpY2UgKnBkZXYpCit7CisJc3RydWN0IHFwbnBfbGVkX2RhdGEgKmxlZF9hcnJheSAg PSBkZXZfZ2V0X2RydmRhdGEoJnBkZXYtPmRldik7CisJaW50IGksIHBhcnNlZF9sZWRzID0gbGVk X2FycmF5LT5udW1fbGVkczsKKworCWZvciAoaSA9IDA7IGkgPCBwYXJzZWRfbGVkczsgaSsrKSB7 CisJCWNhbmNlbF93b3JrX3N5bmMoJmxlZF9hcnJheVtpXS53b3JrKTsKKwkJbXV0ZXhfZGVzdHJv eSgmbGVkX2FycmF5W2ldLmxvY2spOworCQlsZWRfY2xhc3NkZXZfdW5yZWdpc3RlcigmbGVkX2Fy cmF5W2ldLmNkZXYpOworCQlzd2l0Y2ggKGxlZF9hcnJheVtpXS5pZCkgeworCQljYXNlIFFQTlBf SURfRkxBU0gxX0xFRDA6CisJCWNhc2UgUVBOUF9JRF9GTEFTSDFfTEVEMToKKwkJCWlmIChsZWRf YXJyYXlbaV0uZmxhc2hfY2ZnLT5mbGFzaF9yZWdfZ2V0KQorCQkJCXJlZ3VsYXRvcl9wdXQobGVk X2FycmF5W2ldLmZsYXNoX2NmZy0+IFwKKwkJCQkJCQlmbGFzaF9ib29zdF9yZWcpOworCQkJaWYg KGxlZF9hcnJheVtpXS5mbGFzaF9jZmctPnRvcmNoX2VuYWJsZSkKKwkJCQlyZWd1bGF0b3JfcHV0 KGxlZF9hcnJheVtpXS5mbGFzaF9jZmctPlwKKwkJCQkJCQl0b3JjaF9ib29zdF9yZWcpOworCQkJ c3lzZnNfcmVtb3ZlX2dyb3VwKCZsZWRfYXJyYXlbaV0uY2Rldi5kZXYtPmtvYmosCisJCQkJCQkJ JmxlZF9hdHRyX2dyb3VwKTsKKwkJCWJyZWFrOworCQlkZWZhdWx0OgorCQkJZGV2X2VycihsZWRf YXJyYXlbaV0uZGV2LAorCQkJCQkiSW52YWxpZCBMRUQoJWQpXG4iLAorCQkJCQlsZWRfYXJyYXlb aV0uaWQpOworCQkJcmV0dXJuIC1FSU5WQUw7CisJCX0KKwl9CisKKwlyZXR1cm4gMDsKK30KKwor c3RhdGljIGNvbnN0IHN0cnVjdCBvZl9kZXZpY2VfaWQgcXBucF9sZWRzX3NwbWlfb2ZfbWF0Y2hb XSA9IHsKKwl7IC5jb21wYXRpYmxlID0gInFjb20sbGVkcy1xcG5wIiB9LAorCXt9LAorfTsKK01P RFVMRV9ERVZJQ0VfVEFCTEUob2YsIHFwbnBfbGVkc19zcG1pX29mX21hdGNoKTsKKworc3RhdGlj IHN0cnVjdCBwbGF0Zm9ybV9kcml2ZXIgcXBucF9sZWRzX2RyaXZlciA9IHsKKwkuZHJpdmVyCQk9 IHsKKwkJLm5hbWUJPSAicWNvbSxsZWRzLXFwbnAiLAorCQkub2ZfbWF0Y2hfdGFibGUgPSBvZl9t YXRjaF9wdHIocXBucF9sZWRzX3NwbWlfb2ZfbWF0Y2gpLAorCX0sCisJLnByb2JlCQk9IHFwbnBf bGVkc19wcm9iZSwKKwkucmVtb3ZlCQk9IHFwbnBfbGVkc19yZW1vdmUsCit9OworbW9kdWxlX3Bs YXRmb3JtX2RyaXZlcihxcG5wX2xlZHNfZHJpdmVyKTsKKworTU9EVUxFX0RFU0NSSVBUSU9OKCJR UE5QIExFRCBkcml2ZXIiKTsKK01PRFVMRV9MSUNFTlNFKCJHUEwgdjIiKTsKK01PRFVMRV9BTElB UygibGVkczpsZWRzLXFwbnAiKTsKLS0gCjIuMjkuMgoKCgpfX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fX19fX19fX19fX19fX19fXwpsaW51eC1hcm0ta2VybmVsIG1haWxpbmcgbGlzdAps aW51eC1hcm0ta2VybmVsQGxpc3RzLmluZnJhZGVhZC5vcmcKaHR0cDovL2xpc3RzLmluZnJhZGVh ZC5vcmcvbWFpbG1hbi9saXN0aW5mby9saW51eC1hcm0ta2VybmVsCg==