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.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8EE85C76199 for ; Sun, 16 Feb 2020 17:27:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 59D162086A for ; Sun, 16 Feb 2020 17:27:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728522AbgBPR1G (ORCPT ); Sun, 16 Feb 2020 12:27:06 -0500 Received: from asav22.altibox.net ([109.247.116.9]:50660 "EHLO asav22.altibox.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727895AbgBPR1G (ORCPT ); Sun, 16 Feb 2020 12:27:06 -0500 X-Greylist: delayed 319 seconds by postgrey-1.27 at vger.kernel.org; Sun, 16 Feb 2020 12:26:59 EST Received: from localhost.localdomain (unknown [81.166.168.211]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: noralf.tronnes@ebnett.no) by asav22.altibox.net (Postfix) with ESMTPSA id 83324200ED; Sun, 16 Feb 2020 18:21:40 +0100 (CET) From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= To: broonie@kernel.org, balbi@kernel.org, lee.jones@linaro.org Cc: linux-usb@vger.kernel.org, dri-devel@lists.freedesktop.org, =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Subject: [RFC 5/9] usb: gadget: function: mud: Add gpio support Date: Sun, 16 Feb 2020 18:21:13 +0100 Message-Id: <20200216172117.49832-6-noralf@tronnes.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20200216172117.49832-1-noralf@tronnes.org> References: <20200216172117.49832-1-noralf@tronnes.org> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-CMAE-Score: 0 X-CMAE-Analysis: v=2.3 cv=ZvHD1ezG c=1 sm=1 tr=0 a=OYZzhG0JTxDrWp/F2OJbnw==:117 a=OYZzhG0JTxDrWp/F2OJbnw==:17 a=jpOVt7BSZ2e4Z31A5e1TngXxSK0=:19 a=IkcTkHD0fZMA:10 a=M51BFTxLslgA:10 a=SJz97ENfAAAA:8 a=OVWlCPoClyRDxbRKtg8A:9 a=ENd6JL4-XTPeTk_z:21 a=YaaFWRjS8iQpcXM6:21 a=QEXdDO2ut3YA:10 a=vFet0B0WnEQeilDPIY6i:22 Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Add optional gpio functionality to the Multifunction USB Device. Signed-off-by: Noralf Trønnes --- drivers/usb/gadget/Kconfig | 14 + drivers/usb/gadget/function/Makefile | 2 + drivers/usb/gadget/function/f_mud_pins.c | 962 +++++++++++++++++++++++ 3 files changed, 978 insertions(+) create mode 100644 drivers/usb/gadget/function/f_mud_pins.c diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 9551876ffe08..d6285146ec76 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -219,6 +219,9 @@ config USB_F_TCM config USB_F_MUD tristate +config USB_F_MUD_PINS + tristate + # this first set of drivers all depend on bulk-capable hardware. config USB_CONFIGFS @@ -493,6 +496,17 @@ menuconfig USB_CONFIGFS_F_MUD help Core support for the Multifunction USB Device. +if USB_F_MUD + +config USB_CONFIGFS_F_MUD_PINS + bool "Multifunction USB Device GPIO" + depends on PINCTRL + select USB_F_MUD_PINS + help + GPIO support for the Multifunction USB Device. + +endif # USB_F_MUD + choice tristate "USB Gadget precomposed configurations" default USB_ETH diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index b6e31b511521..2e24227fcc12 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -52,3 +52,5 @@ usb_f_tcm-y := f_tcm.o obj-$(CONFIG_USB_F_TCM) += usb_f_tcm.o usb_f_mud-y := f_mud.o mud_regmap.o obj-$(CONFIG_USB_F_MUD) += usb_f_mud.o +usb_f_mud_pins-y := f_mud_pins.o +obj-$(CONFIG_USB_F_MUD_PINS) += usb_f_mud_pins.o diff --git a/drivers/usb/gadget/function/f_mud_pins.c b/drivers/usb/gadget/function/f_mud_pins.c new file mode 100644 index 000000000000..b3466804ad5e --- /dev/null +++ b/drivers/usb/gadget/function/f_mud_pins.c @@ -0,0 +1,962 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Noralf Trønnes + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "f_mud.h" +#include "../../../pinctrl/pinctrl-mud.h" + +/* + * Even though the host side is a pinctrl driver, the device side is a gpio consumer. + * That's because not all boards have a pin controller. + */ + +/* Temporary debugging aid */ +#define fmdebug(fmt, ...) \ +do { \ + if (1) \ + printk(KERN_DEBUG fmt, ##__VA_ARGS__); \ +} while (0) + +static DEFINE_IDA(f_mud_pins_ida); + +struct f_mud_pins_cell_item { + struct list_head node; + unsigned int index; + struct config_group group; + + struct mutex lock; /* Protect the values below */ + int refcnt; + + const char *name; + const char *chip; + int offset; +}; + +static inline struct f_mud_pins_cell_item *ci_to_f_mud_pins_cell_item(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_mud_pins_cell_item, group); +} + +struct f_mud_pins_lookup_device { + struct device dev; + int id; + struct f_mud_cell *cell; + struct gpiod_lookup_table *lookup; + const char **names; + unsigned int count; +}; + +struct f_mud_pins_pin { + struct f_mud_pins_cell *parent; + unsigned int index; + struct gpio_desc *gpio; + unsigned long dflags; + unsigned int debounce; +#define DEBOUNCE_NOT_SET UINT_MAX + bool config_requested; + int irq; + int irqflags; +}; + +struct f_mud_pins_cell { + struct f_mud_cell cell; + + struct mutex lock; /* Protect refcnt and items */ + int refcnt; + struct list_head items; + + struct f_mud_pins_lookup_device *ldev; + struct f_mud_pins_pin *pins; + unsigned int count; + spinlock_t irq_status_lock; + unsigned long *irq_status; +}; + +static inline struct f_mud_pins_cell *ci_to_f_mud_pins_cell(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_mud_pins_cell, cell.group); +} + +static inline struct f_mud_pins_cell *cell_to_pcell(struct f_mud_cell *cell) +{ + return container_of(cell, struct f_mud_pins_cell, cell); +} + +static irqreturn_t f_mud_pins_gpio_irq_thread(int irq, void *p) +{ + struct f_mud_pins_pin *pin = p; + struct f_mud_pins_cell *pcell = pin->parent; + + spin_lock(&pcell->irq_status_lock); + set_bit(pin->index, pcell->irq_status); + spin_unlock(&pcell->irq_status_lock); + + fmdebug("%s(index=%u): irq_status=%*pb\n", __func__, pin->index, + pcell->count, pcell->irq_status); + + f_mud_irq(pcell->ldev->cell); + + return IRQ_HANDLED; +} + +static int f_mud_pins_gpio_irq_request(struct f_mud_pins_cell *pcell, unsigned int index) +{ + struct f_mud_pins_pin *pin = &pcell->pins[index]; + int ret, irq; + + fmdebug("%s(index=%u)\n", __func__, index); + + if (pin->irq) + return 0; + + if (!pin->gpio || !pin->irqflags) + return -EINVAL; + + ret = gpiod_get_direction(pin->gpio); + if (ret < 0) + return ret; + if (ret != 1) + return -EINVAL; + + irq = gpiod_to_irq(pin->gpio); + fmdebug(" irq=%d\n", irq); + if (irq <= 0) + return -ENODEV; + + ret = request_threaded_irq(irq, NULL, f_mud_pins_gpio_irq_thread, + pin->irqflags | IRQF_ONESHOT, + dev_name(&pcell->ldev->dev), pin); + if (ret) + return ret; + + pin->irq = irq; + + return 0; +} + +static void f_mud_pins_gpio_irq_free(struct f_mud_pins_cell *pcell, unsigned int index) +{ + struct f_mud_pins_pin *pin = &pcell->pins[index]; + + fmdebug("%s(index=%u): irq=%d\n", __func__, index, pin->irq); + + if (pin->irq) { + free_irq(pin->irq, pin); + pin->irq = 0; + } +} + +static void f_mud_pins_gpio_irq_free_all(struct f_mud_pins_cell *pcell) +{ + unsigned int i; + + for (i = 0; i < pcell->count; i++) + f_mud_pins_gpio_irq_free(pcell, i); +} + +static int f_mud_pins_gpio_irq_type(struct f_mud_pins_cell *pcell, unsigned int index, + unsigned int val) +{ + struct f_mud_pins_pin *pin = &pcell->pins[index]; + + fmdebug("%s(index=%u, val=%u)\n", __func__, index, val); + + switch (val) { + case MUD_PIN_IRQ_TYPE_EDGE_RISING: + pin->irqflags = IRQF_TRIGGER_RISING; + break; + case MUD_PIN_IRQ_TYPE_EDGE_FALLING: + pin->irqflags = IRQF_TRIGGER_FALLING; + break; + case MUD_PIN_IRQ_TYPE_EDGE_BOTH: + pin->irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; + break; + case MUD_PIN_IRQ_TYPE_NONE: + pin->irqflags = IRQF_TRIGGER_NONE; + break; + default: + return -EINVAL; + }; + + return 0; +} + +static void f_mud_pins_gpio_free(struct f_mud_pins_cell *pcell, unsigned int index) +{ + struct f_mud_pins_pin *pin = &pcell->pins[index]; + + fmdebug("%s(index=%u): gpio=%d, config_requested=%u\n", __func__, index, + pin->gpio ? desc_to_gpio(pin->gpio) : -1, pin->config_requested); + + if (pin->config_requested) + return; + + if (pin->gpio) + gpiod_put(pin->gpio); + pin->gpio = NULL; +} + +/* When flags change re-request the gpio to enable the settings */ +static int f_mud_pins_gpio_request_do(struct f_mud_pins_cell *pcell, unsigned int index, + bool config, unsigned int debounce) +{ + struct f_mud_pins_pin *pin = &pcell->pins[index]; + struct gpio_desc *gpio; + int ret; + + fmdebug("%s(index=%u): lflags=%lu dflags=%lu\n", __func__, index, + pcell->ldev->lookup->table[index].flags, pin->dflags); + + if (!pcell->pins[index].gpio && config) + pin->config_requested = true; + + if (pcell->pins[index].gpio) { + gpiod_put(pcell->pins[index].gpio); + pcell->pins[index].gpio = NULL; + } + + gpio = gpiod_get_index(&pcell->ldev->dev, NULL, index, pin->dflags); + if (IS_ERR(gpio)) { + ret = PTR_ERR(gpio); + fmdebug("failed to get gpio %u: ret=%d\n", index, ret); + return ret; + } + pin->gpio = gpio; + fmdebug(" gpios[%u]: gpionr %d\n", index, desc_to_gpio(gpio)); + + /* Debounce can be set through pinconf so it must be stored */ + if (debounce == DEBOUNCE_NOT_SET) + debounce = pin->debounce; + + if (debounce != DEBOUNCE_NOT_SET) { + ret = gpiod_set_debounce(pin->gpio, debounce); + if (ret) + return ret; + + pin->debounce = debounce ? debounce : DEBOUNCE_NOT_SET; + } + + return 0; +} + +static int f_mud_pins_gpio_request_debounce(struct f_mud_pins_cell *pcell, + unsigned int index, unsigned int debounce) +{ + struct f_mud_pins_pin *pin = &pcell->pins[index]; + + if (pin->debounce == debounce) + return 0; + + return f_mud_pins_gpio_request_do(pcell, index, true, debounce); +} + +static int f_mud_pins_gpio_request_dflag(struct f_mud_pins_cell *pcell, unsigned int index, + enum gpiod_flags dflag, bool dval, bool config) +{ + struct f_mud_pins_pin *pin = &pcell->pins[index]; + bool curr_dflag = pin->dflags & dflag; + bool changed = false; + + fmdebug("%s(index=%u): dflag=%u dval=%u\n", __func__, index, dflag, dval); + + if (curr_dflag != dval) { + if (dval) + pin->dflags |= dflag; + else + pin->dflags &= ~dflag; + changed = true; + } + + if (pin->gpio && !changed) + return 0; + + return f_mud_pins_gpio_request_do(pcell, index, config, DEBOUNCE_NOT_SET); +} + +static int f_mud_pins_gpio_request_lflag(struct f_mud_pins_cell *pcell, unsigned int index, + enum gpio_lookup_flags lflag, bool lval, + bool config) +{ + struct gpiod_lookup *lentry = &pcell->ldev->lookup->table[index]; + struct f_mud_pins_pin *pin = &pcell->pins[index]; + bool curr_lflag = lentry->flags & lflag; + bool changed = false; + + fmdebug("%s(index=%u): lflag=%u lval=%u\n", __func__, index, lflag, lval); + + if (curr_lflag != lval) { + if (lval) + lentry->flags |= lflag; + else + lentry->flags &= ~lflag; + changed = true; + } + + if (pin->gpio && !changed) + return 0; + + return f_mud_pins_gpio_request_do(pcell, index, config, DEBOUNCE_NOT_SET); +} + +static int f_mud_pins_write_gpio_config(struct f_mud_pins_cell *pcell, unsigned int index, + unsigned int offset, unsigned int val) +{ + struct f_mud_pins_pin *pin; + int ret = -ENOTSUPP; + + fmdebug("%s(index=%u, offset=0x%02x, val=%u)\n", __func__, index, offset, val); + + pin = &pcell->pins[index]; + + switch (offset) { + case MUD_PIN_CONFIG_BIAS_PULL_DOWN: + if (!val) + return -ENOTSUPP; + ret = f_mud_pins_gpio_request_lflag(pcell, index, GPIO_PULL_DOWN, val, true); + break; + case MUD_PIN_CONFIG_BIAS_PULL_UP: + if (!val) + return -ENOTSUPP; + ret = f_mud_pins_gpio_request_lflag(pcell, index, GPIO_PULL_UP, val, true); + break; + case MUD_PIN_CONFIG_DRIVE_OPEN_DRAIN: + ret = f_mud_pins_gpio_request_lflag(pcell, index, GPIO_OPEN_DRAIN, 1, true); + break; + case MUD_PIN_CONFIG_DRIVE_OPEN_SOURCE: + ret = f_mud_pins_gpio_request_lflag(pcell, index, GPIO_OPEN_SOURCE, 1, true); + break; + case MUD_PIN_CONFIG_DRIVE_PUSH_PULL: + ret = f_mud_pins_gpio_request_dflag(pcell, index, GPIOD_IN, 0, true); + break; + case MUD_PIN_CONFIG_INPUT_DEBOUNCE: + ret = f_mud_pins_gpio_request_debounce(pcell, index, val); + break; + case MUD_PIN_CONFIG_INPUT_ENABLE: + ret = f_mud_pins_gpio_request_dflag(pcell, index, GPIOD_IN, val, true); + break; + case MUD_PIN_CONFIG_OUTPUT: + val = val ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; + ret = f_mud_pins_gpio_request_dflag(pcell, index, val, 1, true); + break; + case MUD_PIN_CONFIG_PERSIST_STATE: + ret = f_mud_pins_gpio_request_lflag(pcell, index, GPIO_TRANSITORY, val, true); + break; + } + + return ret; +} + +static int f_mud_pins_write_gpio(struct f_mud_pins_cell *pcell, unsigned int regnr, + const void *buf, size_t len) +{ + unsigned int regbase = regnr - MUD_PINCTRL_REG_PIN_BASE; + unsigned int offset = regbase % MUD_PINCTRL_PIN_BLOCK_SIZE; + unsigned int index = regbase / MUD_PINCTRL_PIN_BLOCK_SIZE; + size_t count = len / sizeof(u32); + struct f_mud_pins_pin *pin; + const __le32 *buf32 = buf; + u32 val; + int ret; + + fmdebug("%s(len=%zu): offset=0x%02x index=%u\n", __func__, len, offset, index); + + if (index >= pcell->count) { + fmdebug("%s: gpio index out of bounds: %u\n", __func__, index); + return -EINVAL; + } + + while (count--) { + pin = &pcell->pins[index]; + val = le32_to_cpup(buf32++); + ret = 0; + + switch (offset++) { + case MUD_PIN_CONFIG_BIAS_BUS_HOLD ... MUD_PIN_CONFIG_END: + return f_mud_pins_write_gpio_config(pcell, index, offset - 1, val); + + case MUD_PIN_GPIO_REQUEST: + if (val != 1) + return -EINVAL; + /* Persistence is the default so set it from the start */ + ret = f_mud_pins_gpio_request_lflag(pcell, index, GPIO_TRANSITORY, + 0, false); + break; + case MUD_PIN_GPIO_FREE: + if (val != 1) + return -EINVAL; + f_mud_pins_gpio_free(pcell, index); + break; + + case MUD_PIN_DIRECTION: + if (!pin) + return -EINVAL; + + if (val == MUD_PIN_DIRECTION_INPUT) { + ret = gpiod_direction_input(pin->gpio); + } else { + int value = !!(val & MUD_PIN_DIRECTION_OUTPUT_HIGH); + + ret = gpiod_direction_output(pin->gpio, value); + } + break; + case MUD_PIN_LEVEL: + if (pin) + gpiod_set_value_cansleep(pin->gpio, val); + break; + case MUD_PIN_IRQ_TYPE: + ret = f_mud_pins_gpio_irq_type(pcell, index, val); + break; + case MUD_PIN_IRQ_ENABLED: + if (val) + ret = f_mud_pins_gpio_irq_request(pcell, index); + else + f_mud_pins_gpio_irq_free(pcell, index); + break; + default: + pr_err("%s: unknown register: 0x%x\n", __func__, regnr); + return -EINVAL; + } + + if (ret < 0) + return ret; + } + + return 0; +} + +static int f_mud_pins_writereg(struct f_mud_cell *cell, unsigned int regnr, + const void *buf, size_t len, u8 compression) +{ + struct f_mud_pins_cell *pcell = cell_to_pcell(cell); + + fmdebug("%s(regnr=0x%02x, len=%zu)\n", __func__, regnr, len); + + if (regnr >= MUD_PINCTRL_REG_PIN_BASE) + return f_mud_pins_write_gpio(pcell, regnr, buf, len); + + return -EINVAL; +} + +static int f_mud_pins_read_gpio(struct f_mud_pins_cell *pcell, unsigned int regnr, + void *buf, size_t len) +{ + unsigned int regbase = regnr - MUD_PINCTRL_REG_PIN_BASE; + unsigned int offset = regbase % MUD_PINCTRL_PIN_BLOCK_SIZE; + unsigned int index = regbase / MUD_PINCTRL_PIN_BLOCK_SIZE; + size_t count = len / sizeof(u32); + struct f_mud_pins_pin *pin; + struct gpio_desc *gpio; + __le32 *buf32 = buf; + u32 val; + int ret; + + fmdebug("%s(len=%zu): offset=0x%02x index=%u\n", __func__, len, offset, index); + + if (index >= pcell->count) { + fmdebug("%s: gpio index out of bounds: %u\n", __func__, index); + return -EINVAL; + } + + if (offset >= MUD_PIN_NAME && (offset + count - 1) <= MUD_PIN_NAME_END) { + size_t start = (offset - MUD_PIN_NAME) * sizeof(u32); + char name[MUD_PIN_NAME_LEN]; + + strscpy_pad(name, pcell->ldev->names[index], MUD_PIN_NAME_LEN); + fmdebug(" name=%*ph\n", MUD_PIN_NAME_LEN, name); + memcpy(buf, name + start, len); + + return 0; + } + + pin = &pcell->pins[index]; + + while (count--) { + switch (offset++) { + case MUD_PIN_DIRECTION: + /* + * Host side gpiochip_add_data_with_key() calls ->get_direction + * without requesting the gpio first. + */ + gpio = pin->gpio; + if (!gpio) { + /* non gpio pins will fail here, but that's fine */ + ret = f_mud_pins_gpio_request_lflag(pcell, index, + 0, 0, false); + if (ret) + return ret; + } + ret = gpiod_get_direction(pin->gpio); + if (!gpio) + f_mud_pins_gpio_free(pcell, index); + if (ret < 0) + return ret; + val = ret ? MUD_PIN_DIRECTION_INPUT : MUD_PIN_DIRECTION_OUTPUT; + break; + case MUD_PIN_LEVEL: + if (!pin->gpio) + return -EINVAL; + ret = gpiod_get_value_cansleep(pin->gpio); + if (ret < 0) + return ret; + val = ret; + break; + case MUD_PIN_IRQ_TYPES: + /* FIXME: Is it possible to get this info somewhere? */ + val = MUD_PIN_IRQ_TYPE_EDGE_BOTH; + break; + default: + pr_err("%s: unknown register: 0x%x\n", __func__, regnr); + return -EINVAL; + } + + *(buf32++) = cpu_to_le32(val); + } + + return 0; +} + +static int f_mud_pins_readreg(struct f_mud_cell *cell, unsigned int regnr, + void *buf, size_t *len, u8 compression) +{ + struct f_mud_pins_cell *pcell = cell_to_pcell(cell); + size_t count = *len / sizeof(u32); + __le32 *buf32 = buf; + + fmdebug("%s(regnr=0x%02x, len=%zu)\n", __func__, regnr, *len); + + if (regnr >= MUD_PINCTRL_REG_PIN_BASE) + return f_mud_pins_read_gpio(pcell, regnr, buf, *len); + + if (regnr >= MUD_PINCTRL_REG_IRQ_STATUS && + regnr <= MUD_PINCTRL_REG_IRQ_STATUS_END) { + unsigned int nregs = DIV_ROUND_UP(pcell->count, sizeof(u32)); + unsigned int offset = regnr - MUD_PINCTRL_REG_IRQ_STATUS; + unsigned int i, end = min_t(unsigned int, count, nregs); + u32 irqvals[MUD_PINCTRL_MAX_NUM_PINS / sizeof(u32)]; + + if (count > (nregs - offset)) + return -EINVAL; + + bitmap_to_arr32(irqvals, pcell->irq_status, pcell->count); + + fmdebug(" irq_status=%*pb irqvals=%*ph\n", pcell->count, + pcell->irq_status, nregs, irqvals); + + for (i = offset; i < end; i++) + *buf32++ = cpu_to_le32(irqvals[i]); + + return 0; + } + + if (regnr == MUD_PINCTRL_REG_NUM_PINS && count == 1) { + *buf32 = cpu_to_le32(pcell->count); + return 0; + } + + fmdebug("%s: unknown register 0x%x\n", __func__, regnr); + + return -EINVAL; +} + +static void f_mud_pins_disable(struct f_mud_cell *cell) +{ + struct f_mud_pins_cell *pcell = cell_to_pcell(cell); + + f_mud_pins_gpio_irq_free_all(pcell); + /* + * FIXME: Free requested gpios as well? + * Or should they survive on unplug on a powered board? + */ +} + +static void f_mud_pins_lookup_device_release(struct device *dev) +{ + struct f_mud_pins_lookup_device *ldev = + container_of(dev, struct f_mud_pins_lookup_device, dev); + + fmdebug("%s: ldev=%px\n", __func__, ldev); + + if (ldev->lookup) { + struct gpiod_lookup *p; + + if (ldev->lookup->dev_id) + gpiod_remove_lookup_table(ldev->lookup); + + for (p = &ldev->lookup->table[0]; p->chip_label; p++) + kfree(p->chip_label); + kfree(ldev->lookup); + } + + if (ldev->names) { + unsigned int i; + + for (i = 0; i < ldev->count; i++) + kfree(ldev->names[i]); + kfree(ldev->names); + } + + ida_free(&f_mud_pins_ida, ldev->id); + kfree(ldev); +} + +static int f_mud_pins_looup_device_create(struct f_mud_pins_cell *pcell) +{ + struct f_mud_pins_lookup_device *ldev; + struct f_mud_pins_cell_item *fitem; + unsigned int max_index = 0; + int ret; + + fmdebug("%s: %px\n", __func__, pcell); + + ldev = kzalloc(sizeof(*ldev), GFP_KERNEL); + if (!ldev) + return -ENOMEM; + + fmdebug("%s: ldev=%px\n", __func__, ldev); + + ldev->id = ida_alloc(&f_mud_pins_ida, GFP_KERNEL); + if (ldev->id < 0) { + kfree(ldev); + return ldev->id; + } + + ldev->cell = &pcell->cell; + ldev->dev.release = f_mud_pins_lookup_device_release; + dev_set_name(&ldev->dev, "f_mud_pins-%d", ldev->id); + + ret = device_register(&ldev->dev); + if (ret) { + put_device(&ldev->dev); + return ret; + } + + mutex_lock(&pcell->lock); + + list_for_each_entry(fitem, &pcell->items, node) { + max_index = max(max_index, fitem->index); + ldev->count++; + } + + if (!ldev->count) { + ret = -ENOENT; + goto out_unlock; + } + + if (ldev->count != max_index + 1) { + pr_err("Pin indices are not continuous\n"); + ret = -EINVAL; + goto out_unlock; + } + + ldev->names = kcalloc(ldev->count, sizeof(*ldev->names), GFP_KERNEL); + ldev->lookup = kzalloc(struct_size(ldev->lookup, table, ldev->count + 1), + GFP_KERNEL); + if (!ldev->lookup || !ldev->names) { + ret = -ENOMEM; + goto out_unlock; + } + + ret = 0; + list_for_each_entry(fitem, &pcell->items, node) { + struct gpiod_lookup *entry = &ldev->lookup->table[fitem->index]; + + mutex_lock(&fitem->lock); + + if (!fitem->name) { + pr_err("Missing name for pin %u\n", fitem->index); + ret = -EINVAL; + goto out_unlock_pin; + } + + ldev->names[fitem->index] = kstrdup(fitem->name, GFP_KERNEL); + if (!ldev->names[fitem->index]) { + ret = -ENOMEM; + goto out_unlock_pin; + } + + /* Skip adding to lookup if the pin has no gpio function */ + if (!fitem->chip) + goto out_unlock_pin; + + entry->idx = fitem->index; + entry->chip_hwnum = fitem->offset; + + entry->chip_label = kstrdup(fitem->chip, GFP_KERNEL); + if (!entry->chip_label) { + ret = -ENOMEM; + goto out_unlock_pin; + } + + fmdebug(" %u: chip=%s hwnum=%u name=%s\n", entry->idx, + entry->chip_label, entry->chip_hwnum, ldev->names[fitem->index]); +out_unlock_pin: + mutex_unlock(&fitem->lock); + if (ret) + goto out_unlock; + } + + ldev->lookup->dev_id = dev_name(&ldev->dev); + gpiod_add_lookup_table(ldev->lookup); + + pcell->ldev = ldev; + pcell->count = ldev->count; + +out_unlock: + mutex_unlock(&pcell->lock); + + if (ret) + device_unregister(&ldev->dev); + + return ret; +} + +static void f_mud_pins_lookup_device_destroy(struct f_mud_pins_cell *pcell) +{ + if (pcell->ldev) { + device_unregister(&pcell->ldev->dev); + pcell->ldev = NULL; + } +} + +static int f_mud_pins_bind(struct f_mud_cell *cell) +{ + struct f_mud_pins_cell *pcell = cell_to_pcell(cell); + unsigned int i; + int ret; + + fmdebug("%s: %px\n", __func__, pcell); + + ret = f_mud_pins_looup_device_create(pcell); + if (ret) + return ret; + + spin_lock_init(&pcell->irq_status_lock); + pcell->irq_status = bitmap_zalloc(pcell->count, GFP_KERNEL); + if (!pcell->irq_status) { + ret = -ENOMEM; + goto error_free; + } + + pcell->pins = kcalloc(pcell->count, sizeof(*pcell->pins), GFP_KERNEL); + if (!pcell->pins) { + ret = -ENOMEM; + goto error_free; + } + + for (i = 0; i < pcell->count; i++) { + struct f_mud_pins_pin *pin = &pcell->pins[i]; + + pin->parent = pcell; + pin->index = i; + pin->debounce = DEBOUNCE_NOT_SET; + } + + return 0; + +error_free: + kfree(pcell->pins); + f_mud_pins_lookup_device_destroy(pcell); + + return ret; +} + +static void f_mud_pins_unbind(struct f_mud_cell *cell) +{ + struct f_mud_pins_cell *pcell = cell_to_pcell(cell); + unsigned int i; + + fmdebug("%s:\n", __func__); + + if (pcell->pins) { + for (i = 0; i < pcell->count; i++) { + if (pcell->pins[i].gpio) { + fmdebug(" gpiod_put: %u\n", i); + gpiod_put(pcell->pins[i].gpio); + } + } + + kfree(pcell->pins); + } + + bitmap_free(pcell->irq_status); + + f_mud_pins_lookup_device_destroy(pcell); +} + +static void f_mud_pins_cell_item_item_release(struct config_item *item) +{ + struct f_mud_pins_cell_item *fitem = ci_to_f_mud_pins_cell_item(item); + + fmdebug("%s: fitem=%px\n", __func__, fitem); + + kfree(fitem->name); + kfree(fitem->chip); + kfree(fitem); +} + +F_MUD_OPT_STR(f_mud_pins_cell_item, name); +F_MUD_OPT_STR(f_mud_pins_cell_item, chip); +F_MUD_OPT_INT(f_mud_pins_cell_item, offset, 0, INT_MAX); + +static struct configfs_attribute *f_mud_pins_cell_item_attrs[] = { + &f_mud_pins_cell_item_attr_name, + &f_mud_pins_cell_item_attr_chip, + &f_mud_pins_cell_item_attr_offset, + NULL, +}; + +static struct configfs_item_operations f_mud_pins_cell_item_item_ops = { + .release = f_mud_pins_cell_item_item_release, +}; + +static const struct config_item_type f_mud_pins_cell_item_func_type = { + .ct_item_ops = &f_mud_pins_cell_item_item_ops, + .ct_attrs = f_mud_pins_cell_item_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct config_group *f_mud_pins_make_group(struct config_group *group, + const char *name) +{ + struct f_mud_pins_cell *pcell = ci_to_f_mud_pins_cell(&group->cg_item); + struct f_mud_pins_cell_item *fitem; + const char *prefix = "pin."; + struct config_group *grp; + int ret, index; + + fmdebug("%s: name=%s\n", __func__, name); + + mutex_lock(&pcell->lock); + fmdebug("%s: pcell=%px pcell->refcnt=%d\n", __func__, pcell, pcell->refcnt); + if (pcell->refcnt) { + grp = ERR_PTR(-EBUSY); + goto out_unlock; + } + + if (strstr(name, prefix) != name) { + pr_err("Missing prefix '%s' in name: '%s'\n", prefix, name); + grp = ERR_PTR(-EINVAL); + goto out_unlock; + } + + ret = kstrtoint(name + strlen(prefix), 10, &index); + if (ret) { + pr_err("Failed to parse index in name: '%s'\n", name); + grp = ERR_PTR(ret); + goto out_unlock; + } + + fitem = kzalloc(sizeof(*fitem), GFP_KERNEL); + fmdebug(" pin=%px\n", fitem); + if (!fitem) { + grp = ERR_PTR(-ENOMEM); + goto out_unlock; + } + + fitem->index = index; + grp = &fitem->group; + + config_group_init_type_name(grp, "", &f_mud_pins_cell_item_func_type); + + list_add(&fitem->node, &pcell->items); +out_unlock: + mutex_unlock(&pcell->lock); + + return grp; +} + +static void f_mud_pins_drop_item(struct config_group *group, struct config_item *item) +{ + struct f_mud_pins_cell *pcell = ci_to_f_mud_pins_cell(&group->cg_item); + struct f_mud_pins_cell_item *fitem = ci_to_f_mud_pins_cell_item(item); + + fmdebug("%s: pcell=%px fitem=%px\n", __func__, pcell, fitem); + + mutex_lock(&pcell->lock); + list_del(&fitem->node); + mutex_unlock(&pcell->lock); + + config_item_put(item); +} + +static struct configfs_group_operations f_mud_pins_group_ops = { + .make_group = f_mud_pins_make_group, + .drop_item = f_mud_pins_drop_item, +}; + +static struct configfs_item_operations f_mud_pins_item_ops = { + .release = f_mud_cell_item_release, +}; + +static const struct config_item_type f_mud_pins_func_type = { + .ct_item_ops = &f_mud_pins_item_ops, + .ct_group_ops = &f_mud_pins_group_ops, + .ct_owner = THIS_MODULE, +}; + +static void f_mud_pins_free(struct f_mud_cell *cell) +{ + struct f_mud_pins_cell *pcell = container_of(cell, struct f_mud_pins_cell, cell); + + fmdebug("%s: pcell=%px\n", __func__, pcell); + + mutex_destroy(&pcell->lock); + kfree(pcell); +} + +static struct f_mud_cell *f_mud_pins_alloc(void) +{ + struct f_mud_pins_cell *pcell; + + pcell = kzalloc(sizeof(*pcell), GFP_KERNEL); + fmdebug("%s: pcell=%px\n", __func__, pcell); + if (!pcell) + return ERR_PTR(-ENOMEM); + + mutex_init(&pcell->lock); + INIT_LIST_HEAD(&pcell->items); + config_group_init_type_name(&pcell->cell.group, "", &f_mud_pins_func_type); + + fmdebug("%s: cell=%px\n", __func__, &pcell->cell); + + return &pcell->cell; +} + +static const struct f_mud_cell_ops f_mud_pins_ops = { + .name = "mud-pins", + .owner = THIS_MODULE, + + .interrupt_interval_ms = 100, + + .alloc = f_mud_pins_alloc, + .free = f_mud_pins_free, + .bind = f_mud_pins_bind, + .unbind = f_mud_pins_unbind, + + .regval_bytes = 4, + .max_transfer_size = 64, + + .disable = f_mud_pins_disable, + .readreg = f_mud_pins_readreg, + .writereg = f_mud_pins_writereg, +}; + +DECLARE_F_MUD_CELL_INIT(f_mud_pins_ops); + +MODULE_AUTHOR("Noralf Trønnes"); +MODULE_LICENSE("GPL"); -- 2.23.0 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.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D758EC76199 for ; Sun, 16 Feb 2020 17:27:22 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (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 BA16A20857 for ; Sun, 16 Feb 2020 17:27:22 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org BA16A20857 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=tronnes.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 883256E46E; Sun, 16 Feb 2020 17:27:06 +0000 (UTC) Received: from asav22.altibox.net (asav22.altibox.net [109.247.116.9]) by gabe.freedesktop.org (Postfix) with ESMTPS id A28AE6E44E for ; Sun, 16 Feb 2020 17:27:00 +0000 (UTC) Received: from localhost.localdomain (unknown [81.166.168.211]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: noralf.tronnes@ebnett.no) by asav22.altibox.net (Postfix) with ESMTPSA id 83324200ED; Sun, 16 Feb 2020 18:21:40 +0100 (CET) From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= To: broonie@kernel.org, balbi@kernel.org, lee.jones@linaro.org Subject: [RFC 5/9] usb: gadget: function: mud: Add gpio support Date: Sun, 16 Feb 2020 18:21:13 +0100 Message-Id: <20200216172117.49832-6-noralf@tronnes.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20200216172117.49832-1-noralf@tronnes.org> References: <20200216172117.49832-1-noralf@tronnes.org> MIME-Version: 1.0 X-CMAE-Score: 0 X-CMAE-Analysis: v=2.3 cv=ZvHD1ezG c=1 sm=1 tr=0 a=OYZzhG0JTxDrWp/F2OJbnw==:117 a=OYZzhG0JTxDrWp/F2OJbnw==:17 a=jpOVt7BSZ2e4Z31A5e1TngXxSK0=:19 a=IkcTkHD0fZMA:10 a=M51BFTxLslgA:10 a=SJz97ENfAAAA:8 a=OVWlCPoClyRDxbRKtg8A:9 a=ENd6JL4-XTPeTk_z:21 a=YaaFWRjS8iQpcXM6:21 a=QEXdDO2ut3YA:10 a=vFet0B0WnEQeilDPIY6i:22 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-usb@vger.kernel.org, dri-devel@lists.freedesktop.org Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" QWRkIG9wdGlvbmFsIGdwaW8gZnVuY3Rpb25hbGl0eSB0byB0aGUgTXVsdGlmdW5jdGlvbiBVU0Ig RGV2aWNlLgoKU2lnbmVkLW9mZi1ieTogTm9yYWxmIFRyw7hubmVzIDxub3JhbGZAdHJvbm5lcy5v cmc+Ci0tLQogZHJpdmVycy91c2IvZ2FkZ2V0L0tjb25maWcgICAgICAgICAgICAgICB8ICAxNCAr CiBkcml2ZXJzL3VzYi9nYWRnZXQvZnVuY3Rpb24vTWFrZWZpbGUgICAgIHwgICAyICsKIGRyaXZl cnMvdXNiL2dhZGdldC9mdW5jdGlvbi9mX211ZF9waW5zLmMgfCA5NjIgKysrKysrKysrKysrKysr KysrKysrKysKIDMgZmlsZXMgY2hhbmdlZCwgOTc4IGluc2VydGlvbnMoKykKIGNyZWF0ZSBtb2Rl IDEwMDY0NCBkcml2ZXJzL3VzYi9nYWRnZXQvZnVuY3Rpb24vZl9tdWRfcGlucy5jCgpkaWZmIC0t Z2l0IGEvZHJpdmVycy91c2IvZ2FkZ2V0L0tjb25maWcgYi9kcml2ZXJzL3VzYi9nYWRnZXQvS2Nv bmZpZwppbmRleCA5NTUxODc2ZmZlMDguLmQ2Mjg1MTQ2ZWM3NiAxMDA2NDQKLS0tIGEvZHJpdmVy cy91c2IvZ2FkZ2V0L0tjb25maWcKKysrIGIvZHJpdmVycy91c2IvZ2FkZ2V0L0tjb25maWcKQEAg LTIxOSw2ICsyMTksOSBAQCBjb25maWcgVVNCX0ZfVENNCiBjb25maWcgVVNCX0ZfTVVECiAJdHJp c3RhdGUKIAorY29uZmlnIFVTQl9GX01VRF9QSU5TCisJdHJpc3RhdGUKKwogIyB0aGlzIGZpcnN0 IHNldCBvZiBkcml2ZXJzIGFsbCBkZXBlbmQgb24gYnVsay1jYXBhYmxlIGhhcmR3YXJlLgogCiBj b25maWcgVVNCX0NPTkZJR0ZTCkBAIC00OTMsNiArNDk2LDE3IEBAIG1lbnVjb25maWcgVVNCX0NP TkZJR0ZTX0ZfTVVECiAJaGVscAogCSAgQ29yZSBzdXBwb3J0IGZvciB0aGUgTXVsdGlmdW5jdGlv biBVU0IgRGV2aWNlLgogCitpZiBVU0JfRl9NVUQKKworY29uZmlnIFVTQl9DT05GSUdGU19GX01V RF9QSU5TCisJYm9vbCAiTXVsdGlmdW5jdGlvbiBVU0IgRGV2aWNlIEdQSU8iCisJZGVwZW5kcyBv biBQSU5DVFJMCisJc2VsZWN0IFVTQl9GX01VRF9QSU5TCisJaGVscAorCSAgR1BJTyBzdXBwb3J0 IGZvciB0aGUgTXVsdGlmdW5jdGlvbiBVU0IgRGV2aWNlLgorCitlbmRpZiAjIFVTQl9GX01VRAor CiBjaG9pY2UKIAl0cmlzdGF0ZSAiVVNCIEdhZGdldCBwcmVjb21wb3NlZCBjb25maWd1cmF0aW9u cyIKIAlkZWZhdWx0IFVTQl9FVEgKZGlmZiAtLWdpdCBhL2RyaXZlcnMvdXNiL2dhZGdldC9mdW5j dGlvbi9NYWtlZmlsZSBiL2RyaXZlcnMvdXNiL2dhZGdldC9mdW5jdGlvbi9NYWtlZmlsZQppbmRl eCBiNmUzMWI1MTE1MjEuLjJlMjQyMjdmY2MxMiAxMDA2NDQKLS0tIGEvZHJpdmVycy91c2IvZ2Fk Z2V0L2Z1bmN0aW9uL01ha2VmaWxlCisrKyBiL2RyaXZlcnMvdXNiL2dhZGdldC9mdW5jdGlvbi9N YWtlZmlsZQpAQCAtNTIsMyArNTIsNSBAQCB1c2JfZl90Y20teQkJCTo9IGZfdGNtLm8KIG9iai0k KENPTkZJR19VU0JfRl9UQ00pCQkrPSB1c2JfZl90Y20ubwogdXNiX2ZfbXVkLXkJCQk6PSBmX211 ZC5vIG11ZF9yZWdtYXAubwogb2JqLSQoQ09ORklHX1VTQl9GX01VRCkJCSs9IHVzYl9mX211ZC5v Cit1c2JfZl9tdWRfcGlucy15CQk6PSBmX211ZF9waW5zLm8KK29iai0kKENPTkZJR19VU0JfRl9N VURfUElOUykJKz0gdXNiX2ZfbXVkX3BpbnMubwpkaWZmIC0tZ2l0IGEvZHJpdmVycy91c2IvZ2Fk Z2V0L2Z1bmN0aW9uL2ZfbXVkX3BpbnMuYyBiL2RyaXZlcnMvdXNiL2dhZGdldC9mdW5jdGlvbi9m X211ZF9waW5zLmMKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMDAwMDAwLi5iMzQ2 NjgwNGFkNWUKLS0tIC9kZXYvbnVsbAorKysgYi9kcml2ZXJzL3VzYi9nYWRnZXQvZnVuY3Rpb24v Zl9tdWRfcGlucy5jCkBAIC0wLDAgKzEsOTYyIEBACisvLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmll cjogR1BMLTIuMC1vci1sYXRlcgorLyoKKyAqIENvcHlyaWdodCAoQykgMjAyMCBOb3JhbGYgVHLD uG5uZXMKKyAqLworCisjaW5jbHVkZSA8bGludXgvYml0bWFwLmg+CisjaW5jbHVkZSA8bGludXgv Y29uZmlnZnMuaD4KKyNpbmNsdWRlIDxsaW51eC9kZXZpY2UuaD4KKyNpbmNsdWRlIDxsaW51eC9n cGlvL2NvbnN1bWVyLmg+CisjaW5jbHVkZSA8bGludXgvZ3Bpby9tYWNoaW5lLmg+CisjaW5jbHVk ZSA8bGludXgvaWRyLmg+CisjaW5jbHVkZSA8bGludXgvaW50ZXJydXB0Lmg+CisjaW5jbHVkZSA8 bGludXgva2VybmVsLmg+CisjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+CisjaW5jbHVkZSA8bGlu dXgvbXV0ZXguaD4KKyNpbmNsdWRlIDxsaW51eC9yZWdtYXAuaD4KKyNpbmNsdWRlIDxsaW51eC9z bGFiLmg+CisjaW5jbHVkZSA8bGludXgvc3RyaW5nLmg+CisKKyNpbmNsdWRlICJmX211ZC5oIgor I2luY2x1ZGUgIi4uLy4uLy4uL3BpbmN0cmwvcGluY3RybC1tdWQuaCIKKworLyoKKyAqIEV2ZW4g dGhvdWdoIHRoZSBob3N0IHNpZGUgaXMgYSBwaW5jdHJsIGRyaXZlciwgdGhlIGRldmljZSBzaWRl IGlzIGEgZ3BpbyBjb25zdW1lci4KKyAqIFRoYXQncyBiZWNhdXNlIG5vdCBhbGwgYm9hcmRzIGhh dmUgYSBwaW4gY29udHJvbGxlci4KKyAqLworCisvKiBUZW1wb3JhcnkgZGVidWdnaW5nIGFpZCAq LworI2RlZmluZSBmbWRlYnVnKGZtdCwgLi4uKQkJCQlcCitkbyB7CQkJCQkJCVwKKwlpZiAoMSkJ CQkJCQlcCisJCXByaW50ayhLRVJOX0RFQlVHIGZtdCwgIyNfX1ZBX0FSR1NfXyk7CVwKK30gd2hp bGUgKDApCisKK3N0YXRpYyBERUZJTkVfSURBKGZfbXVkX3BpbnNfaWRhKTsKKworc3RydWN0IGZf bXVkX3BpbnNfY2VsbF9pdGVtIHsKKwlzdHJ1Y3QgbGlzdF9oZWFkIG5vZGU7CisJdW5zaWduZWQg aW50IGluZGV4OworCXN0cnVjdCBjb25maWdfZ3JvdXAgZ3JvdXA7CisKKwlzdHJ1Y3QgbXV0ZXgg bG9jazsgLyogUHJvdGVjdCB0aGUgdmFsdWVzIGJlbG93ICovCisJaW50IHJlZmNudDsKKworCWNv bnN0IGNoYXIgKm5hbWU7CisJY29uc3QgY2hhciAqY2hpcDsKKwlpbnQgb2Zmc2V0OworfTsKKwor c3RhdGljIGlubGluZSBzdHJ1Y3QgZl9tdWRfcGluc19jZWxsX2l0ZW0gKmNpX3RvX2ZfbXVkX3Bp bnNfY2VsbF9pdGVtKHN0cnVjdCBjb25maWdfaXRlbSAqaXRlbSkKK3sKKwlyZXR1cm4gY29udGFp bmVyX29mKHRvX2NvbmZpZ19ncm91cChpdGVtKSwgc3RydWN0IGZfbXVkX3BpbnNfY2VsbF9pdGVt LCBncm91cCk7Cit9CisKK3N0cnVjdCBmX211ZF9waW5zX2xvb2t1cF9kZXZpY2UgeworCXN0cnVj dCBkZXZpY2UgZGV2OworCWludCBpZDsKKwlzdHJ1Y3QgZl9tdWRfY2VsbCAqY2VsbDsKKwlzdHJ1 Y3QgZ3Bpb2RfbG9va3VwX3RhYmxlICpsb29rdXA7CisJY29uc3QgY2hhciAqKm5hbWVzOworCXVu c2lnbmVkIGludCBjb3VudDsKK307CisKK3N0cnVjdCBmX211ZF9waW5zX3BpbiB7CisJc3RydWN0 IGZfbXVkX3BpbnNfY2VsbCAqcGFyZW50OworCXVuc2lnbmVkIGludCBpbmRleDsKKwlzdHJ1Y3Qg Z3Bpb19kZXNjICpncGlvOworCXVuc2lnbmVkIGxvbmcgZGZsYWdzOworCXVuc2lnbmVkIGludCBk ZWJvdW5jZTsKKyNkZWZpbmUgREVCT1VOQ0VfTk9UX1NFVCBVSU5UX01BWAorCWJvb2wgY29uZmln X3JlcXVlc3RlZDsKKwlpbnQgaXJxOworCWludCBpcnFmbGFnczsKK307CisKK3N0cnVjdCBmX211 ZF9waW5zX2NlbGwgeworCXN0cnVjdCBmX211ZF9jZWxsIGNlbGw7CisKKwlzdHJ1Y3QgbXV0ZXgg bG9jazsgLyogUHJvdGVjdCByZWZjbnQgYW5kIGl0ZW1zICovCisJaW50IHJlZmNudDsKKwlzdHJ1 Y3QgbGlzdF9oZWFkIGl0ZW1zOworCisJc3RydWN0IGZfbXVkX3BpbnNfbG9va3VwX2RldmljZSAq bGRldjsKKwlzdHJ1Y3QgZl9tdWRfcGluc19waW4gKnBpbnM7CisJdW5zaWduZWQgaW50IGNvdW50 OworCXNwaW5sb2NrX3QgaXJxX3N0YXR1c19sb2NrOworCXVuc2lnbmVkIGxvbmcgKmlycV9zdGF0 dXM7Cit9OworCitzdGF0aWMgaW5saW5lIHN0cnVjdCBmX211ZF9waW5zX2NlbGwgKmNpX3RvX2Zf bXVkX3BpbnNfY2VsbChzdHJ1Y3QgY29uZmlnX2l0ZW0gKml0ZW0pCit7CisJcmV0dXJuIGNvbnRh aW5lcl9vZih0b19jb25maWdfZ3JvdXAoaXRlbSksIHN0cnVjdCBmX211ZF9waW5zX2NlbGwsIGNl bGwuZ3JvdXApOworfQorCitzdGF0aWMgaW5saW5lIHN0cnVjdCBmX211ZF9waW5zX2NlbGwgKmNl bGxfdG9fcGNlbGwoc3RydWN0IGZfbXVkX2NlbGwgKmNlbGwpCit7CisJcmV0dXJuIGNvbnRhaW5l cl9vZihjZWxsLCBzdHJ1Y3QgZl9tdWRfcGluc19jZWxsLCBjZWxsKTsKK30KKworc3RhdGljIGly cXJldHVybl90IGZfbXVkX3BpbnNfZ3Bpb19pcnFfdGhyZWFkKGludCBpcnEsIHZvaWQgKnApCit7 CisJc3RydWN0IGZfbXVkX3BpbnNfcGluICpwaW4gPSBwOworCXN0cnVjdCBmX211ZF9waW5zX2Nl bGwgKnBjZWxsID0gcGluLT5wYXJlbnQ7CisKKwlzcGluX2xvY2soJnBjZWxsLT5pcnFfc3RhdHVz X2xvY2spOworCXNldF9iaXQocGluLT5pbmRleCwgcGNlbGwtPmlycV9zdGF0dXMpOworCXNwaW5f dW5sb2NrKCZwY2VsbC0+aXJxX3N0YXR1c19sb2NrKTsKKworCWZtZGVidWcoIiVzKGluZGV4PSV1 KTogaXJxX3N0YXR1cz0lKnBiXG4iLCBfX2Z1bmNfXywgcGluLT5pbmRleCwKKwkJcGNlbGwtPmNv dW50LCBwY2VsbC0+aXJxX3N0YXR1cyk7CisKKwlmX211ZF9pcnEocGNlbGwtPmxkZXYtPmNlbGwp OworCisJcmV0dXJuIElSUV9IQU5ETEVEOworfQorCitzdGF0aWMgaW50IGZfbXVkX3BpbnNfZ3Bp b19pcnFfcmVxdWVzdChzdHJ1Y3QgZl9tdWRfcGluc19jZWxsICpwY2VsbCwgdW5zaWduZWQgaW50 IGluZGV4KQoreworCXN0cnVjdCBmX211ZF9waW5zX3BpbiAqcGluID0gJnBjZWxsLT5waW5zW2lu ZGV4XTsKKwlpbnQgcmV0LCBpcnE7CisKKwlmbWRlYnVnKCIlcyhpbmRleD0ldSlcbiIsIF9fZnVu Y19fLCBpbmRleCk7CisKKwlpZiAocGluLT5pcnEpCisJCXJldHVybiAwOworCisJaWYgKCFwaW4t PmdwaW8gfHwgIXBpbi0+aXJxZmxhZ3MpCisJCXJldHVybiAtRUlOVkFMOworCisJcmV0ID0gZ3Bp b2RfZ2V0X2RpcmVjdGlvbihwaW4tPmdwaW8pOworCWlmIChyZXQgPCAwKQorCQlyZXR1cm4gcmV0 OworCWlmIChyZXQgIT0gMSkKKwkJcmV0dXJuIC1FSU5WQUw7CisKKwlpcnEgPSBncGlvZF90b19p cnEocGluLT5ncGlvKTsKKwlmbWRlYnVnKCIgICAgaXJxPSVkXG4iLCBpcnEpOworCWlmIChpcnEg PD0gMCkKKwkJcmV0dXJuIC1FTk9ERVY7CisKKwlyZXQgPSByZXF1ZXN0X3RocmVhZGVkX2lycShp cnEsIE5VTEwsIGZfbXVkX3BpbnNfZ3Bpb19pcnFfdGhyZWFkLAorCQkJCSAgIHBpbi0+aXJxZmxh Z3MgfCBJUlFGX09ORVNIT1QsCisJCQkJICAgZGV2X25hbWUoJnBjZWxsLT5sZGV2LT5kZXYpLCBw aW4pOworCWlmIChyZXQpCisJCXJldHVybiByZXQ7CisKKwlwaW4tPmlycSA9IGlycTsKKworCXJl dHVybiAwOworfQorCitzdGF0aWMgdm9pZCBmX211ZF9waW5zX2dwaW9faXJxX2ZyZWUoc3RydWN0 IGZfbXVkX3BpbnNfY2VsbCAqcGNlbGwsIHVuc2lnbmVkIGludCBpbmRleCkKK3sKKwlzdHJ1Y3Qg Zl9tdWRfcGluc19waW4gKnBpbiA9ICZwY2VsbC0+cGluc1tpbmRleF07CisKKwlmbWRlYnVnKCIl cyhpbmRleD0ldSk6IGlycT0lZFxuIiwgX19mdW5jX18sIGluZGV4LCBwaW4tPmlycSk7CisKKwlp ZiAocGluLT5pcnEpIHsKKwkJZnJlZV9pcnEocGluLT5pcnEsIHBpbik7CisJCXBpbi0+aXJxID0g MDsKKwl9Cit9CisKK3N0YXRpYyB2b2lkIGZfbXVkX3BpbnNfZ3Bpb19pcnFfZnJlZV9hbGwoc3Ry dWN0IGZfbXVkX3BpbnNfY2VsbCAqcGNlbGwpCit7CisJdW5zaWduZWQgaW50IGk7CisKKwlmb3Ig KGkgPSAwOyBpIDwgcGNlbGwtPmNvdW50OyBpKyspCisJCWZfbXVkX3BpbnNfZ3Bpb19pcnFfZnJl ZShwY2VsbCwgaSk7Cit9CisKK3N0YXRpYyBpbnQgZl9tdWRfcGluc19ncGlvX2lycV90eXBlKHN0 cnVjdCBmX211ZF9waW5zX2NlbGwgKnBjZWxsLCB1bnNpZ25lZCBpbnQgaW5kZXgsCisJCQkJICAg IHVuc2lnbmVkIGludCB2YWwpCit7CisJc3RydWN0IGZfbXVkX3BpbnNfcGluICpwaW4gPSAmcGNl bGwtPnBpbnNbaW5kZXhdOworCisJZm1kZWJ1ZygiJXMoaW5kZXg9JXUsIHZhbD0ldSlcbiIsIF9f ZnVuY19fLCBpbmRleCwgdmFsKTsKKworCXN3aXRjaCAodmFsKSB7CisJY2FzZSBNVURfUElOX0lS UV9UWVBFX0VER0VfUklTSU5HOgorCQlwaW4tPmlycWZsYWdzID0gSVJRRl9UUklHR0VSX1JJU0lO RzsKKwkJYnJlYWs7CisJY2FzZSBNVURfUElOX0lSUV9UWVBFX0VER0VfRkFMTElORzoKKwkJcGlu LT5pcnFmbGFncyA9IElSUUZfVFJJR0dFUl9GQUxMSU5HOworCQlicmVhazsKKwljYXNlIE1VRF9Q SU5fSVJRX1RZUEVfRURHRV9CT1RIOgorCQlwaW4tPmlycWZsYWdzID0gSVJRRl9UUklHR0VSX1JJ U0lORyB8IElSUUZfVFJJR0dFUl9GQUxMSU5HOworCQlicmVhazsKKwljYXNlIE1VRF9QSU5fSVJR X1RZUEVfTk9ORToKKwkJcGluLT5pcnFmbGFncyA9IElSUUZfVFJJR0dFUl9OT05FOworCQlicmVh azsKKwlkZWZhdWx0OgorCQlyZXR1cm4gLUVJTlZBTDsKKwl9OworCisJcmV0dXJuIDA7Cit9CisK K3N0YXRpYyB2b2lkIGZfbXVkX3BpbnNfZ3Bpb19mcmVlKHN0cnVjdCBmX211ZF9waW5zX2NlbGwg KnBjZWxsLCB1bnNpZ25lZCBpbnQgaW5kZXgpCit7CisJc3RydWN0IGZfbXVkX3BpbnNfcGluICpw aW4gPSAmcGNlbGwtPnBpbnNbaW5kZXhdOworCisJZm1kZWJ1ZygiJXMoaW5kZXg9JXUpOiBncGlv PSVkLCBjb25maWdfcmVxdWVzdGVkPSV1XG4iLCBfX2Z1bmNfXywgaW5kZXgsCisJCXBpbi0+Z3Bp byA/IGRlc2NfdG9fZ3BpbyhwaW4tPmdwaW8pIDogLTEsIHBpbi0+Y29uZmlnX3JlcXVlc3RlZCk7 CisKKwlpZiAocGluLT5jb25maWdfcmVxdWVzdGVkKQorCQlyZXR1cm47CisKKwlpZiAocGluLT5n cGlvKQorCQlncGlvZF9wdXQocGluLT5ncGlvKTsKKwlwaW4tPmdwaW8gPSBOVUxMOworfQorCisv KiBXaGVuIGZsYWdzIGNoYW5nZSByZS1yZXF1ZXN0IHRoZSBncGlvIHRvIGVuYWJsZSB0aGUgc2V0 dGluZ3MgKi8KK3N0YXRpYyBpbnQgZl9tdWRfcGluc19ncGlvX3JlcXVlc3RfZG8oc3RydWN0IGZf bXVkX3BpbnNfY2VsbCAqcGNlbGwsIHVuc2lnbmVkIGludCBpbmRleCwKKwkJCQkgICAgICBib29s IGNvbmZpZywgdW5zaWduZWQgaW50IGRlYm91bmNlKQoreworCXN0cnVjdCBmX211ZF9waW5zX3Bp biAqcGluID0gJnBjZWxsLT5waW5zW2luZGV4XTsKKwlzdHJ1Y3QgZ3Bpb19kZXNjICpncGlvOwor CWludCByZXQ7CisKKwlmbWRlYnVnKCIlcyhpbmRleD0ldSk6IGxmbGFncz0lbHUgZGZsYWdzPSVs dVxuIiwgX19mdW5jX18sIGluZGV4LAorCQlwY2VsbC0+bGRldi0+bG9va3VwLT50YWJsZVtpbmRl eF0uZmxhZ3MsIHBpbi0+ZGZsYWdzKTsKKworCWlmICghcGNlbGwtPnBpbnNbaW5kZXhdLmdwaW8g JiYgY29uZmlnKQorCQlwaW4tPmNvbmZpZ19yZXF1ZXN0ZWQgPSB0cnVlOworCisJaWYgKHBjZWxs LT5waW5zW2luZGV4XS5ncGlvKSB7CisJCWdwaW9kX3B1dChwY2VsbC0+cGluc1tpbmRleF0uZ3Bp byk7CisJCXBjZWxsLT5waW5zW2luZGV4XS5ncGlvID0gTlVMTDsKKwl9CisKKwlncGlvID0gZ3Bp b2RfZ2V0X2luZGV4KCZwY2VsbC0+bGRldi0+ZGV2LCBOVUxMLCBpbmRleCwgcGluLT5kZmxhZ3Mp OworCWlmIChJU19FUlIoZ3BpbykpIHsKKwkJcmV0ID0gUFRSX0VSUihncGlvKTsKKwkJZm1kZWJ1 ZygiZmFpbGVkIHRvIGdldCBncGlvICV1OiByZXQ9JWRcbiIsIGluZGV4LCByZXQpOworCQlyZXR1 cm4gcmV0OworCX0KKwlwaW4tPmdwaW8gPSBncGlvOworCWZtZGVidWcoIiAgICBncGlvc1sldV06 IGdwaW9uciAlZFxuIiwgaW5kZXgsIGRlc2NfdG9fZ3BpbyhncGlvKSk7CisKKwkvKiBEZWJvdW5j ZSBjYW4gYmUgc2V0IHRocm91Z2ggcGluY29uZiBzbyBpdCBtdXN0IGJlIHN0b3JlZCAqLworCWlm IChkZWJvdW5jZSA9PSBERUJPVU5DRV9OT1RfU0VUKQorCQlkZWJvdW5jZSA9IHBpbi0+ZGVib3Vu Y2U7CisKKwlpZiAoZGVib3VuY2UgIT0gREVCT1VOQ0VfTk9UX1NFVCkgeworCQlyZXQgPSBncGlv ZF9zZXRfZGVib3VuY2UocGluLT5ncGlvLCBkZWJvdW5jZSk7CisJCWlmIChyZXQpCisJCQlyZXR1 cm4gcmV0OworCisJCXBpbi0+ZGVib3VuY2UgPSBkZWJvdW5jZSA/IGRlYm91bmNlIDogREVCT1VO Q0VfTk9UX1NFVDsKKwl9CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGludCBmX211ZF9waW5z X2dwaW9fcmVxdWVzdF9kZWJvdW5jZShzdHJ1Y3QgZl9tdWRfcGluc19jZWxsICpwY2VsbCwKKwkJ CQkJICAgIHVuc2lnbmVkIGludCBpbmRleCwgdW5zaWduZWQgaW50IGRlYm91bmNlKQoreworCXN0 cnVjdCBmX211ZF9waW5zX3BpbiAqcGluID0gJnBjZWxsLT5waW5zW2luZGV4XTsKKworCWlmIChw aW4tPmRlYm91bmNlID09IGRlYm91bmNlKQorCQlyZXR1cm4gMDsKKworCXJldHVybiBmX211ZF9w aW5zX2dwaW9fcmVxdWVzdF9kbyhwY2VsbCwgaW5kZXgsIHRydWUsIGRlYm91bmNlKTsKK30KKwor c3RhdGljIGludCBmX211ZF9waW5zX2dwaW9fcmVxdWVzdF9kZmxhZyhzdHJ1Y3QgZl9tdWRfcGlu c19jZWxsICpwY2VsbCwgdW5zaWduZWQgaW50IGluZGV4LAorCQkJCQkgZW51bSBncGlvZF9mbGFn cyBkZmxhZywgYm9vbCBkdmFsLCBib29sIGNvbmZpZykKK3sKKwlzdHJ1Y3QgZl9tdWRfcGluc19w aW4gKnBpbiA9ICZwY2VsbC0+cGluc1tpbmRleF07CisJYm9vbCBjdXJyX2RmbGFnID0gcGluLT5k ZmxhZ3MgJiBkZmxhZzsKKwlib29sIGNoYW5nZWQgPSBmYWxzZTsKKworCWZtZGVidWcoIiVzKGlu ZGV4PSV1KTogZGZsYWc9JXUgZHZhbD0ldVxuIiwgX19mdW5jX18sIGluZGV4LCBkZmxhZywgZHZh bCk7CisKKwlpZiAoY3Vycl9kZmxhZyAhPSBkdmFsKSB7CisJCWlmIChkdmFsKQorCQkJcGluLT5k ZmxhZ3MgfD0gZGZsYWc7CisJCWVsc2UKKwkJCXBpbi0+ZGZsYWdzICY9IH5kZmxhZzsKKwkJY2hh bmdlZCA9IHRydWU7CisJfQorCisJaWYgKHBpbi0+Z3BpbyAmJiAhY2hhbmdlZCkKKwkJcmV0dXJu IDA7CisKKwlyZXR1cm4gZl9tdWRfcGluc19ncGlvX3JlcXVlc3RfZG8ocGNlbGwsIGluZGV4LCBj b25maWcsIERFQk9VTkNFX05PVF9TRVQpOworfQorCitzdGF0aWMgaW50IGZfbXVkX3BpbnNfZ3Bp b19yZXF1ZXN0X2xmbGFnKHN0cnVjdCBmX211ZF9waW5zX2NlbGwgKnBjZWxsLCB1bnNpZ25lZCBp bnQgaW5kZXgsCisJCQkJCSBlbnVtIGdwaW9fbG9va3VwX2ZsYWdzIGxmbGFnLCBib29sIGx2YWws CisJCQkJCSBib29sIGNvbmZpZykKK3sKKwlzdHJ1Y3QgZ3Bpb2RfbG9va3VwICpsZW50cnkgPSAm cGNlbGwtPmxkZXYtPmxvb2t1cC0+dGFibGVbaW5kZXhdOworCXN0cnVjdCBmX211ZF9waW5zX3Bp biAqcGluID0gJnBjZWxsLT5waW5zW2luZGV4XTsKKwlib29sIGN1cnJfbGZsYWcgPSBsZW50cnkt PmZsYWdzICYgbGZsYWc7CisJYm9vbCBjaGFuZ2VkID0gZmFsc2U7CisKKwlmbWRlYnVnKCIlcyhp bmRleD0ldSk6IGxmbGFnPSV1IGx2YWw9JXVcbiIsIF9fZnVuY19fLCBpbmRleCwgbGZsYWcsIGx2 YWwpOworCisJaWYgKGN1cnJfbGZsYWcgIT0gbHZhbCkgeworCQlpZiAobHZhbCkKKwkJCWxlbnRy eS0+ZmxhZ3MgfD0gbGZsYWc7CisJCWVsc2UKKwkJCWxlbnRyeS0+ZmxhZ3MgJj0gfmxmbGFnOwor CQljaGFuZ2VkID0gdHJ1ZTsKKwl9CisKKwlpZiAocGluLT5ncGlvICYmICFjaGFuZ2VkKQorCQly ZXR1cm4gMDsKKworCXJldHVybiBmX211ZF9waW5zX2dwaW9fcmVxdWVzdF9kbyhwY2VsbCwgaW5k ZXgsIGNvbmZpZywgREVCT1VOQ0VfTk9UX1NFVCk7Cit9CisKK3N0YXRpYyBpbnQgZl9tdWRfcGlu c193cml0ZV9ncGlvX2NvbmZpZyhzdHJ1Y3QgZl9tdWRfcGluc19jZWxsICpwY2VsbCwgdW5zaWdu ZWQgaW50IGluZGV4LAorCQkJCQl1bnNpZ25lZCBpbnQgb2Zmc2V0LCB1bnNpZ25lZCBpbnQgdmFs KQoreworCXN0cnVjdCBmX211ZF9waW5zX3BpbiAqcGluOworCWludCByZXQgPSAtRU5PVFNVUFA7 CisKKwlmbWRlYnVnKCIlcyhpbmRleD0ldSwgb2Zmc2V0PTB4JTAyeCwgdmFsPSV1KVxuIiwgX19m dW5jX18sIGluZGV4LCBvZmZzZXQsIHZhbCk7CisKKwlwaW4gPSAmcGNlbGwtPnBpbnNbaW5kZXhd OworCisJc3dpdGNoIChvZmZzZXQpIHsKKwljYXNlIE1VRF9QSU5fQ09ORklHX0JJQVNfUFVMTF9E T1dOOgorCQlpZiAoIXZhbCkKKwkJCXJldHVybiAtRU5PVFNVUFA7CisJCXJldCA9IGZfbXVkX3Bp bnNfZ3Bpb19yZXF1ZXN0X2xmbGFnKHBjZWxsLCBpbmRleCwgR1BJT19QVUxMX0RPV04sIHZhbCwg dHJ1ZSk7CisJCWJyZWFrOworCWNhc2UgTVVEX1BJTl9DT05GSUdfQklBU19QVUxMX1VQOgorCQlp ZiAoIXZhbCkKKwkJCXJldHVybiAtRU5PVFNVUFA7CisJCXJldCA9IGZfbXVkX3BpbnNfZ3Bpb19y ZXF1ZXN0X2xmbGFnKHBjZWxsLCBpbmRleCwgR1BJT19QVUxMX1VQLCB2YWwsIHRydWUpOworCQli cmVhazsKKwljYXNlIE1VRF9QSU5fQ09ORklHX0RSSVZFX09QRU5fRFJBSU46CisJCXJldCA9IGZf bXVkX3BpbnNfZ3Bpb19yZXF1ZXN0X2xmbGFnKHBjZWxsLCBpbmRleCwgR1BJT19PUEVOX0RSQUlO LCAxLCB0cnVlKTsKKwkJYnJlYWs7CisJY2FzZSBNVURfUElOX0NPTkZJR19EUklWRV9PUEVOX1NP VVJDRToKKwkJcmV0ID0gZl9tdWRfcGluc19ncGlvX3JlcXVlc3RfbGZsYWcocGNlbGwsIGluZGV4 LCBHUElPX09QRU5fU09VUkNFLCAxLCB0cnVlKTsKKwkJYnJlYWs7CisJY2FzZSBNVURfUElOX0NP TkZJR19EUklWRV9QVVNIX1BVTEw6CisJCXJldCA9IGZfbXVkX3BpbnNfZ3Bpb19yZXF1ZXN0X2Rm bGFnKHBjZWxsLCBpbmRleCwgR1BJT0RfSU4sIDAsIHRydWUpOworCQlicmVhazsKKwljYXNlIE1V RF9QSU5fQ09ORklHX0lOUFVUX0RFQk9VTkNFOgorCQlyZXQgPSBmX211ZF9waW5zX2dwaW9fcmVx dWVzdF9kZWJvdW5jZShwY2VsbCwgaW5kZXgsIHZhbCk7CisJCWJyZWFrOworCWNhc2UgTVVEX1BJ Tl9DT05GSUdfSU5QVVRfRU5BQkxFOgorCQlyZXQgPSBmX211ZF9waW5zX2dwaW9fcmVxdWVzdF9k ZmxhZyhwY2VsbCwgaW5kZXgsIEdQSU9EX0lOLCB2YWwsIHRydWUpOworCQlicmVhazsKKwljYXNl IE1VRF9QSU5fQ09ORklHX09VVFBVVDoKKwkJdmFsID0gdmFsID8gR1BJT0RfT1VUX0hJR0ggOiBH UElPRF9PVVRfTE9XOworCQlyZXQgPSBmX211ZF9waW5zX2dwaW9fcmVxdWVzdF9kZmxhZyhwY2Vs bCwgaW5kZXgsIHZhbCwgMSwgdHJ1ZSk7CisJCWJyZWFrOworCWNhc2UgTVVEX1BJTl9DT05GSUdf UEVSU0lTVF9TVEFURToKKwkJcmV0ID0gZl9tdWRfcGluc19ncGlvX3JlcXVlc3RfbGZsYWcocGNl bGwsIGluZGV4LCBHUElPX1RSQU5TSVRPUlksIHZhbCwgdHJ1ZSk7CisJCWJyZWFrOworCX0KKwor CXJldHVybiByZXQ7Cit9CisKK3N0YXRpYyBpbnQgZl9tdWRfcGluc193cml0ZV9ncGlvKHN0cnVj dCBmX211ZF9waW5zX2NlbGwgKnBjZWxsLCB1bnNpZ25lZCBpbnQgcmVnbnIsCisJCQkJIGNvbnN0 IHZvaWQgKmJ1Ziwgc2l6ZV90IGxlbikKK3sKKwl1bnNpZ25lZCBpbnQgcmVnYmFzZSA9IHJlZ25y IC0gTVVEX1BJTkNUUkxfUkVHX1BJTl9CQVNFOworCXVuc2lnbmVkIGludCBvZmZzZXQgPSByZWdi YXNlICUgTVVEX1BJTkNUUkxfUElOX0JMT0NLX1NJWkU7CisJdW5zaWduZWQgaW50IGluZGV4ID0g cmVnYmFzZSAvIE1VRF9QSU5DVFJMX1BJTl9CTE9DS19TSVpFOworCXNpemVfdCBjb3VudCA9IGxl biAvIHNpemVvZih1MzIpOworCXN0cnVjdCBmX211ZF9waW5zX3BpbiAqcGluOworCWNvbnN0IF9f bGUzMiAqYnVmMzIgPSBidWY7CisJdTMyIHZhbDsKKwlpbnQgcmV0OworCisJZm1kZWJ1ZygiJXMo bGVuPSV6dSk6IG9mZnNldD0weCUwMnggaW5kZXg9JXVcbiIsIF9fZnVuY19fLCBsZW4sIG9mZnNl dCwgaW5kZXgpOworCisJaWYgKGluZGV4ID49IHBjZWxsLT5jb3VudCkgeworCQlmbWRlYnVnKCIl czogZ3BpbyBpbmRleCBvdXQgb2YgYm91bmRzOiAldVxuIiwgX19mdW5jX18sIGluZGV4KTsKKwkJ cmV0dXJuIC1FSU5WQUw7CisJfQorCisJd2hpbGUgKGNvdW50LS0pIHsKKwkJcGluID0gJnBjZWxs LT5waW5zW2luZGV4XTsKKwkJdmFsID0gbGUzMl90b19jcHVwKGJ1ZjMyKyspOworCQlyZXQgPSAw OworCisJCXN3aXRjaCAob2Zmc2V0KyspIHsKKwkJY2FzZSBNVURfUElOX0NPTkZJR19CSUFTX0JV U19IT0xEIC4uLiBNVURfUElOX0NPTkZJR19FTkQ6CisJCQlyZXR1cm4gZl9tdWRfcGluc193cml0 ZV9ncGlvX2NvbmZpZyhwY2VsbCwgaW5kZXgsIG9mZnNldCAtIDEsIHZhbCk7CisKKwkJY2FzZSBN VURfUElOX0dQSU9fUkVRVUVTVDoKKwkJCWlmICh2YWwgIT0gMSkKKwkJCQlyZXR1cm4gLUVJTlZB TDsKKwkJCS8qIFBlcnNpc3RlbmNlIGlzIHRoZSBkZWZhdWx0IHNvIHNldCBpdCBmcm9tIHRoZSBz dGFydCAqLworCQkJcmV0ID0gZl9tdWRfcGluc19ncGlvX3JlcXVlc3RfbGZsYWcocGNlbGwsIGlu ZGV4LCBHUElPX1RSQU5TSVRPUlksCisJCQkJCQkJICAgIDAsIGZhbHNlKTsKKwkJCWJyZWFrOwor CQljYXNlIE1VRF9QSU5fR1BJT19GUkVFOgorCQkJaWYgKHZhbCAhPSAxKQorCQkJCXJldHVybiAt RUlOVkFMOworCQkJZl9tdWRfcGluc19ncGlvX2ZyZWUocGNlbGwsIGluZGV4KTsKKwkJCWJyZWFr OworCisJCWNhc2UgTVVEX1BJTl9ESVJFQ1RJT046CisJCQlpZiAoIXBpbikKKwkJCQlyZXR1cm4g LUVJTlZBTDsKKworCQkJaWYgKHZhbCA9PSBNVURfUElOX0RJUkVDVElPTl9JTlBVVCkgeworCQkJ CXJldCA9IGdwaW9kX2RpcmVjdGlvbl9pbnB1dChwaW4tPmdwaW8pOworCQkJfSBlbHNlIHsKKwkJ CQlpbnQgdmFsdWUgPSAhISh2YWwgJiBNVURfUElOX0RJUkVDVElPTl9PVVRQVVRfSElHSCk7CisK KwkJCQlyZXQgPSBncGlvZF9kaXJlY3Rpb25fb3V0cHV0KHBpbi0+Z3BpbywgdmFsdWUpOworCQkJ fQorCQkJYnJlYWs7CisJCWNhc2UgTVVEX1BJTl9MRVZFTDoKKwkJCWlmIChwaW4pCisJCQkJZ3Bp b2Rfc2V0X3ZhbHVlX2NhbnNsZWVwKHBpbi0+Z3BpbywgdmFsKTsKKwkJCWJyZWFrOworCQljYXNl IE1VRF9QSU5fSVJRX1RZUEU6CisJCQlyZXQgPSBmX211ZF9waW5zX2dwaW9faXJxX3R5cGUocGNl bGwsIGluZGV4LCB2YWwpOworCQkJYnJlYWs7CisJCWNhc2UgTVVEX1BJTl9JUlFfRU5BQkxFRDoK KwkJCWlmICh2YWwpCisJCQkJcmV0ID0gZl9tdWRfcGluc19ncGlvX2lycV9yZXF1ZXN0KHBjZWxs LCBpbmRleCk7CisJCQllbHNlCisJCQkJZl9tdWRfcGluc19ncGlvX2lycV9mcmVlKHBjZWxsLCBp bmRleCk7CisJCQlicmVhazsKKwkJZGVmYXVsdDoKKwkJCXByX2VycigiJXM6IHVua25vd24gcmVn aXN0ZXI6IDB4JXhcbiIsIF9fZnVuY19fLCByZWducik7CisJCQlyZXR1cm4gLUVJTlZBTDsKKwkJ fQorCisJCWlmIChyZXQgPCAwKQorCQkJcmV0dXJuIHJldDsKKwl9CisKKwlyZXR1cm4gMDsKK30K Kworc3RhdGljIGludCBmX211ZF9waW5zX3dyaXRlcmVnKHN0cnVjdCBmX211ZF9jZWxsICpjZWxs LCB1bnNpZ25lZCBpbnQgcmVnbnIsCisJCQkgICAgICAgY29uc3Qgdm9pZCAqYnVmLCBzaXplX3Qg bGVuLCB1OCBjb21wcmVzc2lvbikKK3sKKwlzdHJ1Y3QgZl9tdWRfcGluc19jZWxsICpwY2VsbCA9 IGNlbGxfdG9fcGNlbGwoY2VsbCk7CisKKwlmbWRlYnVnKCIlcyhyZWducj0weCUwMngsIGxlbj0l enUpXG4iLCBfX2Z1bmNfXywgcmVnbnIsIGxlbik7CisKKwlpZiAocmVnbnIgPj0gTVVEX1BJTkNU UkxfUkVHX1BJTl9CQVNFKQorCQlyZXR1cm4gZl9tdWRfcGluc193cml0ZV9ncGlvKHBjZWxsLCBy ZWduciwgYnVmLCBsZW4pOworCisJcmV0dXJuIC1FSU5WQUw7Cit9CisKK3N0YXRpYyBpbnQgZl9t dWRfcGluc19yZWFkX2dwaW8oc3RydWN0IGZfbXVkX3BpbnNfY2VsbCAqcGNlbGwsIHVuc2lnbmVk IGludCByZWduciwKKwkJCQl2b2lkICpidWYsIHNpemVfdCBsZW4pCit7CisJdW5zaWduZWQgaW50 IHJlZ2Jhc2UgPSByZWduciAtIE1VRF9QSU5DVFJMX1JFR19QSU5fQkFTRTsKKwl1bnNpZ25lZCBp bnQgb2Zmc2V0ID0gcmVnYmFzZSAlIE1VRF9QSU5DVFJMX1BJTl9CTE9DS19TSVpFOworCXVuc2ln bmVkIGludCBpbmRleCA9IHJlZ2Jhc2UgLyBNVURfUElOQ1RSTF9QSU5fQkxPQ0tfU0laRTsKKwlz aXplX3QgY291bnQgPSBsZW4gLyBzaXplb2YodTMyKTsKKwlzdHJ1Y3QgZl9tdWRfcGluc19waW4g KnBpbjsKKwlzdHJ1Y3QgZ3Bpb19kZXNjICpncGlvOworCV9fbGUzMiAqYnVmMzIgPSBidWY7CisJ dTMyIHZhbDsKKwlpbnQgcmV0OworCisJZm1kZWJ1ZygiJXMobGVuPSV6dSk6IG9mZnNldD0weCUw MnggaW5kZXg9JXVcbiIsIF9fZnVuY19fLCBsZW4sIG9mZnNldCwgaW5kZXgpOworCisJaWYgKGlu ZGV4ID49IHBjZWxsLT5jb3VudCkgeworCQlmbWRlYnVnKCIlczogZ3BpbyBpbmRleCBvdXQgb2Yg Ym91bmRzOiAldVxuIiwgX19mdW5jX18sIGluZGV4KTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQor CisJaWYgKG9mZnNldCA+PSBNVURfUElOX05BTUUgJiYgKG9mZnNldCArIGNvdW50IC0gMSkgPD0g TVVEX1BJTl9OQU1FX0VORCkgeworCQlzaXplX3Qgc3RhcnQgPSAob2Zmc2V0IC0gTVVEX1BJTl9O QU1FKSAqIHNpemVvZih1MzIpOworCQljaGFyIG5hbWVbTVVEX1BJTl9OQU1FX0xFTl07CisKKwkJ c3Ryc2NweV9wYWQobmFtZSwgcGNlbGwtPmxkZXYtPm5hbWVzW2luZGV4XSwgTVVEX1BJTl9OQU1F X0xFTik7CisJCWZtZGVidWcoIiAgICBuYW1lPSUqcGhcbiIsIE1VRF9QSU5fTkFNRV9MRU4sIG5h bWUpOworCQltZW1jcHkoYnVmLCBuYW1lICsgc3RhcnQsIGxlbik7CisKKwkJcmV0dXJuIDA7CisJ fQorCisJcGluID0gJnBjZWxsLT5waW5zW2luZGV4XTsKKworCXdoaWxlIChjb3VudC0tKSB7CisJ CXN3aXRjaCAob2Zmc2V0KyspIHsKKwkJY2FzZSBNVURfUElOX0RJUkVDVElPTjoKKwkJCS8qCisJ CQkgKiBIb3N0IHNpZGUgZ3Bpb2NoaXBfYWRkX2RhdGFfd2l0aF9rZXkoKSBjYWxscyAtPmdldF9k aXJlY3Rpb24KKwkJCSAqIHdpdGhvdXQgcmVxdWVzdGluZyB0aGUgZ3BpbyBmaXJzdC4KKwkJCSAq LworCQkJZ3BpbyA9IHBpbi0+Z3BpbzsKKwkJCWlmICghZ3BpbykgeworCQkJCS8qIG5vbiBncGlv IHBpbnMgd2lsbCBmYWlsIGhlcmUsIGJ1dCB0aGF0J3MgZmluZSAqLworCQkJCXJldCA9IGZfbXVk X3BpbnNfZ3Bpb19yZXF1ZXN0X2xmbGFnKHBjZWxsLCBpbmRleCwKKwkJCQkJCQkJICAgIDAsIDAs IGZhbHNlKTsKKwkJCQlpZiAocmV0KQorCQkJCQlyZXR1cm4gcmV0OworCQkJfQorCQkJcmV0ID0g Z3Bpb2RfZ2V0X2RpcmVjdGlvbihwaW4tPmdwaW8pOworCQkJaWYgKCFncGlvKQorCQkJCWZfbXVk X3BpbnNfZ3Bpb19mcmVlKHBjZWxsLCBpbmRleCk7CisJCQlpZiAocmV0IDwgMCkKKwkJCQlyZXR1 cm4gcmV0OworCQkJdmFsID0gcmV0ID8gTVVEX1BJTl9ESVJFQ1RJT05fSU5QVVQgOiBNVURfUElO X0RJUkVDVElPTl9PVVRQVVQ7CisJCQlicmVhazsKKwkJY2FzZSBNVURfUElOX0xFVkVMOgorCQkJ aWYgKCFwaW4tPmdwaW8pCisJCQkJcmV0dXJuIC1FSU5WQUw7CisJCQlyZXQgPSBncGlvZF9nZXRf dmFsdWVfY2Fuc2xlZXAocGluLT5ncGlvKTsKKwkJCWlmIChyZXQgPCAwKQorCQkJCXJldHVybiBy ZXQ7CisJCQl2YWwgPSByZXQ7CisJCQlicmVhazsKKwkJY2FzZSBNVURfUElOX0lSUV9UWVBFUzoK KwkJCS8qIEZJWE1FOiBJcyBpdCBwb3NzaWJsZSB0byBnZXQgdGhpcyBpbmZvIHNvbWV3aGVyZT8g Ki8KKwkJCXZhbCA9IE1VRF9QSU5fSVJRX1RZUEVfRURHRV9CT1RIOworCQkJYnJlYWs7CisJCWRl ZmF1bHQ6CisJCQlwcl9lcnIoIiVzOiB1bmtub3duIHJlZ2lzdGVyOiAweCV4XG4iLCBfX2Z1bmNf XywgcmVnbnIpOworCQkJcmV0dXJuIC1FSU5WQUw7CisJCX0KKworCQkqKGJ1ZjMyKyspID0gY3B1 X3RvX2xlMzIodmFsKTsKKwl9CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGludCBmX211ZF9w aW5zX3JlYWRyZWcoc3RydWN0IGZfbXVkX2NlbGwgKmNlbGwsIHVuc2lnbmVkIGludCByZWduciwK KwkJCSAgICAgIHZvaWQgKmJ1Ziwgc2l6ZV90ICpsZW4sIHU4IGNvbXByZXNzaW9uKQoreworCXN0 cnVjdCBmX211ZF9waW5zX2NlbGwgKnBjZWxsID0gY2VsbF90b19wY2VsbChjZWxsKTsKKwlzaXpl X3QgY291bnQgPSAqbGVuIC8gc2l6ZW9mKHUzMik7CisJX19sZTMyICpidWYzMiA9IGJ1ZjsKKwor CWZtZGVidWcoIiVzKHJlZ25yPTB4JTAyeCwgbGVuPSV6dSlcbiIsIF9fZnVuY19fLCByZWduciwg Kmxlbik7CisKKwlpZiAocmVnbnIgPj0gTVVEX1BJTkNUUkxfUkVHX1BJTl9CQVNFKQorCQlyZXR1 cm4gZl9tdWRfcGluc19yZWFkX2dwaW8ocGNlbGwsIHJlZ25yLCBidWYsICpsZW4pOworCisJaWYg KHJlZ25yID49IE1VRF9QSU5DVFJMX1JFR19JUlFfU1RBVFVTICYmCisJICAgIHJlZ25yIDw9IE1V RF9QSU5DVFJMX1JFR19JUlFfU1RBVFVTX0VORCkgeworCQl1bnNpZ25lZCBpbnQgbnJlZ3MgPSBE SVZfUk9VTkRfVVAocGNlbGwtPmNvdW50LCBzaXplb2YodTMyKSk7CisJCXVuc2lnbmVkIGludCBv ZmZzZXQgPSByZWduciAtIE1VRF9QSU5DVFJMX1JFR19JUlFfU1RBVFVTOworCQl1bnNpZ25lZCBp bnQgaSwgZW5kID0gbWluX3QodW5zaWduZWQgaW50LCBjb3VudCwgbnJlZ3MpOworCQl1MzIgaXJx dmFsc1tNVURfUElOQ1RSTF9NQVhfTlVNX1BJTlMgLyBzaXplb2YodTMyKV07CisKKwkJaWYgKGNv dW50ID4gKG5yZWdzIC0gb2Zmc2V0KSkKKwkJCXJldHVybiAtRUlOVkFMOworCisJCWJpdG1hcF90 b19hcnIzMihpcnF2YWxzLCBwY2VsbC0+aXJxX3N0YXR1cywgcGNlbGwtPmNvdW50KTsKKworCQlm bWRlYnVnKCIgICAgaXJxX3N0YXR1cz0lKnBiICBpcnF2YWxzPSUqcGhcbiIsIHBjZWxsLT5jb3Vu dCwKKwkJCXBjZWxsLT5pcnFfc3RhdHVzLCBucmVncywgaXJxdmFscyk7CisKKwkJZm9yIChpID0g b2Zmc2V0OyBpIDwgZW5kOyBpKyspCisJCQkqYnVmMzIrKyA9IGNwdV90b19sZTMyKGlycXZhbHNb aV0pOworCisJCXJldHVybiAwOworCX0KKworCWlmIChyZWduciA9PSBNVURfUElOQ1RSTF9SRUdf TlVNX1BJTlMgJiYgY291bnQgPT0gMSkgeworCQkqYnVmMzIgPSBjcHVfdG9fbGUzMihwY2VsbC0+ Y291bnQpOworCQlyZXR1cm4gMDsKKwl9CisKKwlmbWRlYnVnKCIlczogdW5rbm93biByZWdpc3Rl ciAweCV4XG4iLCBfX2Z1bmNfXywgcmVnbnIpOworCisJcmV0dXJuIC1FSU5WQUw7Cit9CisKK3N0 YXRpYyB2b2lkIGZfbXVkX3BpbnNfZGlzYWJsZShzdHJ1Y3QgZl9tdWRfY2VsbCAqY2VsbCkKK3sK KwlzdHJ1Y3QgZl9tdWRfcGluc19jZWxsICpwY2VsbCA9IGNlbGxfdG9fcGNlbGwoY2VsbCk7CisK KwlmX211ZF9waW5zX2dwaW9faXJxX2ZyZWVfYWxsKHBjZWxsKTsKKwkvKgorCSAqIEZJWE1FOiBG cmVlIHJlcXVlc3RlZCBncGlvcyBhcyB3ZWxsPworCSAqICAgICAgICBPciBzaG91bGQgdGhleSBz dXJ2aXZlIG9uIHVucGx1ZyBvbiBhIHBvd2VyZWQgYm9hcmQ/CisJICovCit9CisKK3N0YXRpYyB2 b2lkIGZfbXVkX3BpbnNfbG9va3VwX2RldmljZV9yZWxlYXNlKHN0cnVjdCBkZXZpY2UgKmRldikK K3sKKwlzdHJ1Y3QgZl9tdWRfcGluc19sb29rdXBfZGV2aWNlICpsZGV2ID0KKwkJCQljb250YWlu ZXJfb2YoZGV2LCBzdHJ1Y3QgZl9tdWRfcGluc19sb29rdXBfZGV2aWNlLCBkZXYpOworCisJZm1k ZWJ1ZygiJXM6IGxkZXY9JXB4XG4iLCBfX2Z1bmNfXywgbGRldik7CisKKwlpZiAobGRldi0+bG9v a3VwKSB7CisJCXN0cnVjdCBncGlvZF9sb29rdXAgKnA7CisKKwkJaWYgKGxkZXYtPmxvb2t1cC0+ ZGV2X2lkKQorCQkJZ3Bpb2RfcmVtb3ZlX2xvb2t1cF90YWJsZShsZGV2LT5sb29rdXApOworCisJ CWZvciAocCA9ICZsZGV2LT5sb29rdXAtPnRhYmxlWzBdOyBwLT5jaGlwX2xhYmVsOyBwKyspCisJ CQlrZnJlZShwLT5jaGlwX2xhYmVsKTsKKwkJa2ZyZWUobGRldi0+bG9va3VwKTsKKwl9CisKKwlp ZiAobGRldi0+bmFtZXMpIHsKKwkJdW5zaWduZWQgaW50IGk7CisKKwkJZm9yIChpID0gMDsgaSA8 IGxkZXYtPmNvdW50OyBpKyspCisJCQlrZnJlZShsZGV2LT5uYW1lc1tpXSk7CisJCWtmcmVlKGxk ZXYtPm5hbWVzKTsKKwl9CisKKwlpZGFfZnJlZSgmZl9tdWRfcGluc19pZGEsIGxkZXYtPmlkKTsK KwlrZnJlZShsZGV2KTsKK30KKworc3RhdGljIGludCBmX211ZF9waW5zX2xvb3VwX2RldmljZV9j cmVhdGUoc3RydWN0IGZfbXVkX3BpbnNfY2VsbCAqcGNlbGwpCit7CisJc3RydWN0IGZfbXVkX3Bp bnNfbG9va3VwX2RldmljZSAqbGRldjsKKwlzdHJ1Y3QgZl9tdWRfcGluc19jZWxsX2l0ZW0gKmZp dGVtOworCXVuc2lnbmVkIGludCBtYXhfaW5kZXggPSAwOworCWludCByZXQ7CisKKwlmbWRlYnVn KCIlczogJXB4XG4iLCBfX2Z1bmNfXywgcGNlbGwpOworCisJbGRldiA9IGt6YWxsb2Moc2l6ZW9m KCpsZGV2KSwgR0ZQX0tFUk5FTCk7CisJaWYgKCFsZGV2KQorCQlyZXR1cm4gLUVOT01FTTsKKwor CWZtZGVidWcoIiVzOiBsZGV2PSVweFxuIiwgX19mdW5jX18sIGxkZXYpOworCisJbGRldi0+aWQg PSBpZGFfYWxsb2MoJmZfbXVkX3BpbnNfaWRhLCBHRlBfS0VSTkVMKTsKKwlpZiAobGRldi0+aWQg PCAwKSB7CisJCWtmcmVlKGxkZXYpOworCQlyZXR1cm4gbGRldi0+aWQ7CisJfQorCisJbGRldi0+ Y2VsbCA9ICZwY2VsbC0+Y2VsbDsKKwlsZGV2LT5kZXYucmVsZWFzZSA9IGZfbXVkX3BpbnNfbG9v a3VwX2RldmljZV9yZWxlYXNlOworCWRldl9zZXRfbmFtZSgmbGRldi0+ZGV2LCAiZl9tdWRfcGlu cy0lZCIsIGxkZXYtPmlkKTsKKworCXJldCA9IGRldmljZV9yZWdpc3RlcigmbGRldi0+ZGV2KTsK KwlpZiAocmV0KSB7CisJCXB1dF9kZXZpY2UoJmxkZXYtPmRldik7CisJCXJldHVybiByZXQ7CisJ fQorCisJbXV0ZXhfbG9jaygmcGNlbGwtPmxvY2spOworCisJbGlzdF9mb3JfZWFjaF9lbnRyeShm aXRlbSwgJnBjZWxsLT5pdGVtcywgbm9kZSkgeworCQltYXhfaW5kZXggPSBtYXgobWF4X2luZGV4 LCBmaXRlbS0+aW5kZXgpOworCQlsZGV2LT5jb3VudCsrOworCX0KKworCWlmICghbGRldi0+Y291 bnQpIHsKKwkJcmV0ID0gLUVOT0VOVDsKKwkJZ290byBvdXRfdW5sb2NrOworCX0KKworCWlmIChs ZGV2LT5jb3VudCAhPSBtYXhfaW5kZXggKyAxKSB7CisJCXByX2VycigiUGluIGluZGljZXMgYXJl IG5vdCBjb250aW51b3VzXG4iKTsKKwkJcmV0ID0gLUVJTlZBTDsKKwkJZ290byBvdXRfdW5sb2Nr OworCX0KKworCWxkZXYtPm5hbWVzID0ga2NhbGxvYyhsZGV2LT5jb3VudCwgc2l6ZW9mKCpsZGV2 LT5uYW1lcyksIEdGUF9LRVJORUwpOworCWxkZXYtPmxvb2t1cCA9IGt6YWxsb2Moc3RydWN0X3Np emUobGRldi0+bG9va3VwLCB0YWJsZSwgbGRldi0+Y291bnQgKyAxKSwKKwkJCSAgICAgICBHRlBf S0VSTkVMKTsKKwlpZiAoIWxkZXYtPmxvb2t1cCB8fCAhbGRldi0+bmFtZXMpIHsKKwkJcmV0ID0g LUVOT01FTTsKKwkJZ290byBvdXRfdW5sb2NrOworCX0KKworCXJldCA9IDA7CisJbGlzdF9mb3Jf ZWFjaF9lbnRyeShmaXRlbSwgJnBjZWxsLT5pdGVtcywgbm9kZSkgeworCQlzdHJ1Y3QgZ3Bpb2Rf bG9va3VwICplbnRyeSA9ICZsZGV2LT5sb29rdXAtPnRhYmxlW2ZpdGVtLT5pbmRleF07CisKKwkJ bXV0ZXhfbG9jaygmZml0ZW0tPmxvY2spOworCisJCWlmICghZml0ZW0tPm5hbWUpIHsKKwkJCXBy X2VycigiTWlzc2luZyBuYW1lIGZvciBwaW4gJXVcbiIsIGZpdGVtLT5pbmRleCk7CisJCQlyZXQg PSAtRUlOVkFMOworCQkJZ290byBvdXRfdW5sb2NrX3BpbjsKKwkJfQorCisJCWxkZXYtPm5hbWVz W2ZpdGVtLT5pbmRleF0gPSBrc3RyZHVwKGZpdGVtLT5uYW1lLCBHRlBfS0VSTkVMKTsKKwkJaWYg KCFsZGV2LT5uYW1lc1tmaXRlbS0+aW5kZXhdKSB7CisJCQlyZXQgPSAtRU5PTUVNOworCQkJZ290 byBvdXRfdW5sb2NrX3BpbjsKKwkJfQorCisJCS8qIFNraXAgYWRkaW5nIHRvIGxvb2t1cCBpZiB0 aGUgcGluIGhhcyBubyBncGlvIGZ1bmN0aW9uICovCisJCWlmICghZml0ZW0tPmNoaXApCisJCQln b3RvIG91dF91bmxvY2tfcGluOworCisJCWVudHJ5LT5pZHggPSBmaXRlbS0+aW5kZXg7CisJCWVu dHJ5LT5jaGlwX2h3bnVtID0gZml0ZW0tPm9mZnNldDsKKworCQllbnRyeS0+Y2hpcF9sYWJlbCA9 IGtzdHJkdXAoZml0ZW0tPmNoaXAsIEdGUF9LRVJORUwpOworCQlpZiAoIWVudHJ5LT5jaGlwX2xh YmVsKSB7CisJCQlyZXQgPSAtRU5PTUVNOworCQkJZ290byBvdXRfdW5sb2NrX3BpbjsKKwkJfQor CisJCWZtZGVidWcoIiAgICAldTogY2hpcD0lcyBod251bT0ldSBuYW1lPSVzXG4iLCBlbnRyeS0+ aWR4LAorCQkJZW50cnktPmNoaXBfbGFiZWwsIGVudHJ5LT5jaGlwX2h3bnVtLCBsZGV2LT5uYW1l c1tmaXRlbS0+aW5kZXhdKTsKK291dF91bmxvY2tfcGluOgorCQltdXRleF91bmxvY2soJmZpdGVt LT5sb2NrKTsKKwkJaWYgKHJldCkKKwkJCWdvdG8gb3V0X3VubG9jazsKKwl9CisKKwlsZGV2LT5s b29rdXAtPmRldl9pZCA9IGRldl9uYW1lKCZsZGV2LT5kZXYpOworCWdwaW9kX2FkZF9sb29rdXBf dGFibGUobGRldi0+bG9va3VwKTsKKworCXBjZWxsLT5sZGV2ID0gbGRldjsKKwlwY2VsbC0+Y291 bnQgPSBsZGV2LT5jb3VudDsKKworb3V0X3VubG9jazoKKwltdXRleF91bmxvY2soJnBjZWxsLT5s b2NrKTsKKworCWlmIChyZXQpCisJCWRldmljZV91bnJlZ2lzdGVyKCZsZGV2LT5kZXYpOworCisJ cmV0dXJuIHJldDsKK30KKworc3RhdGljIHZvaWQgZl9tdWRfcGluc19sb29rdXBfZGV2aWNlX2Rl c3Ryb3koc3RydWN0IGZfbXVkX3BpbnNfY2VsbCAqcGNlbGwpCit7CisJaWYgKHBjZWxsLT5sZGV2 KSB7CisJCWRldmljZV91bnJlZ2lzdGVyKCZwY2VsbC0+bGRldi0+ZGV2KTsKKwkJcGNlbGwtPmxk ZXYgPSBOVUxMOworCX0KK30KKworc3RhdGljIGludCBmX211ZF9waW5zX2JpbmQoc3RydWN0IGZf bXVkX2NlbGwgKmNlbGwpCit7CisJc3RydWN0IGZfbXVkX3BpbnNfY2VsbCAqcGNlbGwgPSBjZWxs X3RvX3BjZWxsKGNlbGwpOworCXVuc2lnbmVkIGludCBpOworCWludCByZXQ7CisKKwlmbWRlYnVn KCIlczogJXB4XG4iLCBfX2Z1bmNfXywgcGNlbGwpOworCisJcmV0ID0gZl9tdWRfcGluc19sb291 cF9kZXZpY2VfY3JlYXRlKHBjZWxsKTsKKwlpZiAocmV0KQorCQlyZXR1cm4gcmV0OworCisJc3Bp bl9sb2NrX2luaXQoJnBjZWxsLT5pcnFfc3RhdHVzX2xvY2spOworCXBjZWxsLT5pcnFfc3RhdHVz ID0gYml0bWFwX3phbGxvYyhwY2VsbC0+Y291bnQsIEdGUF9LRVJORUwpOworCWlmICghcGNlbGwt PmlycV9zdGF0dXMpIHsKKwkJcmV0ID0gLUVOT01FTTsKKwkJZ290byBlcnJvcl9mcmVlOworCX0K KworCXBjZWxsLT5waW5zID0ga2NhbGxvYyhwY2VsbC0+Y291bnQsIHNpemVvZigqcGNlbGwtPnBp bnMpLCBHRlBfS0VSTkVMKTsKKwlpZiAoIXBjZWxsLT5waW5zKSB7CisJCXJldCA9IC1FTk9NRU07 CisJCWdvdG8gZXJyb3JfZnJlZTsKKwl9CisKKwlmb3IgKGkgPSAwOyBpIDwgcGNlbGwtPmNvdW50 OyBpKyspIHsKKwkJc3RydWN0IGZfbXVkX3BpbnNfcGluICpwaW4gPSAmcGNlbGwtPnBpbnNbaV07 CisKKwkJcGluLT5wYXJlbnQgPSBwY2VsbDsKKwkJcGluLT5pbmRleCA9IGk7CisJCXBpbi0+ZGVi b3VuY2UgPSBERUJPVU5DRV9OT1RfU0VUOworCX0KKworCXJldHVybiAwOworCitlcnJvcl9mcmVl OgorCWtmcmVlKHBjZWxsLT5waW5zKTsKKwlmX211ZF9waW5zX2xvb2t1cF9kZXZpY2VfZGVzdHJv eShwY2VsbCk7CisKKwlyZXR1cm4gcmV0OworfQorCitzdGF0aWMgdm9pZCBmX211ZF9waW5zX3Vu YmluZChzdHJ1Y3QgZl9tdWRfY2VsbCAqY2VsbCkKK3sKKwlzdHJ1Y3QgZl9tdWRfcGluc19jZWxs ICpwY2VsbCA9IGNlbGxfdG9fcGNlbGwoY2VsbCk7CisJdW5zaWduZWQgaW50IGk7CisKKwlmbWRl YnVnKCIlczpcbiIsIF9fZnVuY19fKTsKKworCWlmIChwY2VsbC0+cGlucykgeworCQlmb3IgKGkg PSAwOyBpIDwgcGNlbGwtPmNvdW50OyBpKyspIHsKKwkJCWlmIChwY2VsbC0+cGluc1tpXS5ncGlv KSB7CisJCQkJZm1kZWJ1ZygiICAgIGdwaW9kX3B1dDogJXVcbiIsIGkpOworCQkJCWdwaW9kX3B1 dChwY2VsbC0+cGluc1tpXS5ncGlvKTsKKwkJCX0KKwkJfQorCisJCWtmcmVlKHBjZWxsLT5waW5z KTsKKwl9CisKKwliaXRtYXBfZnJlZShwY2VsbC0+aXJxX3N0YXR1cyk7CisKKwlmX211ZF9waW5z X2xvb2t1cF9kZXZpY2VfZGVzdHJveShwY2VsbCk7Cit9CisKK3N0YXRpYyB2b2lkIGZfbXVkX3Bp bnNfY2VsbF9pdGVtX2l0ZW1fcmVsZWFzZShzdHJ1Y3QgY29uZmlnX2l0ZW0gKml0ZW0pCit7CisJ c3RydWN0IGZfbXVkX3BpbnNfY2VsbF9pdGVtICpmaXRlbSA9IGNpX3RvX2ZfbXVkX3BpbnNfY2Vs bF9pdGVtKGl0ZW0pOworCisJZm1kZWJ1ZygiJXM6IGZpdGVtPSVweFxuIiwgX19mdW5jX18sIGZp dGVtKTsKKworCWtmcmVlKGZpdGVtLT5uYW1lKTsKKwlrZnJlZShmaXRlbS0+Y2hpcCk7CisJa2Zy ZWUoZml0ZW0pOworfQorCitGX01VRF9PUFRfU1RSKGZfbXVkX3BpbnNfY2VsbF9pdGVtLCBuYW1l KTsKK0ZfTVVEX09QVF9TVFIoZl9tdWRfcGluc19jZWxsX2l0ZW0sIGNoaXApOworRl9NVURfT1BU X0lOVChmX211ZF9waW5zX2NlbGxfaXRlbSwgb2Zmc2V0LCAwLCBJTlRfTUFYKTsKKworc3RhdGlj IHN0cnVjdCBjb25maWdmc19hdHRyaWJ1dGUgKmZfbXVkX3BpbnNfY2VsbF9pdGVtX2F0dHJzW10g PSB7CisJJmZfbXVkX3BpbnNfY2VsbF9pdGVtX2F0dHJfbmFtZSwKKwkmZl9tdWRfcGluc19jZWxs X2l0ZW1fYXR0cl9jaGlwLAorCSZmX211ZF9waW5zX2NlbGxfaXRlbV9hdHRyX29mZnNldCwKKwlO VUxMLAorfTsKKworc3RhdGljIHN0cnVjdCBjb25maWdmc19pdGVtX29wZXJhdGlvbnMgZl9tdWRf cGluc19jZWxsX2l0ZW1faXRlbV9vcHMgPSB7CisJLnJlbGVhc2UgPSBmX211ZF9waW5zX2NlbGxf aXRlbV9pdGVtX3JlbGVhc2UsCit9OworCitzdGF0aWMgY29uc3Qgc3RydWN0IGNvbmZpZ19pdGVt X3R5cGUgZl9tdWRfcGluc19jZWxsX2l0ZW1fZnVuY190eXBlID0geworCS5jdF9pdGVtX29wcwk9 ICZmX211ZF9waW5zX2NlbGxfaXRlbV9pdGVtX29wcywKKwkuY3RfYXR0cnMJPSBmX211ZF9waW5z X2NlbGxfaXRlbV9hdHRycywKKwkuY3Rfb3duZXIJPSBUSElTX01PRFVMRSwKK307CisKK3N0YXRp YyBzdHJ1Y3QgY29uZmlnX2dyb3VwICpmX211ZF9waW5zX21ha2VfZ3JvdXAoc3RydWN0IGNvbmZp Z19ncm91cCAqZ3JvdXAsCisJCQkJCQkgIGNvbnN0IGNoYXIgKm5hbWUpCit7CisJc3RydWN0IGZf bXVkX3BpbnNfY2VsbCAqcGNlbGwgPSBjaV90b19mX211ZF9waW5zX2NlbGwoJmdyb3VwLT5jZ19p dGVtKTsKKwlzdHJ1Y3QgZl9tdWRfcGluc19jZWxsX2l0ZW0gKmZpdGVtOworCWNvbnN0IGNoYXIg KnByZWZpeCA9ICJwaW4uIjsKKwlzdHJ1Y3QgY29uZmlnX2dyb3VwICpncnA7CisJaW50IHJldCwg aW5kZXg7CisKKwlmbWRlYnVnKCIlczogbmFtZT0lc1xuIiwgX19mdW5jX18sIG5hbWUpOworCisJ bXV0ZXhfbG9jaygmcGNlbGwtPmxvY2spOworCWZtZGVidWcoIiVzOiBwY2VsbD0lcHggcGNlbGwt PnJlZmNudD0lZFxuIiwgX19mdW5jX18sIHBjZWxsLCBwY2VsbC0+cmVmY250KTsKKwlpZiAocGNl bGwtPnJlZmNudCkgeworCQlncnAgPSBFUlJfUFRSKC1FQlVTWSk7CisJCWdvdG8gb3V0X3VubG9j azsKKwl9CisKKwlpZiAoc3Ryc3RyKG5hbWUsIHByZWZpeCkgIT0gbmFtZSkgeworCQlwcl9lcnIo Ik1pc3NpbmcgcHJlZml4ICclcycgaW4gbmFtZTogJyVzJ1xuIiwgcHJlZml4LCBuYW1lKTsKKwkJ Z3JwID0gRVJSX1BUUigtRUlOVkFMKTsKKwkJZ290byBvdXRfdW5sb2NrOworCX0KKworCXJldCA9 IGtzdHJ0b2ludChuYW1lICsgc3RybGVuKHByZWZpeCksIDEwLCAmaW5kZXgpOworCWlmIChyZXQp IHsKKwkJcHJfZXJyKCJGYWlsZWQgdG8gcGFyc2UgaW5kZXggaW4gbmFtZTogJyVzJ1xuIiwgbmFt ZSk7CisJCWdycCA9IEVSUl9QVFIocmV0KTsKKwkJZ290byBvdXRfdW5sb2NrOworCX0KKworCWZp dGVtID0ga3phbGxvYyhzaXplb2YoKmZpdGVtKSwgR0ZQX0tFUk5FTCk7CisJZm1kZWJ1ZygiICAg IHBpbj0lcHhcbiIsIGZpdGVtKTsKKwlpZiAoIWZpdGVtKSB7CisJCWdycCA9IEVSUl9QVFIoLUVO T01FTSk7CisJCWdvdG8gb3V0X3VubG9jazsKKwl9CisKKwlmaXRlbS0+aW5kZXggPSBpbmRleDsK KwlncnAgPSAmZml0ZW0tPmdyb3VwOworCisJY29uZmlnX2dyb3VwX2luaXRfdHlwZV9uYW1lKGdy cCwgIiIsICZmX211ZF9waW5zX2NlbGxfaXRlbV9mdW5jX3R5cGUpOworCisJbGlzdF9hZGQoJmZp dGVtLT5ub2RlLCAmcGNlbGwtPml0ZW1zKTsKK291dF91bmxvY2s6CisJbXV0ZXhfdW5sb2NrKCZw Y2VsbC0+bG9jayk7CisKKwlyZXR1cm4gZ3JwOworfQorCitzdGF0aWMgdm9pZCBmX211ZF9waW5z X2Ryb3BfaXRlbShzdHJ1Y3QgY29uZmlnX2dyb3VwICpncm91cCwgc3RydWN0IGNvbmZpZ19pdGVt ICppdGVtKQoreworCXN0cnVjdCBmX211ZF9waW5zX2NlbGwgKnBjZWxsID0gY2lfdG9fZl9tdWRf cGluc19jZWxsKCZncm91cC0+Y2dfaXRlbSk7CisJc3RydWN0IGZfbXVkX3BpbnNfY2VsbF9pdGVt ICpmaXRlbSA9IGNpX3RvX2ZfbXVkX3BpbnNfY2VsbF9pdGVtKGl0ZW0pOworCisJZm1kZWJ1Zygi JXM6IHBjZWxsPSVweCBmaXRlbT0lcHhcbiIsIF9fZnVuY19fLCBwY2VsbCwgZml0ZW0pOworCisJ bXV0ZXhfbG9jaygmcGNlbGwtPmxvY2spOworCWxpc3RfZGVsKCZmaXRlbS0+bm9kZSk7CisJbXV0 ZXhfdW5sb2NrKCZwY2VsbC0+bG9jayk7CisKKwljb25maWdfaXRlbV9wdXQoaXRlbSk7Cit9CisK K3N0YXRpYyBzdHJ1Y3QgY29uZmlnZnNfZ3JvdXBfb3BlcmF0aW9ucyBmX211ZF9waW5zX2dyb3Vw X29wcyA9IHsKKwkubWFrZV9ncm91cAk9IGZfbXVkX3BpbnNfbWFrZV9ncm91cCwKKwkuZHJvcF9p dGVtCT0gZl9tdWRfcGluc19kcm9wX2l0ZW0sCit9OworCitzdGF0aWMgc3RydWN0IGNvbmZpZ2Zz X2l0ZW1fb3BlcmF0aW9ucyBmX211ZF9waW5zX2l0ZW1fb3BzID0geworCS5yZWxlYXNlID0gZl9t dWRfY2VsbF9pdGVtX3JlbGVhc2UsCit9OworCitzdGF0aWMgY29uc3Qgc3RydWN0IGNvbmZpZ19p dGVtX3R5cGUgZl9tdWRfcGluc19mdW5jX3R5cGUgPSB7CisJLmN0X2l0ZW1fb3BzCT0gJmZfbXVk X3BpbnNfaXRlbV9vcHMsCisJLmN0X2dyb3VwX29wcwk9ICZmX211ZF9waW5zX2dyb3VwX29wcywK KwkuY3Rfb3duZXIJPSBUSElTX01PRFVMRSwKK307CisKK3N0YXRpYyB2b2lkIGZfbXVkX3BpbnNf ZnJlZShzdHJ1Y3QgZl9tdWRfY2VsbCAqY2VsbCkKK3sKKwlzdHJ1Y3QgZl9tdWRfcGluc19jZWxs ICpwY2VsbCA9IGNvbnRhaW5lcl9vZihjZWxsLCBzdHJ1Y3QgZl9tdWRfcGluc19jZWxsLCBjZWxs KTsKKworCWZtZGVidWcoIiVzOiBwY2VsbD0lcHhcbiIsIF9fZnVuY19fLCBwY2VsbCk7CisKKwlt dXRleF9kZXN0cm95KCZwY2VsbC0+bG9jayk7CisJa2ZyZWUocGNlbGwpOworfQorCitzdGF0aWMg c3RydWN0IGZfbXVkX2NlbGwgKmZfbXVkX3BpbnNfYWxsb2Modm9pZCkKK3sKKwlzdHJ1Y3QgZl9t dWRfcGluc19jZWxsICpwY2VsbDsKKworCXBjZWxsID0ga3phbGxvYyhzaXplb2YoKnBjZWxsKSwg R0ZQX0tFUk5FTCk7CisJZm1kZWJ1ZygiJXM6IHBjZWxsPSVweFxuIiwgX19mdW5jX18sIHBjZWxs KTsKKwlpZiAoIXBjZWxsKQorCQlyZXR1cm4gRVJSX1BUUigtRU5PTUVNKTsKKworCW11dGV4X2lu aXQoJnBjZWxsLT5sb2NrKTsKKwlJTklUX0xJU1RfSEVBRCgmcGNlbGwtPml0ZW1zKTsKKwljb25m aWdfZ3JvdXBfaW5pdF90eXBlX25hbWUoJnBjZWxsLT5jZWxsLmdyb3VwLCAiIiwgJmZfbXVkX3Bp bnNfZnVuY190eXBlKTsKKworCWZtZGVidWcoIiVzOiBjZWxsPSVweFxuIiwgX19mdW5jX18sICZw Y2VsbC0+Y2VsbCk7CisKKwlyZXR1cm4gJnBjZWxsLT5jZWxsOworfQorCitzdGF0aWMgY29uc3Qg c3RydWN0IGZfbXVkX2NlbGxfb3BzIGZfbXVkX3BpbnNfb3BzID0geworCS5uYW1lID0gIm11ZC1w aW5zIiwKKwkub3duZXIgPSBUSElTX01PRFVMRSwKKworCS5pbnRlcnJ1cHRfaW50ZXJ2YWxfbXMg PSAxMDAsCisKKwkuYWxsb2MgPSBmX211ZF9waW5zX2FsbG9jLAorCS5mcmVlID0gZl9tdWRfcGlu c19mcmVlLAorCS5iaW5kID0gZl9tdWRfcGluc19iaW5kLAorCS51bmJpbmQgPSBmX211ZF9waW5z X3VuYmluZCwKKworCS5yZWd2YWxfYnl0ZXMgPSA0LAorCS5tYXhfdHJhbnNmZXJfc2l6ZSA9IDY0 LAorCisJLmRpc2FibGUgPSBmX211ZF9waW5zX2Rpc2FibGUsCisJLnJlYWRyZWcgPSBmX211ZF9w aW5zX3JlYWRyZWcsCisJLndyaXRlcmVnID0gZl9tdWRfcGluc193cml0ZXJlZywKK307CisKK0RF Q0xBUkVfRl9NVURfQ0VMTF9JTklUKGZfbXVkX3BpbnNfb3BzKTsKKworTU9EVUxFX0FVVEhPUigi Tm9yYWxmIFRyw7hubmVzIik7CitNT0RVTEVfTElDRU5TRSgiR1BMIik7Ci0tIAoyLjIzLjAKCl9f X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fCmRyaS1kZXZlbCBt YWlsaW5nIGxpc3QKZHJpLWRldmVsQGxpc3RzLmZyZWVkZXNrdG9wLm9yZwpodHRwczovL2xpc3Rz LmZyZWVkZXNrdG9wLm9yZy9tYWlsbWFuL2xpc3RpbmZvL2RyaS1kZXZlbAo=