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, URIBL_BLOCKED,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 45B5FC83003 for ; Wed, 29 Apr 2020 12:58:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 12AC5208FE for ; Wed, 29 Apr 2020 12:58:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726676AbgD2M6K (ORCPT ); Wed, 29 Apr 2020 08:58:10 -0400 Received: from asav21.altibox.net ([109.247.116.8]:58750 "EHLO asav21.altibox.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727053AbgD2M6K (ORCPT ); Wed, 29 Apr 2020 08:58:10 -0400 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 asav21.altibox.net (Postfix) with ESMTPSA id F23B680193; Wed, 29 Apr 2020 14:48:51 +0200 (CEST) From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= To: dri-devel@lists.freedesktop.org, linux-usb@vger.kernel.org Cc: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Subject: [PATCH 09/10] drm/gud: Add functionality for the USB gadget side Date: Wed, 29 Apr 2020 14:48:29 +0200 Message-Id: <20200429124830.27475-10-noralf@tronnes.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20200429124830.27475-1-noralf@tronnes.org> References: <20200429124830.27475-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=AvXAIt1P c=1 sm=1 tr=0 a=OYZzhG0JTxDrWp/F2OJbnw==:117 a=OYZzhG0JTxDrWp/F2OJbnw==:17 a=IkcTkHD0fZMA:10 a=M51BFTxLslgA:10 a=SJz97ENfAAAA:8 a=JEiCMFymvXJ_tcOM5XYA:9 a=adth_mbAzEm_eDmq:21 a=vMyTFNr94S6AnSfT: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 Since the USB gadget/device has to reach into the DRM internals, part of the code is placed in the DRM subsystem as a separate module. All calls into this module runs in process context and are serialized, except one function that runs in interrupt context. Since both the gadget side and the DRM side can disable the gadget, special care has been taken to make that safe. Signed-off-by: Noralf Trønnes --- drivers/gpu/drm/gud/Kconfig | 6 + drivers/gpu/drm/gud/Makefile | 1 + drivers/gpu/drm/gud/gud_drm_gadget.c | 1169 ++++++++++++++++++++++++++ include/drm/gud_drm.h | 13 + 4 files changed, 1189 insertions(+) create mode 100644 drivers/gpu/drm/gud/gud_drm_gadget.c diff --git a/drivers/gpu/drm/gud/Kconfig b/drivers/gpu/drm/gud/Kconfig index 203d4490f1c7..99bfbfbf9023 100644 --- a/drivers/gpu/drm/gud/Kconfig +++ b/drivers/gpu/drm/gud/Kconfig @@ -12,3 +12,9 @@ config DRM_GUD adapters. If M is selected the module will be called gud_drm. + +config DRM_GUD_GADGET + tristate + depends on DRM + select LZ4_DECOMPRESS + select BACKLIGHT_CLASS_DEVICE diff --git a/drivers/gpu/drm/gud/Makefile b/drivers/gpu/drm/gud/Makefile index 73ed7ef3da94..fb5cfbd93d0f 100644 --- a/drivers/gpu/drm/gud/Makefile +++ b/drivers/gpu/drm/gud/Makefile @@ -2,3 +2,4 @@ gud_drm-objs := gud_drm_drv.o gud_drm_pipe.o gud_drm_connector.o obj-$(CONFIG_DRM_GUD) += gud_drm.o +obj-$(CONFIG_DRM_GUD_GADGET) += gud_drm_gadget.o diff --git a/drivers/gpu/drm/gud/gud_drm_gadget.c b/drivers/gpu/drm/gud/gud_drm_gadget.c new file mode 100644 index 000000000000..a9c916abec85 --- /dev/null +++ b/drivers/gpu/drm/gud/gud_drm_gadget.c @@ -0,0 +1,1169 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2020 Noralf Trønnes + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gud_drm_internal.h" + +/* + * Concurrency: + * Calls into this module from f_gud_drm are serialized and run in process + * context except gud_drm_gadget_ctrl_get() which is run in interrupt context. + * + * Termination: + * A DRM client can not release itself, only the DRM driver which resources the + * client uses can do that. + * This means that there are 2 paths to stop the gadget function: + * - Unregistering the DRM driver (module unload) + * - Disabling the USB gadget (configfs unbind) + * + * A use counter protects the gadget should the client go away. A kref is used + * to control the release of the gud_drm_gadget structure shared by the 2 actors. + * + * Backlight: + * If there's a backlight device it's attached to the first connector. + */ + +struct gud_drm_gadget_connector { + struct drm_connector *connector; + + const struct gud_drm_property *properties; + unsigned int num_properties; + const char *tv_mode_enum_names; + unsigned int num_tv_mode_enum_names; + struct backlight_device *backlight; + + spinlock_t lock; /* Protects the following members: */ + enum drm_connector_status status; + unsigned int width_mm; + unsigned int height_mm; + struct gud_drm_display_mode *modes; + unsigned int num_modes; + void *edid; + size_t edid_len; + bool changed; +}; + +struct gud_drm_gadget { + struct kref refcount; + refcount_t usecnt; + struct drm_client_dev client; + struct backlight_device *backlight; + + const u32 *formats; + unsigned int format_count; + + const struct gud_drm_property *properties; + unsigned int num_properties; + + struct gud_drm_gadget_connector *connectors; + unsigned int connector_count; + + struct drm_rect set_buffer_rect; + u32 set_buffer_length; + u8 set_buffer_compression; + u32 set_buffer_compressed_length; + + struct drm_client_buffer *buffer; + struct drm_client_buffer *buffer_check; + u8 brightness; + bool check_ok; + + size_t max_buffer_size; + void *work_buf; +}; + +static int gud_drm_gadget_probe_connector(struct gud_drm_gadget_connector *gconn) +{ + struct drm_connector *connector = gconn->connector; + struct gud_drm_display_mode *modes = NULL; + struct drm_device *drm = connector->dev; + struct drm_display_mode *mode; + void *edid_data, *edid = NULL; + unsigned int num_modes = 0; + size_t edid_len = 0; + unsigned long flags; + unsigned int i = 0; + int ret = 0; + + mutex_lock(&drm->mode_config.mutex); + + connector->funcs->fill_modes(connector, + drm->mode_config.max_width, + drm->mode_config.max_height); + + list_for_each_entry(mode, &connector->modes, head) + num_modes++; + + if (!num_modes) + goto update; + + modes = kmalloc_array(num_modes, sizeof(*modes), GFP_KERNEL); + if (!modes) { + ret = -ENOMEM; + num_modes = 0; + goto update; + } + + list_for_each_entry(mode, &connector->modes, head) + gud_drm_from_display_mode(&modes[i++], mode); + + if (!connector->edid_blob_ptr) + goto update; + + edid_data = connector->edid_blob_ptr->data; + edid_len = connector->edid_blob_ptr->length; + if (!edid_data || !edid_len) { + edid_len = 0; + goto update; + } + + edid = kmemdup(edid_data, edid_len, GFP_KERNEL); + if (!edid) { + ret = -ENOMEM; + edid_len = 0; + } + +update: + spin_lock_irqsave(&gconn->lock, flags); + if (gconn->status != connector->status || gconn->num_modes != num_modes || + gconn->edid_len != edid_len || + (gconn->modes && modes && memcmp(gconn->modes, modes, num_modes * sizeof(*modes))) || + (gconn->edid && edid && memcmp(gconn->edid, edid, edid_len))) + gconn->changed = true; + swap(gconn->modes, modes); + gconn->num_modes = num_modes; + swap(gconn->edid, edid); + gconn->edid_len = edid_len; + gconn->width_mm = connector->display_info.width_mm; + gconn->height_mm = connector->display_info.height_mm; + gconn->status = connector->status; + spin_unlock_irqrestore(&gconn->lock, flags); + + mutex_unlock(&drm->mode_config.mutex); + + kfree(edid); + kfree(modes); + + return ret; +} + +static void gud_drm_gadget_probe_connectors(struct gud_drm_gadget *gdg) +{ + unsigned int i; + + for (i = 0; i < gdg->connector_count; i++) + gud_drm_gadget_probe_connector(&gdg->connectors[i]); +} + +static bool gud_drm_gadget_check_buffer(struct gud_drm_gadget *gdg, + struct drm_client_buffer *buffer, + struct drm_display_mode *mode, + u32 format) +{ + struct drm_framebuffer *fb; + + if (!buffer) + return false; + + fb = buffer->fb; + + return fb->format->format == format && + fb->width == mode->hdisplay && fb->height == mode->vdisplay; +} + +static bool gud_drm_gadget_set_connector_property(struct drm_client_dev *client, + struct drm_connector *connector, + u16 prop, u64 val, int *ret) +{ + struct drm_mode_config *config = &connector->dev->mode_config; + struct drm_property *property; + + switch (prop) { + case GUD_DRM_PROPERTY_TV_SELECT_SUBCONNECTOR: + property = config->tv_select_subconnector_property; + break; + case GUD_DRM_PROPERTY_TV_LEFT_MARGIN: + property = config->tv_left_margin_property; + break; + case GUD_DRM_PROPERTY_TV_RIGHT_MARGIN: + property = config->tv_right_margin_property; + break; + case GUD_DRM_PROPERTY_TV_TOP_MARGIN: + property = config->tv_top_margin_property; + break; + case GUD_DRM_PROPERTY_TV_BOTTOM_MARGIN: + property = config->tv_bottom_margin_property; + break; + case GUD_DRM_PROPERTY_TV_MODE: + property = config->tv_mode_property; + break; + case GUD_DRM_PROPERTY_TV_BRIGHTNESS: + property = config->tv_brightness_property; + break; + case GUD_DRM_PROPERTY_TV_CONTRAST: + property = config->tv_contrast_property; + break; + case GUD_DRM_PROPERTY_TV_FLICKER_REDUCTION: + property = config->tv_flicker_reduction_property; + break; + case GUD_DRM_PROPERTY_TV_OVERSCAN: + property = config->tv_overscan_property; + break; + case GUD_DRM_PROPERTY_TV_SATURATION: + property = config->tv_saturation_property; + break; + case GUD_DRM_PROPERTY_TV_HUE: + property = config->tv_hue_property; + break; + default: + return false; + } + + *ret = drm_client_modeset_set_property(client, &connector->base, property, val); + + return true; +} + +static int gud_drm_gadget_check(struct gud_drm_gadget *gdg, struct gud_drm_req_set_state *req, + size_t size) +{ + struct drm_client_dev *client = &gdg->client; + u32 format = le32_to_cpu(req->format); + struct drm_client_buffer *buffer; + struct drm_connector *connector; + struct drm_display_mode mode; + unsigned int i; + void *vaddr; + int ret; + + if (size < sizeof(struct gud_drm_req_set_state)) + return -EINVAL; + + if (size != struct_size(req, properties, req->num_properties)) + return -EINVAL; + + memset(&mode, 0, sizeof(mode)); + gud_drm_to_display_mode(&mode, &req->mode); + + gdg->check_ok = false; + + if (!mode.hdisplay || !format) + return -EINVAL; + + if (req->connector >= gdg->connector_count) + return -EINVAL; + + connector = gdg->connectors[req->connector].connector; + + if (gdg->buffer_check) { + drm_client_framebuffer_delete(gdg->buffer_check); + gdg->buffer_check = NULL; + } + + if (!gud_drm_gadget_check_buffer(gdg, gdg->buffer, &mode, format)) { + buffer = drm_client_framebuffer_create(client, mode.hdisplay, mode.vdisplay, + format); + if (IS_ERR(buffer)) + return PTR_ERR(buffer); + + vaddr = drm_client_buffer_vmap(buffer); + if (IS_ERR(vaddr)) { + drm_client_framebuffer_delete(buffer); + return PTR_ERR(vaddr); + } + + gdg->buffer_check = buffer; + } else { + buffer = gdg->buffer; + } + + ret = drm_client_modeset_set(client, connector, &mode, buffer->fb); + if (ret) + return ret; + + for (i = 0; i < req->num_properties; i++) { + u16 prop = le16_to_cpu(req->properties[i].prop); + u64 val = le64_to_cpu(req->properties[i].val); + + if (gud_drm_gadget_set_connector_property(client, connector, prop, val, &ret)) { + if (ret) + return ret; + continue; + } + + switch (prop) { + case GUD_DRM_PROPERTY_BACKLIGHT_BRIGHTNESS: + if (val > 100) + return -EINVAL; + gdg->brightness = val; + break; + case GUD_DRM_PROPERTY_ROTATION: + ret = drm_client_modeset_set_rotation(client, val); + break; + default: + pr_err("%s: Unknown property: %u\n", __func__, prop); + continue; + } + + if (ret) + return ret; + } + + ret = drm_client_modeset_check(&gdg->client); + if (ret) + return ret; + + gdg->check_ok = true; + + return 0; +} + +static int gud_drm_gadget_commit(struct gud_drm_gadget *gdg) +{ + int ret; + + if (!gdg->check_ok) + return -EINVAL; + + if (gdg->backlight) { + int val, max_brightness = gdg->backlight->props.max_brightness; + + val = DIV64_U64_ROUND_UP(gdg->brightness * max_brightness, 100); + ret = backlight_device_set_brightness(gdg->backlight, val); + if (ret) + return ret; + } + + ret = drm_client_modeset_commit(&gdg->client); + if (ret) + return ret; + + if (gdg->buffer_check) { + drm_client_framebuffer_delete(gdg->buffer); + gdg->buffer = gdg->buffer_check; + gdg->buffer_check = NULL; + } + + return 0; +} + +static size_t gud_drm_gadget_write_buffer_memcpy(struct drm_client_buffer *buffer, + const void *src, size_t len, + struct drm_rect *rect) +{ + unsigned int cpp = buffer->fb->format->cpp[0]; + size_t dst_pitch = buffer->fb->pitches[0]; + size_t src_pitch = drm_rect_width(rect) * cpp; + unsigned int y; + void *dst; + + /* Get the address, it's already mapped */ + dst = drm_client_buffer_vmap(buffer); + dst += rect->y1 * dst_pitch; + dst += rect->x1 * cpp; + + for (y = 0; y < drm_rect_height(rect) && len; y++) { + src_pitch = min(src_pitch, len); + memcpy(dst, src, src_pitch); + src += src_pitch; + dst += dst_pitch; + len -= src_pitch; + } + + return len; +} + +static bool gud_drm_gadget_check_rect(struct drm_client_buffer *buffer, struct drm_rect *rect) +{ + return buffer->fb && rect->x1 < rect->x2 && rect->y1 < rect->y2 && + rect->x2 <= buffer->fb->width && rect->y2 <= buffer->fb->height; +} + +int gud_drm_gadget_write_buffer(struct gud_drm_gadget *gdg, const void *buf, size_t len) +{ + struct drm_client_buffer *buffer = gdg->buffer ? gdg->buffer : gdg->buffer_check; + struct drm_rect *rect = &gdg->set_buffer_rect; + u8 compression = gdg->set_buffer_compression; + struct drm_framebuffer *fb; + size_t remain; + int ret; + + pr_debug("%s: len=%zu compression=0x%x\n", __func__, len, compression); + + if (WARN_ON_ONCE(!buffer)) + return -ENOMEM; + + if (!gud_drm_gadget_check_rect(buffer, rect)) { + pr_err("%s: Rectangle doesn't fit\n", __func__); + return -EINVAL; + } + + fb = buffer->fb; + + if (compression & GUD_DRM_COMPRESSION_LZ4) { + if (len != gdg->set_buffer_compressed_length) { + pr_err("%s: Buffer compressed len differs: %zu != %zu\n", + __func__, len, gdg->set_buffer_compressed_length); + return -EINVAL; + } + + ret = LZ4_decompress_safe(buf, gdg->work_buf, len, gdg->max_buffer_size); + if (ret < 0) { + pr_err("%s: Failed to decompress buffer\n", __func__); + return -EIO; + } + + buf = gdg->work_buf; + len = ret; + } + + if (len != gdg->set_buffer_length) { + pr_err("%s: Buffer len differs: %zu != %zu\n", + __func__, len, gdg->set_buffer_length); + return -EINVAL; + } + + if (len > (drm_rect_width(rect) * drm_rect_height(rect) * fb->format->cpp[0])) { + pr_err("%s: Buffer is too big for rectangle\n", __func__); + return -EINVAL; + } + + remain = gud_drm_gadget_write_buffer_memcpy(buffer, buf, len, rect); + if (remain) { + pr_err("%s: Failed to write buffer: remain=%zu\n", __func__, remain); + return -EIO; + } + + return drm_client_framebuffer_flush(buffer, rect); +} +EXPORT_SYMBOL(gud_drm_gadget_write_buffer); + +int gud_drm_gadget_set_buffer(struct gud_drm_gadget *gdg, struct gud_drm_req_set_buffer *req) +{ + u32 compressed_length = le32_to_cpu(req->compressed_length); + u32 length = le32_to_cpu(req->length); + struct drm_client_buffer *buffer; + struct drm_rect rect; + int ret = 0; + + if (!refcount_inc_not_zero(&gdg->usecnt)) + return -ENODEV; + + buffer = gdg->buffer ? gdg->buffer : gdg->buffer_check; + if (!buffer) { + ret = -ENOENT; + goto out; + } + + drm_rect_init(&rect, le32_to_cpu(req->x), le32_to_cpu(req->y), + le32_to_cpu(req->width), le32_to_cpu(req->height)); + + pr_debug("%s: " DRM_RECT_FMT "\n", __func__, DRM_RECT_ARG(&rect)); + + if (!gud_drm_gadget_check_rect(buffer, &rect)) { + ret = -EINVAL; + goto out; + } + + if (req->compression & ~GUD_DRM_COMPRESSION_LZ4) { + ret = -EINVAL; + goto out; + } + + gdg->set_buffer_rect = rect; + gdg->set_buffer_length = length; + + if (req->compression) { + if (!compressed_length) { + ret = -EINVAL; + goto out; + } + gdg->set_buffer_compression = req->compression; + gdg->set_buffer_compressed_length = compressed_length; + length = compressed_length; + } else { + gdg->set_buffer_compression = 0; + gdg->set_buffer_compressed_length = 0; + } +out: + refcount_dec(&gdg->usecnt); + + return ret ? ret : length; +} +EXPORT_SYMBOL(gud_drm_gadget_set_buffer); + +static void gud_drm_gadget_delete_buffers(struct gud_drm_gadget *gdg) +{ + drm_client_framebuffer_delete(gdg->buffer_check); + drm_client_framebuffer_delete(gdg->buffer); + gdg->buffer_check = NULL; + gdg->buffer = NULL; +} + +int gud_drm_gadget_disable_pipe(struct gud_drm_gadget *gdg) +{ + int ret; + + drm_client_modeset_set(&gdg->client, NULL, NULL, NULL); + ret = drm_client_modeset_commit(&gdg->client); + if (ret) + return ret; + + gud_drm_gadget_delete_buffers(gdg); + + return 0; +} +EXPORT_SYMBOL(gud_drm_gadget_disable_pipe); + +static int gud_drm_gadget_ctrl_get_display_descriptor(struct gud_drm_gadget *gdg, u16 value, + void *data, size_t size) +{ + struct drm_device *drm = gdg->client.dev; + struct gud_drm_display_descriptor desc; + u8 type = value >> 8; + u8 index = value & 0xff; + + if (type != GUD_DRM_USB_DT_DISPLAY || index) + return -EINVAL; + + desc.bLength = sizeof(desc); + desc.bDescriptorType = GUD_DRM_USB_DT_DISPLAY; + + desc.bVersion = 1; + desc.bMaxBufferSizeOrder = ilog2(gdg->max_buffer_size); + desc.bmFlags = 0; + desc.bCompression = GUD_DRM_COMPRESSION_LZ4; + + desc.dwMinWidth = cpu_to_le32(drm->mode_config.min_width); + desc.dwMaxWidth = cpu_to_le32(drm->mode_config.max_width); + desc.dwMinHeight = cpu_to_le32(drm->mode_config.min_height); + desc.dwMaxHeight = cpu_to_le32(drm->mode_config.max_height); + desc.bNumFormats = gdg->format_count; + desc.bNumProperties = gdg->num_properties; + desc.bNumConnectors = gdg->connector_count; + + size = min(size, sizeof(desc)); + memcpy(data, &desc, size); + + return size; +} + +static void gud_drm_gadget_ctrl_get_formats(struct gud_drm_gadget *gdg, __le32 *formats) +{ + unsigned int i; + + for (i = 0; i < gdg->format_count; i++) + formats[i] = cpu_to_le32(gdg->formats[i]); +} + +static int gud_drm_gadget_ctrl_get_connector(struct gud_drm_gadget *gdg, unsigned int index, + struct gud_drm_req_get_connector *desc) +{ + struct gud_drm_gadget_connector *gconn; + + if (index >= gdg->connector_count) + return -EINVAL; + + memset(desc, 0, sizeof(*desc)); + + gconn = &gdg->connectors[index]; + + desc->connector_type = gconn->connector->connector_type; + desc->flags = cpu_to_le32(GUD_DRM_CONNECTOR_FLAGS_POLL); + desc->num_properties = gconn->num_properties; + + return 0; +} + +static struct gud_drm_gadget_connector * +gud_drm_gadget_get_gconn(struct gud_drm_gadget *gdg, unsigned int index) +{ + if (index >= gdg->connector_count) + return NULL; + + return &gdg->connectors[index]; +} + +static int gud_drm_gadget_ctrl_get_connector_status(struct gud_drm_gadget *gdg, unsigned int index, + struct gud_drm_req_get_connector_status *status) +{ + struct gud_drm_gadget_connector *gconn; + unsigned long flags; + + gconn = gud_drm_gadget_get_gconn(gdg, index); + if (!gconn) + return -ENOENT; + + memset(status, 0, sizeof(*status)); + + spin_lock_irqsave(&gconn->lock, flags); + status->status = gconn->status; + if (gconn->changed) { + status->status |= GUD_DRM_CONNECTOR_STATUS_CHANGED; + gconn->changed = false; + } + if (gconn->num_modes) + status->num_modes = cpu_to_le16(gconn->num_modes); + if (gconn->edid_len) + status->edid_len = cpu_to_le16(gconn->edid_len); + spin_unlock_irqrestore(&gconn->lock, flags); + + return 0; +} + +/* This runs in interrupt context */ +int gud_drm_gadget_ctrl_get(struct gud_drm_gadget *gdg, u8 request, + u16 index, void *data, size_t size) +{ + struct gud_drm_gadget_connector *gconn; + unsigned long flags; + int ret = -EINVAL; + + pr_debug("%s: request=0x%x index=%u size=%zu\n", __func__, request, index, size); + + if (!refcount_inc_not_zero(&gdg->usecnt)) + return -ENODEV; + + if (!size) + goto out; + + switch (request) { + case USB_REQ_GET_DESCRIPTOR: + ret = gud_drm_gadget_ctrl_get_display_descriptor(gdg, index, data, size); + break; + case GUD_DRM_USB_REQ_GET_FORMATS: + if (!index && size == gdg->format_count * sizeof(u32)) { + gud_drm_gadget_ctrl_get_formats(gdg, data); + ret = 0; + } + break; + case GUD_DRM_USB_REQ_GET_PROPERTIES: + if (!index && size == gdg->num_properties * sizeof(*gdg->properties)) { + memcpy(data, gdg->properties, size); + ret = 0; + } + break; + case GUD_DRM_USB_REQ_GET_CONNECTOR: + if (size == sizeof(struct gud_drm_req_get_connector)) + ret = gud_drm_gadget_ctrl_get_connector(gdg, index, data); + break; + case GUD_DRM_USB_REQ_GET_CONNECTOR_PROPERTIES: + gconn = gud_drm_gadget_get_gconn(gdg, index); + if (gconn && size == gconn->num_properties * sizeof(*gconn->properties)) { + memcpy(data, gconn->properties, size); + ret = 0; + } + break; + case GUD_DRM_USB_REQ_GET_CONNECTOR_TV_MODE_VALUES: + gconn = gud_drm_gadget_get_gconn(gdg, index); + if (gconn && size == gconn->num_tv_mode_enum_names * DRM_PROP_NAME_LEN) { + memcpy(data, gconn->tv_mode_enum_names, size); + ret = 0; + } + break; + case GUD_DRM_USB_REQ_GET_CONNECTOR_STATUS: + if (size == sizeof(struct gud_drm_req_get_connector_status)) + ret = gud_drm_gadget_ctrl_get_connector_status(gdg, index, data); + break; + case GUD_DRM_USB_REQ_GET_CONNECTOR_MODES: + gconn = gud_drm_gadget_get_gconn(gdg, index); + spin_lock_irqsave(&gconn->lock, flags); + if (gconn && size == gconn->num_modes * sizeof(*gconn->modes)) { + memcpy(data, gconn->modes, size); + ret = 0; + } + spin_unlock_irqrestore(&gconn->lock, flags); + break; + case GUD_DRM_USB_REQ_GET_CONNECTOR_EDID: + gconn = gud_drm_gadget_get_gconn(gdg, index); + spin_lock_irqsave(&gconn->lock, flags); + if (gconn && size == gconn->edid_len) { + memcpy(data, gconn->edid, size); + ret = 0; + } + spin_unlock_irqrestore(&gconn->lock, flags); + break; + } +out: + refcount_dec(&gdg->usecnt); + + return !ret ? size : ret; +} +EXPORT_SYMBOL(gud_drm_gadget_ctrl_get); + +int gud_drm_gadget_ctrl_set(struct gud_drm_gadget *gdg, u8 request, + u16 index, void *data, size_t size) +{ + struct gud_drm_gadget_connector *gconn; + int dpms, ret = -EINVAL; + + pr_debug("%s: request=0x%x index=%u size=%zu\n", __func__, request, index, size); + + if (!refcount_inc_not_zero(&gdg->usecnt)) + return -ENODEV; + + switch (request) { + case GUD_DRM_USB_REQ_SET_CONNECTOR_FORCE_DETECT: + gconn = gud_drm_gadget_get_gconn(gdg, index); + if (gconn) + ret = gud_drm_gadget_probe_connector(gconn); + break; + case GUD_DRM_USB_REQ_SET_STATE_CHECK: + ret = gud_drm_gadget_check(gdg, data, size); + break; + case GUD_DRM_USB_REQ_SET_STATE_COMMIT: + if (!size) + ret = gud_drm_gadget_commit(gdg); + break; + case GUD_DRM_USB_REQ_SET_CONTROLLER_ENABLE: + if (size == sizeof(u8)) { + if (*(u8 *)data == 0) + ret = gud_drm_gadget_disable_pipe(gdg); + else + ret = 0; + } + break; + case GUD_DRM_USB_REQ_SET_DISPLAY_ENABLE: + if (size == sizeof(u8)) { + dpms = *(u8 *)data ? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF; + ret = drm_client_modeset_dpms(&gdg->client, dpms); + } + break; + } + + refcount_dec(&gdg->usecnt); + + return ret; +} +EXPORT_SYMBOL(gud_drm_gadget_ctrl_set); + +static int gud_drm_gadget_get_formats(struct gud_drm_gadget *gdg, u8 *max_cpp) +{ + struct drm_device *drm = gdg->client.dev; + struct drm_plane *plane; + unsigned int i; + u32 *formats; + int ret; + + *max_cpp = 0; + + drm_for_each_plane(plane, drm) { + if (plane->type == DRM_PLANE_TYPE_PRIMARY) + break; + } + + formats = kcalloc(plane->format_count, sizeof(u32), GFP_KERNEL); + if (!formats) + return -ENOMEM; + + for (i = 0; i < plane->format_count; i++) { + const struct drm_format_info *fmt; + + fmt = drm_format_info(plane->format_types[i]); + if (fmt->num_planes != 1) + continue; + + /* + * Supporting 24-bit bpp would add complexity so don't bother. + * It's hardly used and compression removes much of the gain. + */ + if (fmt->cpp[0] == 3) + continue; + + if (*max_cpp < fmt->cpp[0]) + *max_cpp = fmt->cpp[0]; + + formats[gdg->format_count++] = plane->format_types[i]; + } + + if (!gdg->format_count) { + ret = -ENOENT; + goto err_free; + } + + gdg->formats = formats; + + return 0; + +err_free: + kfree(formats); + + return ret; +} + +static int gud_drm_gadget_get_rotation_property(struct drm_device *drm, u16 *prop, u64 *val) +{ + struct drm_property_enum *prop_enum; + struct drm_plane *plane; + unsigned int num_props = 0; + u16 bitmask = 0; + + drm_for_each_plane(plane, drm) { + if (plane->type == DRM_PLANE_TYPE_PRIMARY) + break; + } + + if (!plane->rotation_property) + return 0; + + list_for_each_entry(prop_enum, &plane->rotation_property->enum_list, head) { + num_props++; + bitmask |= BIT(prop_enum->value); + } + + *prop = GUD_DRM_PROPERTY_ROTATION; + *val = bitmask; + + return 1; +} + +static int gud_drm_gadget_get_properties(struct gud_drm_gadget *gdg) +{ + struct gud_drm_property *properties; + u16 prop; + u64 val; + int ret; + + ret = gud_drm_gadget_get_rotation_property(gdg->client.dev, &prop, &val); + if (ret <= 0) + return ret; + + properties = kcalloc(1, sizeof(*properties), GFP_KERNEL); + if (!properties) + return -ENOMEM; + + gdg->properties = properties; + gdg->num_properties++; + + properties[0].prop = cpu_to_le16(prop); + properties[0].val = cpu_to_le64(val); + + return 0; +} + +static int gud_drm_gadget_get_connector_properties(struct gud_drm_gadget *gdg, + struct gud_drm_gadget_connector *gconn) +{ + struct drm_device *drm = gdg->client.dev; + struct drm_mode_config *config = &drm->mode_config; + struct drm_connector *connector = gconn->connector; + struct drm_object_properties *conn_props = connector->base.properties; + struct gud_drm_property *properties; + unsigned int i, ret = 0; + u16 prop; + u64 val; + + mutex_lock(&drm->mode_config.mutex); + + if (!conn_props->count) + goto unlock; + + /* Add room for possible backlight */ + properties = kcalloc(conn_props->count + 1, sizeof(*properties), GFP_KERNEL); + if (!properties) { + ret = -ENOMEM; + goto unlock; + } + + gconn->properties = properties; + + for (i = 0; i < conn_props->count; i++) { + struct drm_property *property = conn_props->properties[i]; + + if (property == config->tv_select_subconnector_property) { + prop = GUD_DRM_PROPERTY_TV_SELECT_SUBCONNECTOR; + val = connector->state->tv.subconnector; + } else if (property == config->tv_left_margin_property) { + prop = GUD_DRM_PROPERTY_TV_LEFT_MARGIN; + val = connector->state->tv.margins.left; + } else if (property == config->tv_right_margin_property) { + prop = GUD_DRM_PROPERTY_TV_RIGHT_MARGIN; + val = connector->state->tv.margins.right; + } else if (property == config->tv_top_margin_property) { + prop = GUD_DRM_PROPERTY_TV_TOP_MARGIN; + val = connector->state->tv.margins.top; + } else if (property == config->tv_bottom_margin_property) { + prop = GUD_DRM_PROPERTY_TV_BOTTOM_MARGIN; + val = connector->state->tv.margins.bottom; + } else if (property == config->tv_mode_property) { + struct drm_property_enum *prop_enum; + char *buf; + + list_for_each_entry(prop_enum, &property->enum_list, head) + gconn->num_tv_mode_enum_names++; + + if (WARN_ON(!gconn->num_tv_mode_enum_names)) { + ret = -EINVAL; + goto unlock; + } + + buf = kcalloc(gconn->num_tv_mode_enum_names, DRM_PROP_NAME_LEN, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto unlock; + } + + gconn->tv_mode_enum_names = buf; + + list_for_each_entry(prop_enum, &property->enum_list, head) { + strncpy(buf, prop_enum->name, DRM_PROP_NAME_LEN); + buf += DRM_PROP_NAME_LEN; + } + + prop = GUD_DRM_PROPERTY_TV_MODE; + val = connector->state->tv.mode; + val |= gconn->num_tv_mode_enum_names << GUD_DRM_USB_CONNECTOR_TV_MODE_NUM_SHIFT; + } else if (property == config->tv_brightness_property) { + prop = GUD_DRM_PROPERTY_TV_BRIGHTNESS; + val = connector->state->tv.brightness; + } else if (property == config->tv_contrast_property) { + prop = GUD_DRM_PROPERTY_TV_CONTRAST; + val = connector->state->tv.contrast; + } else if (property == config->tv_flicker_reduction_property) { + prop = GUD_DRM_PROPERTY_TV_FLICKER_REDUCTION; + val = connector->state->tv.flicker_reduction; + } else if (property == config->tv_overscan_property) { + prop = GUD_DRM_PROPERTY_TV_OVERSCAN; + val = connector->state->tv.overscan; + } else if (property == config->tv_saturation_property) { + prop = GUD_DRM_PROPERTY_TV_SATURATION; + val = connector->state->tv.saturation; + } else if (property == config->tv_hue_property) { + prop = GUD_DRM_PROPERTY_TV_HUE; + val = connector->state->tv.hue; + } else { + continue; + } + + properties[gconn->num_properties].prop = cpu_to_le16(prop); + properties[gconn->num_properties++].val = cpu_to_le64(val); + } + + if (!connector->index && gdg->backlight) { + struct backlight_properties *props = &gdg->backlight->props; + + prop = GUD_DRM_PROPERTY_BACKLIGHT_BRIGHTNESS; + val = DIV64_U64_ROUND_UP(props->brightness * 100, props->max_brightness); + properties[gconn->num_properties].prop = cpu_to_le16(prop); + properties[gconn->num_properties++].val = cpu_to_le64(val); + gconn->backlight = gdg->backlight; + } +unlock: + mutex_unlock(&drm->mode_config.mutex); + + return ret; +} + +static int gud_drm_gadget_get_connectors(struct gud_drm_gadget *gdg) +{ + struct gud_drm_gadget_connector *connectors = NULL; + struct drm_connector_list_iter conn_iter; + struct drm_device *drm = gdg->client.dev; + unsigned int connector_count = 0; + struct drm_connector *connector; + int ret = 0; + + drm_connector_list_iter_begin(drm, &conn_iter); + drm_client_for_each_connector_iter(connector, &conn_iter) { + struct gud_drm_gadget_connector *tmp, *gconn; + + tmp = krealloc(connectors, (connector_count + 1) * sizeof(*connectors), + GFP_KERNEL | __GFP_ZERO); + if (!tmp) { + ret = -ENOMEM; + break; + } + + connectors = tmp; + drm_connector_get(connector); + gconn = &connectors[connector_count++]; + gconn->connector = connector; + spin_lock_init(&gconn->lock); + + ret = gud_drm_gadget_get_connector_properties(gdg, gconn); + if (ret) + break; + } + drm_connector_list_iter_end(&conn_iter); + + gdg->connectors = connectors; + gdg->connector_count = connector_count; + + return ret; +} + +static void gud_drm_gadget_release(struct kref *kref) +{ + struct gud_drm_gadget *gdg = container_of(kref, struct gud_drm_gadget, refcount); + + kfree(gdg); +} + +static void gud_drm_gadget_put(struct gud_drm_gadget *gdg) +{ + kref_put(&gdg->refcount, gud_drm_gadget_release); +} + +static void gud_drm_gadget_client_unregister(struct drm_client_dev *client) +{ + struct gud_drm_gadget *gdg = container_of(client, struct gud_drm_gadget, client); + int timeout = 10000 / 50; + unsigned int i; + + /* + * If usecnt doesn't drop to zero, try waiting for the gadget, but we + * can't block the DRM driver forever. The worst case wait the gadget side + * can hit are tens of seconds through the call to drm_client_modeset_commit(). + */ + if (refcount_dec_and_test(&gdg->usecnt)) { + for (; timeout && refcount_read(&gdg->usecnt); timeout--) + msleep(50); + } + + if (!timeout) { + pr_err("%s: Timeout waiting for gadget side, will leak memory\n", __func__); + return; + } + + vfree(gdg->work_buf); + kfree(gdg->formats); + kfree(gdg->properties); + + for (i = 0; i < gdg->connector_count; i++) { + struct gud_drm_gadget_connector *gconn = &gdg->connectors[i]; + + drm_connector_put(gconn->connector); + kfree(gconn->properties); + kfree(gconn->tv_mode_enum_names); + kfree(gconn->modes); + kfree(gconn->edid); + } + kfree(gdg->connectors); + + gud_drm_gadget_delete_buffers(gdg); + drm_client_release(client); + gud_drm_gadget_put(gdg); +} + +static int gud_drm_gadget_client_hotplug(struct drm_client_dev *client) +{ + struct gud_drm_gadget *gdg = container_of(client, struct gud_drm_gadget, client); + + gud_drm_gadget_probe_connectors(gdg); + + return 0; +} + +static const struct drm_client_funcs gdg_client_funcs = { + .owner = THIS_MODULE, + .unregister = gud_drm_gadget_client_unregister, + .hotplug = gud_drm_gadget_client_hotplug, +}; + +struct gud_drm_gadget *gud_drm_gadget_init(unsigned int minor_id, const char *backlight, + size_t *max_buffer_size) +{ + struct gud_drm_gadget *gdg; + u8 max_cpp; + int ret; + + gdg = kzalloc(sizeof(*gdg), GFP_KERNEL); + if (!gdg) + return ERR_PTR(-ENOMEM); + + ret = drm_client_init_from_id(minor_id, &gdg->client, "gud-drm-gadget", &gdg_client_funcs); + if (ret) { + pr_err("Failed to aquire minor=%u\n", minor_id); + kfree(gdg); + return ERR_PTR(ret); + } + + refcount_set(&gdg->usecnt, 1); + /* The DRM driver (through the client) and f_gud_drm need one ref each */ + kref_init(&gdg->refcount); + kref_get(&gdg->refcount); + + if (backlight) { + gdg->backlight = backlight_device_get_by_name(backlight); + if (!gdg->backlight) { + pr_err("Failed to find backlight: %s\n", backlight); + ret = -ENODEV; + goto error_release; + } + } + + ret = gud_drm_gadget_get_formats(gdg, &max_cpp); + if (ret) { + pr_err("Failed to get formats\n"); + goto error_release; + } + + *max_buffer_size = gdg->client.dev->mode_config.max_width * + gdg->client.dev->mode_config.max_height * max_cpp; + /* f_gud_drm will kmalloc a buffer of this size */ + *max_buffer_size = min_t(size_t, *max_buffer_size, KMALLOC_MAX_SIZE); + + gdg->max_buffer_size = *max_buffer_size; + gdg->work_buf = vmalloc(gdg->max_buffer_size); + if (!gdg->work_buf) { + ret = -ENOMEM; + goto error_release; + } + + ret = gud_drm_gadget_get_properties(gdg); + if (ret) { + pr_err("Failed to get properties\n"); + goto error_release; + } + + ret = gud_drm_gadget_get_connectors(gdg); + if (ret) { + pr_err("Failed to get connectors\n"); + goto error_release; + } + + if (!drm_client_register(&gdg->client)) { + pr_err("DRM device is gone\n"); + ret = -ENODEV; + goto error_release; + } + + gud_drm_gadget_probe_connectors(gdg); + + return gdg; + +error_release: + gud_drm_gadget_client_unregister(&gdg->client); + gud_drm_gadget_fini(gdg); + + return ERR_PTR(ret); +} +EXPORT_SYMBOL(gud_drm_gadget_init); + +void gud_drm_gadget_fini(struct gud_drm_gadget *gdg) +{ + backlight_put(gdg->backlight); + gud_drm_gadget_put(gdg); +} +EXPORT_SYMBOL(gud_drm_gadget_fini); + +MODULE_AUTHOR("Noralf Trønnes"); +MODULE_LICENSE("GPL"); diff --git a/include/drm/gud_drm.h b/include/drm/gud_drm.h index 15bb30577b57..6afc369274d0 100644 --- a/include/drm/gud_drm.h +++ b/include/drm/gud_drm.h @@ -353,4 +353,17 @@ static inline void gud_drm_to_display_mode(struct drm_display_mode *dst, drm_mode_set_name(dst); } +struct gud_drm_gadget; + +struct gud_drm_gadget *gud_drm_gadget_init(unsigned int minor_id, const char *backlight, + size_t *max_buffer_size); +void gud_drm_gadget_fini(struct gud_drm_gadget *gdg); +int gud_drm_gadget_disable_pipe(struct gud_drm_gadget *gdg); +int gud_drm_gadget_ctrl_get(struct gud_drm_gadget *gdg, u8 request, + u16 index, void *data, size_t size); +int gud_drm_gadget_ctrl_set(struct gud_drm_gadget *gdg, u8 request, + u16 index, void *data, size_t size); +int gud_drm_gadget_set_buffer(struct gud_drm_gadget *gdg, struct gud_drm_req_set_buffer *req); +int gud_drm_gadget_write_buffer(struct gud_drm_gadget *gdg, const void *buf, size_t len); + #endif -- 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, URIBL_BLOCKED,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 B1848C83009 for ; Wed, 29 Apr 2020 12:58:20 +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 9102A2186A for ; Wed, 29 Apr 2020 12:58:20 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9102A2186A 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 32B706EE96; Wed, 29 Apr 2020 12:58:17 +0000 (UTC) Received: from asav21.altibox.net (asav21.altibox.net [109.247.116.8]) by gabe.freedesktop.org (Postfix) with ESMTPS id 1E2B46EE8D for ; Wed, 29 Apr 2020 12:57:58 +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 asav21.altibox.net (Postfix) with ESMTPSA id F23B680193; Wed, 29 Apr 2020 14:48:51 +0200 (CEST) From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= To: dri-devel@lists.freedesktop.org, linux-usb@vger.kernel.org Subject: [PATCH 09/10] drm/gud: Add functionality for the USB gadget side Date: Wed, 29 Apr 2020 14:48:29 +0200 Message-Id: <20200429124830.27475-10-noralf@tronnes.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20200429124830.27475-1-noralf@tronnes.org> References: <20200429124830.27475-1-noralf@tronnes.org> MIME-Version: 1.0 X-CMAE-Score: 0 X-CMAE-Analysis: v=2.3 cv=AvXAIt1P c=1 sm=1 tr=0 a=OYZzhG0JTxDrWp/F2OJbnw==:117 a=OYZzhG0JTxDrWp/F2OJbnw==:17 a=IkcTkHD0fZMA:10 a=M51BFTxLslgA:10 a=SJz97ENfAAAA:8 a=JEiCMFymvXJ_tcOM5XYA:9 a=adth_mbAzEm_eDmq:21 a=vMyTFNr94S6AnSfT: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: , Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" U2luY2UgdGhlIFVTQiBnYWRnZXQvZGV2aWNlIGhhcyB0byByZWFjaCBpbnRvIHRoZSBEUk0gaW50 ZXJuYWxzLCBwYXJ0IG9mCnRoZSBjb2RlIGlzIHBsYWNlZCBpbiB0aGUgRFJNIHN1YnN5c3RlbSBh cyBhIHNlcGFyYXRlIG1vZHVsZS4gQWxsIGNhbGxzCmludG8gdGhpcyBtb2R1bGUgcnVucyBpbiBw cm9jZXNzIGNvbnRleHQgYW5kIGFyZSBzZXJpYWxpemVkLCBleGNlcHQgb25lCmZ1bmN0aW9uIHRo YXQgcnVucyBpbiBpbnRlcnJ1cHQgY29udGV4dC4KClNpbmNlIGJvdGggdGhlIGdhZGdldCBzaWRl IGFuZCB0aGUgRFJNIHNpZGUgY2FuIGRpc2FibGUgdGhlIGdhZGdldCwKc3BlY2lhbCBjYXJlIGhh cyBiZWVuIHRha2VuIHRvIG1ha2UgdGhhdCBzYWZlLgoKU2lnbmVkLW9mZi1ieTogTm9yYWxmIFRy w7hubmVzIDxub3JhbGZAdHJvbm5lcy5vcmc+Ci0tLQogZHJpdmVycy9ncHUvZHJtL2d1ZC9LY29u ZmlnICAgICAgICAgIHwgICAgNiArCiBkcml2ZXJzL2dwdS9kcm0vZ3VkL01ha2VmaWxlICAgICAg ICAgfCAgICAxICsKIGRyaXZlcnMvZ3B1L2RybS9ndWQvZ3VkX2RybV9nYWRnZXQuYyB8IDExNjkg KysrKysrKysrKysrKysrKysrKysrKysrKysKIGluY2x1ZGUvZHJtL2d1ZF9kcm0uaCAgICAgICAg ICAgICAgICB8ICAgMTMgKwogNCBmaWxlcyBjaGFuZ2VkLCAxMTg5IGluc2VydGlvbnMoKykKIGNy ZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL2dwdS9kcm0vZ3VkL2d1ZF9kcm1fZ2FkZ2V0LmMKCmRp ZmYgLS1naXQgYS9kcml2ZXJzL2dwdS9kcm0vZ3VkL0tjb25maWcgYi9kcml2ZXJzL2dwdS9kcm0v Z3VkL0tjb25maWcKaW5kZXggMjAzZDQ0OTBmMWM3Li45OWJmYmZiZjkwMjMgMTAwNjQ0Ci0tLSBh L2RyaXZlcnMvZ3B1L2RybS9ndWQvS2NvbmZpZworKysgYi9kcml2ZXJzL2dwdS9kcm0vZ3VkL0tj b25maWcKQEAgLTEyLDMgKzEyLDkgQEAgY29uZmlnIERSTV9HVUQKIAkgIGFkYXB0ZXJzLgogCiAJ ICBJZiBNIGlzIHNlbGVjdGVkIHRoZSBtb2R1bGUgd2lsbCBiZSBjYWxsZWQgZ3VkX2RybS4KKwor Y29uZmlnIERSTV9HVURfR0FER0VUCisJdHJpc3RhdGUKKwlkZXBlbmRzIG9uIERSTQorCXNlbGVj dCBMWjRfREVDT01QUkVTUworCXNlbGVjdCBCQUNLTElHSFRfQ0xBU1NfREVWSUNFCmRpZmYgLS1n aXQgYS9kcml2ZXJzL2dwdS9kcm0vZ3VkL01ha2VmaWxlIGIvZHJpdmVycy9ncHUvZHJtL2d1ZC9N YWtlZmlsZQppbmRleCA3M2VkN2VmM2RhOTQuLmZiNWNmYmQ5M2QwZiAxMDA2NDQKLS0tIGEvZHJp dmVycy9ncHUvZHJtL2d1ZC9NYWtlZmlsZQorKysgYi9kcml2ZXJzL2dwdS9kcm0vZ3VkL01ha2Vm aWxlCkBAIC0yLDMgKzIsNCBAQAogCiBndWRfZHJtLW9ianMJCQk6PSBndWRfZHJtX2Rydi5vIGd1 ZF9kcm1fcGlwZS5vIGd1ZF9kcm1fY29ubmVjdG9yLm8KIG9iai0kKENPTkZJR19EUk1fR1VEKQkJ Kz0gZ3VkX2RybS5vCitvYmotJChDT05GSUdfRFJNX0dVRF9HQURHRVQpCSs9IGd1ZF9kcm1fZ2Fk Z2V0Lm8KZGlmZiAtLWdpdCBhL2RyaXZlcnMvZ3B1L2RybS9ndWQvZ3VkX2RybV9nYWRnZXQuYyBi L2RyaXZlcnMvZ3B1L2RybS9ndWQvZ3VkX2RybV9nYWRnZXQuYwpuZXcgZmlsZSBtb2RlIDEwMDY0 NAppbmRleCAwMDAwMDAwMDAwMDAuLmE5YzkxNmFiZWM4NQotLS0gL2Rldi9udWxsCisrKyBiL2Ry aXZlcnMvZ3B1L2RybS9ndWQvZ3VkX2RybV9nYWRnZXQuYwpAQCAtMCwwICsxLDExNjkgQEAKKy8v IFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBHUEwtMi4wCisvKgorICogQ29weXJpZ2h0IDIwMjAg Tm9yYWxmIFRyw7hubmVzCisgKi8KKworI2luY2x1ZGUgPGxpbnV4L2JhY2tsaWdodC5oPgorI2lu Y2x1ZGUgPGxpbnV4L2RlbGF5Lmg+CisjaW5jbHVkZSA8bGludXgvbHo0Lmg+CisjaW5jbHVkZSA8 bGludXgvbW9kdWxlLmg+CisjaW5jbHVkZSA8bGludXgvc2xhYi5oPgorI2luY2x1ZGUgPGxpbnV4 L3NwaW5sb2NrLmg+CisjaW5jbHVkZSA8bGludXgvc3RyaW5nLmg+CisKKyNpbmNsdWRlIDxkcm0v ZHJtX2NsaWVudC5oPgorI2luY2x1ZGUgPGRybS9kcm1fY29ubmVjdG9yLmg+CisjaW5jbHVkZSA8 ZHJtL2RybV9jcnRjLmg+CisjaW5jbHVkZSA8ZHJtL2RybV9mb3VyY2MuaD4KKyNpbmNsdWRlIDxk cm0vZHJtX21vZGVfb2JqZWN0Lmg+CisjaW5jbHVkZSA8ZHJtL2RybV9wbGFuZS5oPgorI2luY2x1 ZGUgPGRybS9kcm1fcmVjdC5oPgorI2luY2x1ZGUgPGRybS9ndWRfZHJtLmg+CisKKyNpbmNsdWRl ICJndWRfZHJtX2ludGVybmFsLmgiCisKKy8qCisgKiBDb25jdXJyZW5jeToKKyAqIENhbGxzIGlu dG8gdGhpcyBtb2R1bGUgZnJvbSBmX2d1ZF9kcm0gYXJlIHNlcmlhbGl6ZWQgYW5kIHJ1biBpbiBw cm9jZXNzCisgKiBjb250ZXh0IGV4Y2VwdCBndWRfZHJtX2dhZGdldF9jdHJsX2dldCgpIHdoaWNo IGlzIHJ1biBpbiBpbnRlcnJ1cHQgY29udGV4dC4KKyAqCisgKiBUZXJtaW5hdGlvbjoKKyAqIEEg RFJNIGNsaWVudCBjYW4gbm90IHJlbGVhc2UgaXRzZWxmLCBvbmx5IHRoZSBEUk0gZHJpdmVyIHdo aWNoIHJlc291cmNlcyB0aGUKKyAqIGNsaWVudCB1c2VzIGNhbiBkbyB0aGF0LgorICogVGhpcyBt ZWFucyB0aGF0IHRoZXJlIGFyZSAyIHBhdGhzIHRvIHN0b3AgdGhlIGdhZGdldCBmdW5jdGlvbjoK KyAqIC0gVW5yZWdpc3RlcmluZyB0aGUgRFJNIGRyaXZlciAobW9kdWxlIHVubG9hZCkKKyAqIC0g RGlzYWJsaW5nIHRoZSBVU0IgZ2FkZ2V0IChjb25maWdmcyB1bmJpbmQpCisgKgorICogQSB1c2Ug Y291bnRlciBwcm90ZWN0cyB0aGUgZ2FkZ2V0IHNob3VsZCB0aGUgY2xpZW50IGdvIGF3YXkuIEEg a3JlZiBpcyB1c2VkCisgKiB0byBjb250cm9sIHRoZSByZWxlYXNlIG9mIHRoZSBndWRfZHJtX2dh ZGdldCBzdHJ1Y3R1cmUgc2hhcmVkIGJ5IHRoZSAyIGFjdG9ycy4KKyAqCisgKiBCYWNrbGlnaHQ6 CisgKiBJZiB0aGVyZSdzIGEgYmFja2xpZ2h0IGRldmljZSBpdCdzIGF0dGFjaGVkIHRvIHRoZSBm aXJzdCBjb25uZWN0b3IuCisgKi8KKworc3RydWN0IGd1ZF9kcm1fZ2FkZ2V0X2Nvbm5lY3RvciB7 CisJc3RydWN0IGRybV9jb25uZWN0b3IgKmNvbm5lY3RvcjsKKworCWNvbnN0IHN0cnVjdCBndWRf ZHJtX3Byb3BlcnR5ICpwcm9wZXJ0aWVzOworCXVuc2lnbmVkIGludCBudW1fcHJvcGVydGllczsK Kwljb25zdCBjaGFyICp0dl9tb2RlX2VudW1fbmFtZXM7CisJdW5zaWduZWQgaW50IG51bV90dl9t b2RlX2VudW1fbmFtZXM7CisJc3RydWN0IGJhY2tsaWdodF9kZXZpY2UgKmJhY2tsaWdodDsKKwor CXNwaW5sb2NrX3QgbG9jazsgLyogUHJvdGVjdHMgdGhlIGZvbGxvd2luZyBtZW1iZXJzOiAqLwor CWVudW0gZHJtX2Nvbm5lY3Rvcl9zdGF0dXMgc3RhdHVzOworCXVuc2lnbmVkIGludCB3aWR0aF9t bTsKKwl1bnNpZ25lZCBpbnQgaGVpZ2h0X21tOworCXN0cnVjdCBndWRfZHJtX2Rpc3BsYXlfbW9k ZSAqbW9kZXM7CisJdW5zaWduZWQgaW50IG51bV9tb2RlczsKKwl2b2lkICplZGlkOworCXNpemVf dCBlZGlkX2xlbjsKKwlib29sIGNoYW5nZWQ7Cit9OworCitzdHJ1Y3QgZ3VkX2RybV9nYWRnZXQg eworCXN0cnVjdCBrcmVmIHJlZmNvdW50OworCXJlZmNvdW50X3QgdXNlY250OworCXN0cnVjdCBk cm1fY2xpZW50X2RldiBjbGllbnQ7CisJc3RydWN0IGJhY2tsaWdodF9kZXZpY2UgKmJhY2tsaWdo dDsKKworCWNvbnN0IHUzMiAqZm9ybWF0czsKKwl1bnNpZ25lZCBpbnQgZm9ybWF0X2NvdW50Owor CisJY29uc3Qgc3RydWN0IGd1ZF9kcm1fcHJvcGVydHkgKnByb3BlcnRpZXM7CisJdW5zaWduZWQg aW50IG51bV9wcm9wZXJ0aWVzOworCisJc3RydWN0IGd1ZF9kcm1fZ2FkZ2V0X2Nvbm5lY3RvciAq Y29ubmVjdG9yczsKKwl1bnNpZ25lZCBpbnQgY29ubmVjdG9yX2NvdW50OworCisJc3RydWN0IGRy bV9yZWN0IHNldF9idWZmZXJfcmVjdDsKKwl1MzIgc2V0X2J1ZmZlcl9sZW5ndGg7CisJdTggc2V0 X2J1ZmZlcl9jb21wcmVzc2lvbjsKKwl1MzIgc2V0X2J1ZmZlcl9jb21wcmVzc2VkX2xlbmd0aDsK KworCXN0cnVjdCBkcm1fY2xpZW50X2J1ZmZlciAqYnVmZmVyOworCXN0cnVjdCBkcm1fY2xpZW50 X2J1ZmZlciAqYnVmZmVyX2NoZWNrOworCXU4IGJyaWdodG5lc3M7CisJYm9vbCBjaGVja19vazsK KworCXNpemVfdCBtYXhfYnVmZmVyX3NpemU7CisJdm9pZCAqd29ya19idWY7Cit9OworCitzdGF0 aWMgaW50IGd1ZF9kcm1fZ2FkZ2V0X3Byb2JlX2Nvbm5lY3RvcihzdHJ1Y3QgZ3VkX2RybV9nYWRn ZXRfY29ubmVjdG9yICpnY29ubikKK3sKKwlzdHJ1Y3QgZHJtX2Nvbm5lY3RvciAqY29ubmVjdG9y ID0gZ2Nvbm4tPmNvbm5lY3RvcjsKKwlzdHJ1Y3QgZ3VkX2RybV9kaXNwbGF5X21vZGUgKm1vZGVz ID0gTlVMTDsKKwlzdHJ1Y3QgZHJtX2RldmljZSAqZHJtID0gY29ubmVjdG9yLT5kZXY7CisJc3Ry dWN0IGRybV9kaXNwbGF5X21vZGUgKm1vZGU7CisJdm9pZCAqZWRpZF9kYXRhLCAqZWRpZCA9IE5V TEw7CisJdW5zaWduZWQgaW50IG51bV9tb2RlcyA9IDA7CisJc2l6ZV90IGVkaWRfbGVuID0gMDsK Kwl1bnNpZ25lZCBsb25nIGZsYWdzOworCXVuc2lnbmVkIGludCBpID0gMDsKKwlpbnQgcmV0ID0g MDsKKworCW11dGV4X2xvY2soJmRybS0+bW9kZV9jb25maWcubXV0ZXgpOworCisJY29ubmVjdG9y LT5mdW5jcy0+ZmlsbF9tb2Rlcyhjb25uZWN0b3IsCisJCQkJICAgICBkcm0tPm1vZGVfY29uZmln Lm1heF93aWR0aCwKKwkJCQkgICAgIGRybS0+bW9kZV9jb25maWcubWF4X2hlaWdodCk7CisKKwls aXN0X2Zvcl9lYWNoX2VudHJ5KG1vZGUsICZjb25uZWN0b3ItPm1vZGVzLCBoZWFkKQorCQludW1f bW9kZXMrKzsKKworCWlmICghbnVtX21vZGVzKQorCQlnb3RvIHVwZGF0ZTsKKworCW1vZGVzID0g a21hbGxvY19hcnJheShudW1fbW9kZXMsIHNpemVvZigqbW9kZXMpLCBHRlBfS0VSTkVMKTsKKwlp ZiAoIW1vZGVzKSB7CisJCXJldCA9IC1FTk9NRU07CisJCW51bV9tb2RlcyA9IDA7CisJCWdvdG8g dXBkYXRlOworCX0KKworCWxpc3RfZm9yX2VhY2hfZW50cnkobW9kZSwgJmNvbm5lY3Rvci0+bW9k ZXMsIGhlYWQpCisJCWd1ZF9kcm1fZnJvbV9kaXNwbGF5X21vZGUoJm1vZGVzW2krK10sIG1vZGUp OworCisJaWYgKCFjb25uZWN0b3ItPmVkaWRfYmxvYl9wdHIpCisJCWdvdG8gdXBkYXRlOworCisJ ZWRpZF9kYXRhID0gY29ubmVjdG9yLT5lZGlkX2Jsb2JfcHRyLT5kYXRhOworCWVkaWRfbGVuID0g Y29ubmVjdG9yLT5lZGlkX2Jsb2JfcHRyLT5sZW5ndGg7CisJaWYgKCFlZGlkX2RhdGEgfHwgIWVk aWRfbGVuKSB7CisJCWVkaWRfbGVuID0gMDsKKwkJZ290byB1cGRhdGU7CisJfQorCisJZWRpZCA9 IGttZW1kdXAoZWRpZF9kYXRhLCBlZGlkX2xlbiwgR0ZQX0tFUk5FTCk7CisJaWYgKCFlZGlkKSB7 CisJCXJldCA9IC1FTk9NRU07CisJCWVkaWRfbGVuID0gMDsKKwl9CisKK3VwZGF0ZToKKwlzcGlu X2xvY2tfaXJxc2F2ZSgmZ2Nvbm4tPmxvY2ssIGZsYWdzKTsKKwlpZiAoZ2Nvbm4tPnN0YXR1cyAh PSBjb25uZWN0b3ItPnN0YXR1cyB8fCBnY29ubi0+bnVtX21vZGVzICE9IG51bV9tb2RlcyB8fAor CSAgICBnY29ubi0+ZWRpZF9sZW4gIT0gZWRpZF9sZW4gfHwKKwkgICAgKGdjb25uLT5tb2RlcyAm JiBtb2RlcyAmJiBtZW1jbXAoZ2Nvbm4tPm1vZGVzLCBtb2RlcywgbnVtX21vZGVzICogc2l6ZW9m KCptb2RlcykpKSB8fAorCSAgICAoZ2Nvbm4tPmVkaWQgJiYgZWRpZCAmJiBtZW1jbXAoZ2Nvbm4t PmVkaWQsIGVkaWQsIGVkaWRfbGVuKSkpCisJCWdjb25uLT5jaGFuZ2VkID0gdHJ1ZTsKKwlzd2Fw KGdjb25uLT5tb2RlcywgbW9kZXMpOworCWdjb25uLT5udW1fbW9kZXMgPSBudW1fbW9kZXM7CisJ c3dhcChnY29ubi0+ZWRpZCwgZWRpZCk7CisJZ2Nvbm4tPmVkaWRfbGVuID0gZWRpZF9sZW47CisJ Z2Nvbm4tPndpZHRoX21tID0gY29ubmVjdG9yLT5kaXNwbGF5X2luZm8ud2lkdGhfbW07CisJZ2Nv bm4tPmhlaWdodF9tbSA9IGNvbm5lY3Rvci0+ZGlzcGxheV9pbmZvLmhlaWdodF9tbTsKKwlnY29u bi0+c3RhdHVzID0gY29ubmVjdG9yLT5zdGF0dXM7CisJc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgm Z2Nvbm4tPmxvY2ssIGZsYWdzKTsKKworCW11dGV4X3VubG9jaygmZHJtLT5tb2RlX2NvbmZpZy5t dXRleCk7CisKKwlrZnJlZShlZGlkKTsKKwlrZnJlZShtb2Rlcyk7CisKKwlyZXR1cm4gcmV0Owor fQorCitzdGF0aWMgdm9pZCBndWRfZHJtX2dhZGdldF9wcm9iZV9jb25uZWN0b3JzKHN0cnVjdCBn dWRfZHJtX2dhZGdldCAqZ2RnKQoreworCXVuc2lnbmVkIGludCBpOworCisJZm9yIChpID0gMDsg aSA8IGdkZy0+Y29ubmVjdG9yX2NvdW50OyBpKyspCisJCWd1ZF9kcm1fZ2FkZ2V0X3Byb2JlX2Nv bm5lY3RvcigmZ2RnLT5jb25uZWN0b3JzW2ldKTsKK30KKworc3RhdGljIGJvb2wgZ3VkX2RybV9n YWRnZXRfY2hlY2tfYnVmZmVyKHN0cnVjdCBndWRfZHJtX2dhZGdldCAqZ2RnLAorCQkJCQlzdHJ1 Y3QgZHJtX2NsaWVudF9idWZmZXIgKmJ1ZmZlciwKKwkJCQkJc3RydWN0IGRybV9kaXNwbGF5X21v ZGUgKm1vZGUsCisJCQkJCXUzMiBmb3JtYXQpCit7CisJc3RydWN0IGRybV9mcmFtZWJ1ZmZlciAq ZmI7CisKKwlpZiAoIWJ1ZmZlcikKKwkJcmV0dXJuIGZhbHNlOworCisJZmIgPSBidWZmZXItPmZi OworCisJcmV0dXJuIGZiLT5mb3JtYXQtPmZvcm1hdCA9PSBmb3JtYXQgJiYKKwkgICAgICAgZmIt PndpZHRoID09IG1vZGUtPmhkaXNwbGF5ICYmIGZiLT5oZWlnaHQgPT0gbW9kZS0+dmRpc3BsYXk7 Cit9CisKK3N0YXRpYyBib29sIGd1ZF9kcm1fZ2FkZ2V0X3NldF9jb25uZWN0b3JfcHJvcGVydHko c3RydWN0IGRybV9jbGllbnRfZGV2ICpjbGllbnQsCisJCQkJCQkgIHN0cnVjdCBkcm1fY29ubmVj dG9yICpjb25uZWN0b3IsCisJCQkJCQkgIHUxNiBwcm9wLCB1NjQgdmFsLCBpbnQgKnJldCkKK3sK KwlzdHJ1Y3QgZHJtX21vZGVfY29uZmlnICpjb25maWcgPSAmY29ubmVjdG9yLT5kZXYtPm1vZGVf Y29uZmlnOworCXN0cnVjdCBkcm1fcHJvcGVydHkgKnByb3BlcnR5OworCisJc3dpdGNoIChwcm9w KSB7CisJY2FzZSBHVURfRFJNX1BST1BFUlRZX1RWX1NFTEVDVF9TVUJDT05ORUNUT1I6CisJCXBy b3BlcnR5ID0gY29uZmlnLT50dl9zZWxlY3Rfc3ViY29ubmVjdG9yX3Byb3BlcnR5OworCQlicmVh azsKKwljYXNlIEdVRF9EUk1fUFJPUEVSVFlfVFZfTEVGVF9NQVJHSU46CisJCXByb3BlcnR5ID0g Y29uZmlnLT50dl9sZWZ0X21hcmdpbl9wcm9wZXJ0eTsKKwkJYnJlYWs7CisJY2FzZSBHVURfRFJN X1BST1BFUlRZX1RWX1JJR0hUX01BUkdJTjoKKwkJcHJvcGVydHkgPSBjb25maWctPnR2X3JpZ2h0 X21hcmdpbl9wcm9wZXJ0eTsKKwkJYnJlYWs7CisJY2FzZSBHVURfRFJNX1BST1BFUlRZX1RWX1RP UF9NQVJHSU46CisJCXByb3BlcnR5ID0gY29uZmlnLT50dl90b3BfbWFyZ2luX3Byb3BlcnR5Owor CQlicmVhazsKKwljYXNlIEdVRF9EUk1fUFJPUEVSVFlfVFZfQk9UVE9NX01BUkdJTjoKKwkJcHJv cGVydHkgPSBjb25maWctPnR2X2JvdHRvbV9tYXJnaW5fcHJvcGVydHk7CisJCWJyZWFrOworCWNh c2UgR1VEX0RSTV9QUk9QRVJUWV9UVl9NT0RFOgorCQlwcm9wZXJ0eSA9IGNvbmZpZy0+dHZfbW9k ZV9wcm9wZXJ0eTsKKwkJYnJlYWs7CisJY2FzZSBHVURfRFJNX1BST1BFUlRZX1RWX0JSSUdIVE5F U1M6CisJCXByb3BlcnR5ID0gY29uZmlnLT50dl9icmlnaHRuZXNzX3Byb3BlcnR5OworCQlicmVh azsKKwljYXNlIEdVRF9EUk1fUFJPUEVSVFlfVFZfQ09OVFJBU1Q6CisJCXByb3BlcnR5ID0gY29u ZmlnLT50dl9jb250cmFzdF9wcm9wZXJ0eTsKKwkJYnJlYWs7CisJY2FzZSBHVURfRFJNX1BST1BF UlRZX1RWX0ZMSUNLRVJfUkVEVUNUSU9OOgorCQlwcm9wZXJ0eSA9IGNvbmZpZy0+dHZfZmxpY2tl cl9yZWR1Y3Rpb25fcHJvcGVydHk7CisJCWJyZWFrOworCWNhc2UgR1VEX0RSTV9QUk9QRVJUWV9U Vl9PVkVSU0NBTjoKKwkJcHJvcGVydHkgPSBjb25maWctPnR2X292ZXJzY2FuX3Byb3BlcnR5Owor CQlicmVhazsKKwljYXNlIEdVRF9EUk1fUFJPUEVSVFlfVFZfU0FUVVJBVElPTjoKKwkJcHJvcGVy dHkgPSBjb25maWctPnR2X3NhdHVyYXRpb25fcHJvcGVydHk7CisJCWJyZWFrOworCWNhc2UgR1VE X0RSTV9QUk9QRVJUWV9UVl9IVUU6CisJCXByb3BlcnR5ID0gY29uZmlnLT50dl9odWVfcHJvcGVy dHk7CisJCWJyZWFrOworCWRlZmF1bHQ6CisJCXJldHVybiBmYWxzZTsKKwl9CisKKwkqcmV0ID0g ZHJtX2NsaWVudF9tb2Rlc2V0X3NldF9wcm9wZXJ0eShjbGllbnQsICZjb25uZWN0b3ItPmJhc2Us IHByb3BlcnR5LCB2YWwpOworCisJcmV0dXJuIHRydWU7Cit9CisKK3N0YXRpYyBpbnQgZ3VkX2Ry bV9nYWRnZXRfY2hlY2soc3RydWN0IGd1ZF9kcm1fZ2FkZ2V0ICpnZGcsIHN0cnVjdCBndWRfZHJt X3JlcV9zZXRfc3RhdGUgKnJlcSwKKwkJCQlzaXplX3Qgc2l6ZSkKK3sKKwlzdHJ1Y3QgZHJtX2Ns aWVudF9kZXYgKmNsaWVudCA9ICZnZGctPmNsaWVudDsKKwl1MzIgZm9ybWF0ID0gbGUzMl90b19j cHUocmVxLT5mb3JtYXQpOworCXN0cnVjdCBkcm1fY2xpZW50X2J1ZmZlciAqYnVmZmVyOworCXN0 cnVjdCBkcm1fY29ubmVjdG9yICpjb25uZWN0b3I7CisJc3RydWN0IGRybV9kaXNwbGF5X21vZGUg bW9kZTsKKwl1bnNpZ25lZCBpbnQgaTsKKwl2b2lkICp2YWRkcjsKKwlpbnQgcmV0OworCisJaWYg KHNpemUgPCBzaXplb2Yoc3RydWN0IGd1ZF9kcm1fcmVxX3NldF9zdGF0ZSkpCisJCXJldHVybiAt RUlOVkFMOworCisJaWYgKHNpemUgIT0gc3RydWN0X3NpemUocmVxLCBwcm9wZXJ0aWVzLCByZXEt Pm51bV9wcm9wZXJ0aWVzKSkKKwkJcmV0dXJuIC1FSU5WQUw7CisKKwltZW1zZXQoJm1vZGUsIDAs IHNpemVvZihtb2RlKSk7CisJZ3VkX2RybV90b19kaXNwbGF5X21vZGUoJm1vZGUsICZyZXEtPm1v ZGUpOworCisJZ2RnLT5jaGVja19vayA9IGZhbHNlOworCisJaWYgKCFtb2RlLmhkaXNwbGF5IHx8 ICFmb3JtYXQpCisJCXJldHVybiAtRUlOVkFMOworCisJaWYgKHJlcS0+Y29ubmVjdG9yID49IGdk Zy0+Y29ubmVjdG9yX2NvdW50KQorCQlyZXR1cm4gLUVJTlZBTDsKKworCWNvbm5lY3RvciA9IGdk Zy0+Y29ubmVjdG9yc1tyZXEtPmNvbm5lY3Rvcl0uY29ubmVjdG9yOworCisJaWYgKGdkZy0+YnVm ZmVyX2NoZWNrKSB7CisJCWRybV9jbGllbnRfZnJhbWVidWZmZXJfZGVsZXRlKGdkZy0+YnVmZmVy X2NoZWNrKTsKKwkJZ2RnLT5idWZmZXJfY2hlY2sgPSBOVUxMOworCX0KKworCWlmICghZ3VkX2Ry bV9nYWRnZXRfY2hlY2tfYnVmZmVyKGdkZywgZ2RnLT5idWZmZXIsICZtb2RlLCBmb3JtYXQpKSB7 CisJCWJ1ZmZlciA9IGRybV9jbGllbnRfZnJhbWVidWZmZXJfY3JlYXRlKGNsaWVudCwgbW9kZS5o ZGlzcGxheSwgbW9kZS52ZGlzcGxheSwKKwkJCQkJCSAgICAgICBmb3JtYXQpOworCQlpZiAoSVNf RVJSKGJ1ZmZlcikpCisJCQlyZXR1cm4gUFRSX0VSUihidWZmZXIpOworCisJCXZhZGRyID0gZHJt X2NsaWVudF9idWZmZXJfdm1hcChidWZmZXIpOworCQlpZiAoSVNfRVJSKHZhZGRyKSkgeworCQkJ ZHJtX2NsaWVudF9mcmFtZWJ1ZmZlcl9kZWxldGUoYnVmZmVyKTsKKwkJCXJldHVybiBQVFJfRVJS KHZhZGRyKTsKKwkJfQorCisJCWdkZy0+YnVmZmVyX2NoZWNrID0gYnVmZmVyOworCX0gZWxzZSB7 CisJCWJ1ZmZlciA9IGdkZy0+YnVmZmVyOworCX0KKworCXJldCA9IGRybV9jbGllbnRfbW9kZXNl dF9zZXQoY2xpZW50LCBjb25uZWN0b3IsICZtb2RlLCBidWZmZXItPmZiKTsKKwlpZiAocmV0KQor CQlyZXR1cm4gcmV0OworCisJZm9yIChpID0gMDsgaSA8IHJlcS0+bnVtX3Byb3BlcnRpZXM7IGkr KykgeworCQl1MTYgcHJvcCA9IGxlMTZfdG9fY3B1KHJlcS0+cHJvcGVydGllc1tpXS5wcm9wKTsK KwkJdTY0IHZhbCA9IGxlNjRfdG9fY3B1KHJlcS0+cHJvcGVydGllc1tpXS52YWwpOworCisJCWlm IChndWRfZHJtX2dhZGdldF9zZXRfY29ubmVjdG9yX3Byb3BlcnR5KGNsaWVudCwgY29ubmVjdG9y LCBwcm9wLCB2YWwsICZyZXQpKSB7CisJCQlpZiAocmV0KQorCQkJCXJldHVybiByZXQ7CisJCQlj b250aW51ZTsKKwkJfQorCisJCXN3aXRjaCAocHJvcCkgeworCQljYXNlIEdVRF9EUk1fUFJPUEVS VFlfQkFDS0xJR0hUX0JSSUdIVE5FU1M6CisJCQlpZiAodmFsID4gMTAwKQorCQkJCXJldHVybiAt RUlOVkFMOworCQkJZ2RnLT5icmlnaHRuZXNzID0gdmFsOworCQkJYnJlYWs7CisJCWNhc2UgR1VE X0RSTV9QUk9QRVJUWV9ST1RBVElPTjoKKwkJCXJldCA9IGRybV9jbGllbnRfbW9kZXNldF9zZXRf cm90YXRpb24oY2xpZW50LCB2YWwpOworCQkJYnJlYWs7CisJCWRlZmF1bHQ6CisJCQlwcl9lcnIo IiVzOiBVbmtub3duIHByb3BlcnR5OiAldVxuIiwgX19mdW5jX18sIHByb3ApOworCQkJY29udGlu dWU7CisJCX0KKworCQlpZiAocmV0KQorCQkJcmV0dXJuIHJldDsKKwl9CisKKwlyZXQgPSBkcm1f Y2xpZW50X21vZGVzZXRfY2hlY2soJmdkZy0+Y2xpZW50KTsKKwlpZiAocmV0KQorCQlyZXR1cm4g cmV0OworCisJZ2RnLT5jaGVja19vayA9IHRydWU7CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGlj IGludCBndWRfZHJtX2dhZGdldF9jb21taXQoc3RydWN0IGd1ZF9kcm1fZ2FkZ2V0ICpnZGcpCit7 CisJaW50IHJldDsKKworCWlmICghZ2RnLT5jaGVja19vaykKKwkJcmV0dXJuIC1FSU5WQUw7CisK KwlpZiAoZ2RnLT5iYWNrbGlnaHQpIHsKKwkJaW50IHZhbCwgbWF4X2JyaWdodG5lc3MgPSBnZGct PmJhY2tsaWdodC0+cHJvcHMubWF4X2JyaWdodG5lc3M7CisKKwkJdmFsID0gRElWNjRfVTY0X1JP VU5EX1VQKGdkZy0+YnJpZ2h0bmVzcyAqIG1heF9icmlnaHRuZXNzLCAxMDApOworCQlyZXQgPSBi YWNrbGlnaHRfZGV2aWNlX3NldF9icmlnaHRuZXNzKGdkZy0+YmFja2xpZ2h0LCB2YWwpOworCQlp ZiAocmV0KQorCQkJcmV0dXJuIHJldDsKKwl9CisKKwlyZXQgPSBkcm1fY2xpZW50X21vZGVzZXRf Y29tbWl0KCZnZGctPmNsaWVudCk7CisJaWYgKHJldCkKKwkJcmV0dXJuIHJldDsKKworCWlmIChn ZGctPmJ1ZmZlcl9jaGVjaykgeworCQlkcm1fY2xpZW50X2ZyYW1lYnVmZmVyX2RlbGV0ZShnZGct PmJ1ZmZlcik7CisJCWdkZy0+YnVmZmVyID0gZ2RnLT5idWZmZXJfY2hlY2s7CisJCWdkZy0+YnVm ZmVyX2NoZWNrID0gTlVMTDsKKwl9CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIHNpemVfdCBn dWRfZHJtX2dhZGdldF93cml0ZV9idWZmZXJfbWVtY3B5KHN0cnVjdCBkcm1fY2xpZW50X2J1ZmZl ciAqYnVmZmVyLAorCQkJCQkJIGNvbnN0IHZvaWQgKnNyYywgc2l6ZV90IGxlbiwKKwkJCQkJCSBz dHJ1Y3QgZHJtX3JlY3QgKnJlY3QpCit7CisJdW5zaWduZWQgaW50IGNwcCA9IGJ1ZmZlci0+ZmIt PmZvcm1hdC0+Y3BwWzBdOworCXNpemVfdCBkc3RfcGl0Y2ggPSBidWZmZXItPmZiLT5waXRjaGVz WzBdOworCXNpemVfdCBzcmNfcGl0Y2ggPSBkcm1fcmVjdF93aWR0aChyZWN0KSAqIGNwcDsKKwl1 bnNpZ25lZCBpbnQgeTsKKwl2b2lkICpkc3Q7CisKKwkvKiBHZXQgdGhlIGFkZHJlc3MsIGl0J3Mg YWxyZWFkeSBtYXBwZWQgKi8KKwlkc3QgPSBkcm1fY2xpZW50X2J1ZmZlcl92bWFwKGJ1ZmZlcik7 CisJZHN0ICs9IHJlY3QtPnkxICogZHN0X3BpdGNoOworCWRzdCArPSByZWN0LT54MSAqIGNwcDsK KworCWZvciAoeSA9IDA7IHkgPCBkcm1fcmVjdF9oZWlnaHQocmVjdCkgJiYgbGVuOyB5KyspIHsK KwkJc3JjX3BpdGNoID0gbWluKHNyY19waXRjaCwgbGVuKTsKKwkJbWVtY3B5KGRzdCwgc3JjLCBz cmNfcGl0Y2gpOworCQlzcmMgKz0gc3JjX3BpdGNoOworCQlkc3QgKz0gZHN0X3BpdGNoOworCQls ZW4gLT0gc3JjX3BpdGNoOworCX0KKworCXJldHVybiBsZW47Cit9CisKK3N0YXRpYyBib29sIGd1 ZF9kcm1fZ2FkZ2V0X2NoZWNrX3JlY3Qoc3RydWN0IGRybV9jbGllbnRfYnVmZmVyICpidWZmZXIs IHN0cnVjdCBkcm1fcmVjdCAqcmVjdCkKK3sKKwlyZXR1cm4gYnVmZmVyLT5mYiAmJiByZWN0LT54 MSA8IHJlY3QtPngyICYmIHJlY3QtPnkxIDwgcmVjdC0+eTIgJiYKKwkgICAgICAgcmVjdC0+eDIg PD0gYnVmZmVyLT5mYi0+d2lkdGggJiYgcmVjdC0+eTIgPD0gYnVmZmVyLT5mYi0+aGVpZ2h0Owor fQorCitpbnQgZ3VkX2RybV9nYWRnZXRfd3JpdGVfYnVmZmVyKHN0cnVjdCBndWRfZHJtX2dhZGdl dCAqZ2RnLCBjb25zdCB2b2lkICpidWYsIHNpemVfdCBsZW4pCit7CisJc3RydWN0IGRybV9jbGll bnRfYnVmZmVyICpidWZmZXIgPSBnZGctPmJ1ZmZlciA/IGdkZy0+YnVmZmVyIDogZ2RnLT5idWZm ZXJfY2hlY2s7CisJc3RydWN0IGRybV9yZWN0ICpyZWN0ID0gJmdkZy0+c2V0X2J1ZmZlcl9yZWN0 OworCXU4IGNvbXByZXNzaW9uID0gZ2RnLT5zZXRfYnVmZmVyX2NvbXByZXNzaW9uOworCXN0cnVj dCBkcm1fZnJhbWVidWZmZXIgKmZiOworCXNpemVfdCByZW1haW47CisJaW50IHJldDsKKworCXBy X2RlYnVnKCIlczogbGVuPSV6dSBjb21wcmVzc2lvbj0weCV4XG4iLCBfX2Z1bmNfXywgbGVuLCBj b21wcmVzc2lvbik7CisKKwlpZiAoV0FSTl9PTl9PTkNFKCFidWZmZXIpKQorCQlyZXR1cm4gLUVO T01FTTsKKworCWlmICghZ3VkX2RybV9nYWRnZXRfY2hlY2tfcmVjdChidWZmZXIsIHJlY3QpKSB7 CisJCXByX2VycigiJXM6IFJlY3RhbmdsZSBkb2Vzbid0IGZpdFxuIiwgX19mdW5jX18pOworCQly ZXR1cm4gLUVJTlZBTDsKKwl9CisKKwlmYiA9IGJ1ZmZlci0+ZmI7CisKKwlpZiAoY29tcHJlc3Np b24gJiBHVURfRFJNX0NPTVBSRVNTSU9OX0xaNCkgeworCQlpZiAobGVuICE9IGdkZy0+c2V0X2J1 ZmZlcl9jb21wcmVzc2VkX2xlbmd0aCkgeworCQkJcHJfZXJyKCIlczogQnVmZmVyIGNvbXByZXNz ZWQgbGVuIGRpZmZlcnM6ICV6dSAhPSAlenVcbiIsCisJCQkgICAgICAgX19mdW5jX18sIGxlbiwg Z2RnLT5zZXRfYnVmZmVyX2NvbXByZXNzZWRfbGVuZ3RoKTsKKwkJCXJldHVybiAtRUlOVkFMOwor CQl9CisKKwkJcmV0ID0gTFo0X2RlY29tcHJlc3Nfc2FmZShidWYsIGdkZy0+d29ya19idWYsIGxl biwgZ2RnLT5tYXhfYnVmZmVyX3NpemUpOworCQlpZiAocmV0IDwgMCkgeworCQkJcHJfZXJyKCIl czogRmFpbGVkIHRvIGRlY29tcHJlc3MgYnVmZmVyXG4iLCBfX2Z1bmNfXyk7CisJCQlyZXR1cm4g LUVJTzsKKwkJfQorCisJCWJ1ZiA9IGdkZy0+d29ya19idWY7CisJCWxlbiA9IHJldDsKKwl9CisK KwlpZiAobGVuICE9IGdkZy0+c2V0X2J1ZmZlcl9sZW5ndGgpIHsKKwkJcHJfZXJyKCIlczogQnVm ZmVyIGxlbiBkaWZmZXJzOiAlenUgIT0gJXp1XG4iLAorCQkgICAgICAgX19mdW5jX18sIGxlbiwg Z2RnLT5zZXRfYnVmZmVyX2xlbmd0aCk7CisJCXJldHVybiAtRUlOVkFMOworCX0KKworCWlmIChs ZW4gPiAoZHJtX3JlY3Rfd2lkdGgocmVjdCkgKiBkcm1fcmVjdF9oZWlnaHQocmVjdCkgKiBmYi0+ Zm9ybWF0LT5jcHBbMF0pKSB7CisJCXByX2VycigiJXM6IEJ1ZmZlciBpcyB0b28gYmlnIGZvciBy ZWN0YW5nbGVcbiIsIF9fZnVuY19fKTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCisJcmVtYWlu ID0gZ3VkX2RybV9nYWRnZXRfd3JpdGVfYnVmZmVyX21lbWNweShidWZmZXIsIGJ1ZiwgbGVuLCBy ZWN0KTsKKwlpZiAocmVtYWluKSB7CisJCXByX2VycigiJXM6IEZhaWxlZCB0byB3cml0ZSBidWZm ZXI6IHJlbWFpbj0lenVcbiIsIF9fZnVuY19fLCByZW1haW4pOworCQlyZXR1cm4gLUVJTzsKKwl9 CisKKwlyZXR1cm4gZHJtX2NsaWVudF9mcmFtZWJ1ZmZlcl9mbHVzaChidWZmZXIsIHJlY3QpOwor fQorRVhQT1JUX1NZTUJPTChndWRfZHJtX2dhZGdldF93cml0ZV9idWZmZXIpOworCitpbnQgZ3Vk X2RybV9nYWRnZXRfc2V0X2J1ZmZlcihzdHJ1Y3QgZ3VkX2RybV9nYWRnZXQgKmdkZywgc3RydWN0 IGd1ZF9kcm1fcmVxX3NldF9idWZmZXIgKnJlcSkKK3sKKwl1MzIgY29tcHJlc3NlZF9sZW5ndGgg PSBsZTMyX3RvX2NwdShyZXEtPmNvbXByZXNzZWRfbGVuZ3RoKTsKKwl1MzIgbGVuZ3RoID0gbGUz Ml90b19jcHUocmVxLT5sZW5ndGgpOworCXN0cnVjdCBkcm1fY2xpZW50X2J1ZmZlciAqYnVmZmVy OworCXN0cnVjdCBkcm1fcmVjdCByZWN0OworCWludCByZXQgPSAwOworCisJaWYgKCFyZWZjb3Vu dF9pbmNfbm90X3plcm8oJmdkZy0+dXNlY250KSkKKwkJcmV0dXJuIC1FTk9ERVY7CisKKwlidWZm ZXIgPSBnZGctPmJ1ZmZlciA/IGdkZy0+YnVmZmVyIDogZ2RnLT5idWZmZXJfY2hlY2s7CisJaWYg KCFidWZmZXIpIHsKKwkJcmV0ID0gLUVOT0VOVDsKKwkJZ290byBvdXQ7CisJfQorCisJZHJtX3Jl Y3RfaW5pdCgmcmVjdCwgbGUzMl90b19jcHUocmVxLT54KSwgbGUzMl90b19jcHUocmVxLT55KSwK KwkJICAgICAgbGUzMl90b19jcHUocmVxLT53aWR0aCksIGxlMzJfdG9fY3B1KHJlcS0+aGVpZ2h0 KSk7CisKKwlwcl9kZWJ1ZygiJXM6ICIgRFJNX1JFQ1RfRk1UICJcbiIsIF9fZnVuY19fLCBEUk1f UkVDVF9BUkcoJnJlY3QpKTsKKworCWlmICghZ3VkX2RybV9nYWRnZXRfY2hlY2tfcmVjdChidWZm ZXIsICZyZWN0KSkgeworCQlyZXQgPSAtRUlOVkFMOworCQlnb3RvIG91dDsKKwl9CisKKwlpZiAo cmVxLT5jb21wcmVzc2lvbiAmIH5HVURfRFJNX0NPTVBSRVNTSU9OX0xaNCkgeworCQlyZXQgPSAt RUlOVkFMOworCQlnb3RvIG91dDsKKwl9CisKKwlnZGctPnNldF9idWZmZXJfcmVjdCA9IHJlY3Q7 CisJZ2RnLT5zZXRfYnVmZmVyX2xlbmd0aCA9IGxlbmd0aDsKKworCWlmIChyZXEtPmNvbXByZXNz aW9uKSB7CisJCWlmICghY29tcHJlc3NlZF9sZW5ndGgpIHsKKwkJCXJldCA9IC1FSU5WQUw7CisJ CQlnb3RvIG91dDsKKwkJfQorCQlnZGctPnNldF9idWZmZXJfY29tcHJlc3Npb24gPSByZXEtPmNv bXByZXNzaW9uOworCQlnZGctPnNldF9idWZmZXJfY29tcHJlc3NlZF9sZW5ndGggPSBjb21wcmVz c2VkX2xlbmd0aDsKKwkJbGVuZ3RoID0gY29tcHJlc3NlZF9sZW5ndGg7CisJfSBlbHNlIHsKKwkJ Z2RnLT5zZXRfYnVmZmVyX2NvbXByZXNzaW9uID0gMDsKKwkJZ2RnLT5zZXRfYnVmZmVyX2NvbXBy ZXNzZWRfbGVuZ3RoID0gMDsKKwl9CitvdXQ6CisJcmVmY291bnRfZGVjKCZnZGctPnVzZWNudCk7 CisKKwlyZXR1cm4gcmV0ID8gcmV0IDogbGVuZ3RoOworfQorRVhQT1JUX1NZTUJPTChndWRfZHJt X2dhZGdldF9zZXRfYnVmZmVyKTsKKworc3RhdGljIHZvaWQgZ3VkX2RybV9nYWRnZXRfZGVsZXRl X2J1ZmZlcnMoc3RydWN0IGd1ZF9kcm1fZ2FkZ2V0ICpnZGcpCit7CisJZHJtX2NsaWVudF9mcmFt ZWJ1ZmZlcl9kZWxldGUoZ2RnLT5idWZmZXJfY2hlY2spOworCWRybV9jbGllbnRfZnJhbWVidWZm ZXJfZGVsZXRlKGdkZy0+YnVmZmVyKTsKKwlnZGctPmJ1ZmZlcl9jaGVjayA9IE5VTEw7CisJZ2Rn LT5idWZmZXIgPSBOVUxMOworfQorCitpbnQgZ3VkX2RybV9nYWRnZXRfZGlzYWJsZV9waXBlKHN0 cnVjdCBndWRfZHJtX2dhZGdldCAqZ2RnKQoreworCWludCByZXQ7CisKKwlkcm1fY2xpZW50X21v ZGVzZXRfc2V0KCZnZGctPmNsaWVudCwgTlVMTCwgTlVMTCwgTlVMTCk7CisJcmV0ID0gZHJtX2Ns aWVudF9tb2Rlc2V0X2NvbW1pdCgmZ2RnLT5jbGllbnQpOworCWlmIChyZXQpCisJCXJldHVybiBy ZXQ7CisKKwlndWRfZHJtX2dhZGdldF9kZWxldGVfYnVmZmVycyhnZGcpOworCisJcmV0dXJuIDA7 Cit9CitFWFBPUlRfU1lNQk9MKGd1ZF9kcm1fZ2FkZ2V0X2Rpc2FibGVfcGlwZSk7CisKK3N0YXRp YyBpbnQgZ3VkX2RybV9nYWRnZXRfY3RybF9nZXRfZGlzcGxheV9kZXNjcmlwdG9yKHN0cnVjdCBn dWRfZHJtX2dhZGdldCAqZ2RnLCB1MTYgdmFsdWUsCisJCQkJCQkgICAgICB2b2lkICpkYXRhLCBz aXplX3Qgc2l6ZSkKK3sKKwlzdHJ1Y3QgZHJtX2RldmljZSAqZHJtID0gZ2RnLT5jbGllbnQuZGV2 OworCXN0cnVjdCBndWRfZHJtX2Rpc3BsYXlfZGVzY3JpcHRvciBkZXNjOworCXU4IHR5cGUgPSB2 YWx1ZSA+PiA4OworCXU4IGluZGV4ID0gdmFsdWUgJiAweGZmOworCisJaWYgKHR5cGUgIT0gR1VE X0RSTV9VU0JfRFRfRElTUExBWSB8fCBpbmRleCkKKwkJcmV0dXJuIC1FSU5WQUw7CisKKwlkZXNj LmJMZW5ndGggPSBzaXplb2YoZGVzYyk7CisJZGVzYy5iRGVzY3JpcHRvclR5cGUgPSBHVURfRFJN X1VTQl9EVF9ESVNQTEFZOworCisJZGVzYy5iVmVyc2lvbiA9IDE7CisJZGVzYy5iTWF4QnVmZmVy U2l6ZU9yZGVyID0gaWxvZzIoZ2RnLT5tYXhfYnVmZmVyX3NpemUpOworCWRlc2MuYm1GbGFncyA9 IDA7CisJZGVzYy5iQ29tcHJlc3Npb24gPSBHVURfRFJNX0NPTVBSRVNTSU9OX0xaNDsKKworCWRl c2MuZHdNaW5XaWR0aCA9IGNwdV90b19sZTMyKGRybS0+bW9kZV9jb25maWcubWluX3dpZHRoKTsK KwlkZXNjLmR3TWF4V2lkdGggPSBjcHVfdG9fbGUzMihkcm0tPm1vZGVfY29uZmlnLm1heF93aWR0 aCk7CisJZGVzYy5kd01pbkhlaWdodCA9IGNwdV90b19sZTMyKGRybS0+bW9kZV9jb25maWcubWlu X2hlaWdodCk7CisJZGVzYy5kd01heEhlaWdodCA9IGNwdV90b19sZTMyKGRybS0+bW9kZV9jb25m aWcubWF4X2hlaWdodCk7CisJZGVzYy5iTnVtRm9ybWF0cyA9IGdkZy0+Zm9ybWF0X2NvdW50Owor CWRlc2MuYk51bVByb3BlcnRpZXMgPSBnZGctPm51bV9wcm9wZXJ0aWVzOworCWRlc2MuYk51bUNv bm5lY3RvcnMgPSBnZGctPmNvbm5lY3Rvcl9jb3VudDsKKworCXNpemUgPSBtaW4oc2l6ZSwgc2l6 ZW9mKGRlc2MpKTsKKwltZW1jcHkoZGF0YSwgJmRlc2MsIHNpemUpOworCisJcmV0dXJuIHNpemU7 Cit9CisKK3N0YXRpYyB2b2lkIGd1ZF9kcm1fZ2FkZ2V0X2N0cmxfZ2V0X2Zvcm1hdHMoc3RydWN0 IGd1ZF9kcm1fZ2FkZ2V0ICpnZGcsIF9fbGUzMiAqZm9ybWF0cykKK3sKKwl1bnNpZ25lZCBpbnQg aTsKKworCWZvciAoaSA9IDA7IGkgPCBnZGctPmZvcm1hdF9jb3VudDsgaSsrKQorCQlmb3JtYXRz W2ldID0gY3B1X3RvX2xlMzIoZ2RnLT5mb3JtYXRzW2ldKTsKK30KKworc3RhdGljIGludCBndWRf ZHJtX2dhZGdldF9jdHJsX2dldF9jb25uZWN0b3Ioc3RydWN0IGd1ZF9kcm1fZ2FkZ2V0ICpnZGcs IHVuc2lnbmVkIGludCBpbmRleCwKKwkJCQkJICAgICBzdHJ1Y3QgZ3VkX2RybV9yZXFfZ2V0X2Nv bm5lY3RvciAqZGVzYykKK3sKKwlzdHJ1Y3QgZ3VkX2RybV9nYWRnZXRfY29ubmVjdG9yICpnY29u bjsKKworCWlmIChpbmRleCA+PSBnZGctPmNvbm5lY3Rvcl9jb3VudCkKKwkJcmV0dXJuIC1FSU5W QUw7CisKKwltZW1zZXQoZGVzYywgMCwgc2l6ZW9mKCpkZXNjKSk7CisKKwlnY29ubiA9ICZnZGct PmNvbm5lY3RvcnNbaW5kZXhdOworCisJZGVzYy0+Y29ubmVjdG9yX3R5cGUgPSBnY29ubi0+Y29u bmVjdG9yLT5jb25uZWN0b3JfdHlwZTsKKwlkZXNjLT5mbGFncyA9IGNwdV90b19sZTMyKEdVRF9E Uk1fQ09OTkVDVE9SX0ZMQUdTX1BPTEwpOworCWRlc2MtPm51bV9wcm9wZXJ0aWVzID0gZ2Nvbm4t Pm51bV9wcm9wZXJ0aWVzOworCisJcmV0dXJuIDA7Cit9CisKK3N0YXRpYyBzdHJ1Y3QgZ3VkX2Ry bV9nYWRnZXRfY29ubmVjdG9yICoKK2d1ZF9kcm1fZ2FkZ2V0X2dldF9nY29ubihzdHJ1Y3QgZ3Vk X2RybV9nYWRnZXQgKmdkZywgdW5zaWduZWQgaW50IGluZGV4KQoreworCWlmIChpbmRleCA+PSBn ZGctPmNvbm5lY3Rvcl9jb3VudCkKKwkJcmV0dXJuIE5VTEw7CisKKwlyZXR1cm4gJmdkZy0+Y29u bmVjdG9yc1tpbmRleF07Cit9CisKK3N0YXRpYyBpbnQgZ3VkX2RybV9nYWRnZXRfY3RybF9nZXRf Y29ubmVjdG9yX3N0YXR1cyhzdHJ1Y3QgZ3VkX2RybV9nYWRnZXQgKmdkZywgdW5zaWduZWQgaW50 IGluZGV4LAorCQkJCQkJICAgIHN0cnVjdCBndWRfZHJtX3JlcV9nZXRfY29ubmVjdG9yX3N0YXR1 cyAqc3RhdHVzKQoreworCXN0cnVjdCBndWRfZHJtX2dhZGdldF9jb25uZWN0b3IgKmdjb25uOwor CXVuc2lnbmVkIGxvbmcgZmxhZ3M7CisKKwlnY29ubiA9IGd1ZF9kcm1fZ2FkZ2V0X2dldF9nY29u bihnZGcsIGluZGV4KTsKKwlpZiAoIWdjb25uKQorCQlyZXR1cm4gLUVOT0VOVDsKKworCW1lbXNl dChzdGF0dXMsIDAsIHNpemVvZigqc3RhdHVzKSk7CisKKwlzcGluX2xvY2tfaXJxc2F2ZSgmZ2Nv bm4tPmxvY2ssIGZsYWdzKTsKKwlzdGF0dXMtPnN0YXR1cyA9IGdjb25uLT5zdGF0dXM7CisJaWYg KGdjb25uLT5jaGFuZ2VkKSB7CisJCXN0YXR1cy0+c3RhdHVzIHw9IEdVRF9EUk1fQ09OTkVDVE9S X1NUQVRVU19DSEFOR0VEOworCQlnY29ubi0+Y2hhbmdlZCA9IGZhbHNlOworCX0KKwlpZiAoZ2Nv bm4tPm51bV9tb2RlcykKKwkJc3RhdHVzLT5udW1fbW9kZXMgPSBjcHVfdG9fbGUxNihnY29ubi0+ bnVtX21vZGVzKTsKKwlpZiAoZ2Nvbm4tPmVkaWRfbGVuKQorCQlzdGF0dXMtPmVkaWRfbGVuID0g Y3B1X3RvX2xlMTYoZ2Nvbm4tPmVkaWRfbGVuKTsKKwlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZn Y29ubi0+bG9jaywgZmxhZ3MpOworCisJcmV0dXJuIDA7Cit9CisKKy8qIFRoaXMgcnVucyBpbiBp bnRlcnJ1cHQgY29udGV4dCAqLworaW50IGd1ZF9kcm1fZ2FkZ2V0X2N0cmxfZ2V0KHN0cnVjdCBn dWRfZHJtX2dhZGdldCAqZ2RnLCB1OCByZXF1ZXN0LAorCQkJICAgIHUxNiBpbmRleCwgdm9pZCAq ZGF0YSwgc2l6ZV90IHNpemUpCit7CisJc3RydWN0IGd1ZF9kcm1fZ2FkZ2V0X2Nvbm5lY3RvciAq Z2Nvbm47CisJdW5zaWduZWQgbG9uZyBmbGFnczsKKwlpbnQgcmV0ID0gLUVJTlZBTDsKKworCXBy X2RlYnVnKCIlczogcmVxdWVzdD0weCV4IGluZGV4PSV1IHNpemU9JXp1XG4iLCBfX2Z1bmNfXywg cmVxdWVzdCwgaW5kZXgsIHNpemUpOworCisJaWYgKCFyZWZjb3VudF9pbmNfbm90X3plcm8oJmdk Zy0+dXNlY250KSkKKwkJcmV0dXJuIC1FTk9ERVY7CisKKwlpZiAoIXNpemUpCisJCWdvdG8gb3V0 OworCisJc3dpdGNoIChyZXF1ZXN0KSB7CisJY2FzZSBVU0JfUkVRX0dFVF9ERVNDUklQVE9SOgor CQlyZXQgPSBndWRfZHJtX2dhZGdldF9jdHJsX2dldF9kaXNwbGF5X2Rlc2NyaXB0b3IoZ2RnLCBp bmRleCwgZGF0YSwgc2l6ZSk7CisJCWJyZWFrOworCWNhc2UgR1VEX0RSTV9VU0JfUkVRX0dFVF9G T1JNQVRTOgorCQlpZiAoIWluZGV4ICYmIHNpemUgPT0gZ2RnLT5mb3JtYXRfY291bnQgKiBzaXpl b2YodTMyKSkgeworCQkJZ3VkX2RybV9nYWRnZXRfY3RybF9nZXRfZm9ybWF0cyhnZGcsIGRhdGEp OworCQkJcmV0ID0gMDsKKwkJfQorCQlicmVhazsKKwljYXNlIEdVRF9EUk1fVVNCX1JFUV9HRVRf UFJPUEVSVElFUzoKKwkJaWYgKCFpbmRleCAmJiBzaXplID09IGdkZy0+bnVtX3Byb3BlcnRpZXMg KiBzaXplb2YoKmdkZy0+cHJvcGVydGllcykpIHsKKwkJCW1lbWNweShkYXRhLCBnZGctPnByb3Bl cnRpZXMsIHNpemUpOworCQkJcmV0ID0gMDsKKwkJfQorCQlicmVhazsKKwljYXNlIEdVRF9EUk1f VVNCX1JFUV9HRVRfQ09OTkVDVE9SOgorCQlpZiAoc2l6ZSA9PSBzaXplb2Yoc3RydWN0IGd1ZF9k cm1fcmVxX2dldF9jb25uZWN0b3IpKQorCQkJcmV0ID0gZ3VkX2RybV9nYWRnZXRfY3RybF9nZXRf Y29ubmVjdG9yKGdkZywgaW5kZXgsIGRhdGEpOworCQlicmVhazsKKwljYXNlIEdVRF9EUk1fVVNC X1JFUV9HRVRfQ09OTkVDVE9SX1BST1BFUlRJRVM6CisJCWdjb25uID0gZ3VkX2RybV9nYWRnZXRf Z2V0X2djb25uKGdkZywgaW5kZXgpOworCQlpZiAoZ2Nvbm4gJiYgc2l6ZSA9PSBnY29ubi0+bnVt X3Byb3BlcnRpZXMgKiBzaXplb2YoKmdjb25uLT5wcm9wZXJ0aWVzKSkgeworCQkJbWVtY3B5KGRh dGEsIGdjb25uLT5wcm9wZXJ0aWVzLCBzaXplKTsKKwkJCXJldCA9IDA7CisJCX0KKwkJYnJlYWs7 CisJY2FzZSBHVURfRFJNX1VTQl9SRVFfR0VUX0NPTk5FQ1RPUl9UVl9NT0RFX1ZBTFVFUzoKKwkJ Z2Nvbm4gPSBndWRfZHJtX2dhZGdldF9nZXRfZ2Nvbm4oZ2RnLCBpbmRleCk7CisJCWlmIChnY29u biAmJiBzaXplID09IGdjb25uLT5udW1fdHZfbW9kZV9lbnVtX25hbWVzICogRFJNX1BST1BfTkFN RV9MRU4pIHsKKwkJCW1lbWNweShkYXRhLCBnY29ubi0+dHZfbW9kZV9lbnVtX25hbWVzLCBzaXpl KTsKKwkJCXJldCA9IDA7CisJCX0KKwkJYnJlYWs7CisJY2FzZSBHVURfRFJNX1VTQl9SRVFfR0VU X0NPTk5FQ1RPUl9TVEFUVVM6CisJCWlmIChzaXplID09IHNpemVvZihzdHJ1Y3QgZ3VkX2RybV9y ZXFfZ2V0X2Nvbm5lY3Rvcl9zdGF0dXMpKQorCQkJcmV0ID0gZ3VkX2RybV9nYWRnZXRfY3RybF9n ZXRfY29ubmVjdG9yX3N0YXR1cyhnZGcsIGluZGV4LCBkYXRhKTsKKwkJYnJlYWs7CisJY2FzZSBH VURfRFJNX1VTQl9SRVFfR0VUX0NPTk5FQ1RPUl9NT0RFUzoKKwkJZ2Nvbm4gPSBndWRfZHJtX2dh ZGdldF9nZXRfZ2Nvbm4oZ2RnLCBpbmRleCk7CisJCXNwaW5fbG9ja19pcnFzYXZlKCZnY29ubi0+ bG9jaywgZmxhZ3MpOworCQlpZiAoZ2Nvbm4gJiYgc2l6ZSA9PSBnY29ubi0+bnVtX21vZGVzICog c2l6ZW9mKCpnY29ubi0+bW9kZXMpKSB7CisJCQltZW1jcHkoZGF0YSwgZ2Nvbm4tPm1vZGVzLCBz aXplKTsKKwkJCXJldCA9IDA7CisJCX0KKwkJc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgmZ2Nvbm4t PmxvY2ssIGZsYWdzKTsKKwkJYnJlYWs7CisJY2FzZSBHVURfRFJNX1VTQl9SRVFfR0VUX0NPTk5F Q1RPUl9FRElEOgorCQlnY29ubiA9IGd1ZF9kcm1fZ2FkZ2V0X2dldF9nY29ubihnZGcsIGluZGV4 KTsKKwkJc3Bpbl9sb2NrX2lycXNhdmUoJmdjb25uLT5sb2NrLCBmbGFncyk7CisJCWlmIChnY29u biAmJiBzaXplID09IGdjb25uLT5lZGlkX2xlbikgeworCQkJbWVtY3B5KGRhdGEsIGdjb25uLT5l ZGlkLCBzaXplKTsKKwkJCXJldCA9IDA7CisJCX0KKwkJc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgm Z2Nvbm4tPmxvY2ssIGZsYWdzKTsKKwkJYnJlYWs7CisJfQorb3V0OgorCXJlZmNvdW50X2RlYygm Z2RnLT51c2VjbnQpOworCisJcmV0dXJuICFyZXQgPyBzaXplIDogcmV0OworfQorRVhQT1JUX1NZ TUJPTChndWRfZHJtX2dhZGdldF9jdHJsX2dldCk7CisKK2ludCBndWRfZHJtX2dhZGdldF9jdHJs X3NldChzdHJ1Y3QgZ3VkX2RybV9nYWRnZXQgKmdkZywgdTggcmVxdWVzdCwKKwkJCSAgICB1MTYg aW5kZXgsIHZvaWQgKmRhdGEsIHNpemVfdCBzaXplKQoreworCXN0cnVjdCBndWRfZHJtX2dhZGdl dF9jb25uZWN0b3IgKmdjb25uOworCWludCBkcG1zLCByZXQgPSAtRUlOVkFMOworCisJcHJfZGVi dWcoIiVzOiByZXF1ZXN0PTB4JXggaW5kZXg9JXUgc2l6ZT0lenVcbiIsIF9fZnVuY19fLCByZXF1 ZXN0LCBpbmRleCwgc2l6ZSk7CisKKwlpZiAoIXJlZmNvdW50X2luY19ub3RfemVybygmZ2RnLT51 c2VjbnQpKQorCQlyZXR1cm4gLUVOT0RFVjsKKworCXN3aXRjaCAocmVxdWVzdCkgeworCWNhc2Ug R1VEX0RSTV9VU0JfUkVRX1NFVF9DT05ORUNUT1JfRk9SQ0VfREVURUNUOgorCQlnY29ubiA9IGd1 ZF9kcm1fZ2FkZ2V0X2dldF9nY29ubihnZGcsIGluZGV4KTsKKwkJaWYgKGdjb25uKQorCQkJcmV0 ID0gZ3VkX2RybV9nYWRnZXRfcHJvYmVfY29ubmVjdG9yKGdjb25uKTsKKwkJYnJlYWs7CisJY2Fz ZSBHVURfRFJNX1VTQl9SRVFfU0VUX1NUQVRFX0NIRUNLOgorCQlyZXQgPSBndWRfZHJtX2dhZGdl dF9jaGVjayhnZGcsIGRhdGEsIHNpemUpOworCQlicmVhazsKKwljYXNlIEdVRF9EUk1fVVNCX1JF UV9TRVRfU1RBVEVfQ09NTUlUOgorCQlpZiAoIXNpemUpCisJCQlyZXQgPSBndWRfZHJtX2dhZGdl dF9jb21taXQoZ2RnKTsKKwkJYnJlYWs7CisJY2FzZSBHVURfRFJNX1VTQl9SRVFfU0VUX0NPTlRS T0xMRVJfRU5BQkxFOgorCQlpZiAoc2l6ZSA9PSBzaXplb2YodTgpKSB7CisJCQlpZiAoKih1OCAq KWRhdGEgPT0gMCkKKwkJCQlyZXQgPSBndWRfZHJtX2dhZGdldF9kaXNhYmxlX3BpcGUoZ2RnKTsK KwkJCWVsc2UKKwkJCQlyZXQgPSAwOworCQl9CisJCWJyZWFrOworCWNhc2UgR1VEX0RSTV9VU0Jf UkVRX1NFVF9ESVNQTEFZX0VOQUJMRToKKwkJaWYgKHNpemUgPT0gc2l6ZW9mKHU4KSkgeworCQkJ ZHBtcyA9ICoodTggKilkYXRhID8gRFJNX01PREVfRFBNU19PTiA6IERSTV9NT0RFX0RQTVNfT0ZG OworCQkJcmV0ID0gZHJtX2NsaWVudF9tb2Rlc2V0X2RwbXMoJmdkZy0+Y2xpZW50LCBkcG1zKTsK KwkJfQorCQlicmVhazsKKwl9CisKKwlyZWZjb3VudF9kZWMoJmdkZy0+dXNlY250KTsKKworCXJl dHVybiByZXQ7Cit9CitFWFBPUlRfU1lNQk9MKGd1ZF9kcm1fZ2FkZ2V0X2N0cmxfc2V0KTsKKwor c3RhdGljIGludCBndWRfZHJtX2dhZGdldF9nZXRfZm9ybWF0cyhzdHJ1Y3QgZ3VkX2RybV9nYWRn ZXQgKmdkZywgdTggKm1heF9jcHApCit7CisJc3RydWN0IGRybV9kZXZpY2UgKmRybSA9IGdkZy0+ Y2xpZW50LmRldjsKKwlzdHJ1Y3QgZHJtX3BsYW5lICpwbGFuZTsKKwl1bnNpZ25lZCBpbnQgaTsK Kwl1MzIgKmZvcm1hdHM7CisJaW50IHJldDsKKworCSptYXhfY3BwID0gMDsKKworCWRybV9mb3Jf ZWFjaF9wbGFuZShwbGFuZSwgZHJtKSB7CisJCWlmIChwbGFuZS0+dHlwZSA9PSBEUk1fUExBTkVf VFlQRV9QUklNQVJZKQorCQkJYnJlYWs7CisJfQorCisJZm9ybWF0cyA9IGtjYWxsb2MocGxhbmUt PmZvcm1hdF9jb3VudCwgc2l6ZW9mKHUzMiksIEdGUF9LRVJORUwpOworCWlmICghZm9ybWF0cykK KwkJcmV0dXJuIC1FTk9NRU07CisKKwlmb3IgKGkgPSAwOyBpIDwgcGxhbmUtPmZvcm1hdF9jb3Vu dDsgaSsrKSB7CisJCWNvbnN0IHN0cnVjdCBkcm1fZm9ybWF0X2luZm8gKmZtdDsKKworCQlmbXQg PSBkcm1fZm9ybWF0X2luZm8ocGxhbmUtPmZvcm1hdF90eXBlc1tpXSk7CisJCWlmIChmbXQtPm51 bV9wbGFuZXMgIT0gMSkKKwkJCWNvbnRpbnVlOworCisJCS8qCisJCSAqIFN1cHBvcnRpbmcgMjQt Yml0IGJwcCB3b3VsZCBhZGQgY29tcGxleGl0eSBzbyBkb24ndCBib3RoZXIuCisJCSAqIEl0J3Mg aGFyZGx5IHVzZWQgYW5kIGNvbXByZXNzaW9uIHJlbW92ZXMgbXVjaCBvZiB0aGUgZ2Fpbi4KKwkJ ICovCisJCWlmIChmbXQtPmNwcFswXSA9PSAzKQorCQkJY29udGludWU7CisKKwkJaWYgKCptYXhf Y3BwIDwgZm10LT5jcHBbMF0pCisJCQkqbWF4X2NwcCA9IGZtdC0+Y3BwWzBdOworCisJCWZvcm1h dHNbZ2RnLT5mb3JtYXRfY291bnQrK10gPSBwbGFuZS0+Zm9ybWF0X3R5cGVzW2ldOworCX0KKwor CWlmICghZ2RnLT5mb3JtYXRfY291bnQpIHsKKwkJcmV0ID0gLUVOT0VOVDsKKwkJZ290byBlcnJf ZnJlZTsKKwl9CisKKwlnZGctPmZvcm1hdHMgPSBmb3JtYXRzOworCisJcmV0dXJuIDA7CisKK2Vy cl9mcmVlOgorCWtmcmVlKGZvcm1hdHMpOworCisJcmV0dXJuIHJldDsKK30KKworc3RhdGljIGlu dCBndWRfZHJtX2dhZGdldF9nZXRfcm90YXRpb25fcHJvcGVydHkoc3RydWN0IGRybV9kZXZpY2Ug KmRybSwgdTE2ICpwcm9wLCB1NjQgKnZhbCkKK3sKKwlzdHJ1Y3QgZHJtX3Byb3BlcnR5X2VudW0g KnByb3BfZW51bTsKKwlzdHJ1Y3QgZHJtX3BsYW5lICpwbGFuZTsKKwl1bnNpZ25lZCBpbnQgbnVt X3Byb3BzID0gMDsKKwl1MTYgYml0bWFzayA9IDA7CisKKwlkcm1fZm9yX2VhY2hfcGxhbmUocGxh bmUsIGRybSkgeworCQlpZiAocGxhbmUtPnR5cGUgPT0gRFJNX1BMQU5FX1RZUEVfUFJJTUFSWSkK KwkJCWJyZWFrOworCX0KKworCWlmICghcGxhbmUtPnJvdGF0aW9uX3Byb3BlcnR5KQorCQlyZXR1 cm4gMDsKKworCWxpc3RfZm9yX2VhY2hfZW50cnkocHJvcF9lbnVtLCAmcGxhbmUtPnJvdGF0aW9u X3Byb3BlcnR5LT5lbnVtX2xpc3QsIGhlYWQpIHsKKwkJbnVtX3Byb3BzKys7CisJCWJpdG1hc2sg fD0gQklUKHByb3BfZW51bS0+dmFsdWUpOworCX0KKworCSpwcm9wID0gR1VEX0RSTV9QUk9QRVJU WV9ST1RBVElPTjsKKwkqdmFsID0gYml0bWFzazsKKworCXJldHVybiAxOworfQorCitzdGF0aWMg aW50IGd1ZF9kcm1fZ2FkZ2V0X2dldF9wcm9wZXJ0aWVzKHN0cnVjdCBndWRfZHJtX2dhZGdldCAq Z2RnKQoreworCXN0cnVjdCBndWRfZHJtX3Byb3BlcnR5ICpwcm9wZXJ0aWVzOworCXUxNiBwcm9w OworCXU2NCB2YWw7CisJaW50IHJldDsKKworCXJldCA9IGd1ZF9kcm1fZ2FkZ2V0X2dldF9yb3Rh dGlvbl9wcm9wZXJ0eShnZGctPmNsaWVudC5kZXYsICZwcm9wLCAmdmFsKTsKKwlpZiAocmV0IDw9 IDApCisJCXJldHVybiByZXQ7CisKKwlwcm9wZXJ0aWVzID0ga2NhbGxvYygxLCBzaXplb2YoKnBy b3BlcnRpZXMpLCBHRlBfS0VSTkVMKTsKKwlpZiAoIXByb3BlcnRpZXMpCisJCXJldHVybiAtRU5P TUVNOworCisJZ2RnLT5wcm9wZXJ0aWVzID0gcHJvcGVydGllczsKKwlnZGctPm51bV9wcm9wZXJ0 aWVzKys7CisKKwlwcm9wZXJ0aWVzWzBdLnByb3AgPSBjcHVfdG9fbGUxNihwcm9wKTsKKwlwcm9w ZXJ0aWVzWzBdLnZhbCA9IGNwdV90b19sZTY0KHZhbCk7CisKKwlyZXR1cm4gMDsKK30KKworc3Rh dGljIGludCBndWRfZHJtX2dhZGdldF9nZXRfY29ubmVjdG9yX3Byb3BlcnRpZXMoc3RydWN0IGd1 ZF9kcm1fZ2FkZ2V0ICpnZGcsCisJCQkJCQkgICBzdHJ1Y3QgZ3VkX2RybV9nYWRnZXRfY29ubmVj dG9yICpnY29ubikKK3sKKwlzdHJ1Y3QgZHJtX2RldmljZSAqZHJtID0gZ2RnLT5jbGllbnQuZGV2 OworCXN0cnVjdCBkcm1fbW9kZV9jb25maWcgKmNvbmZpZyA9ICZkcm0tPm1vZGVfY29uZmlnOwor CXN0cnVjdCBkcm1fY29ubmVjdG9yICpjb25uZWN0b3IgPSBnY29ubi0+Y29ubmVjdG9yOworCXN0 cnVjdCBkcm1fb2JqZWN0X3Byb3BlcnRpZXMgKmNvbm5fcHJvcHMgPSBjb25uZWN0b3ItPmJhc2Uu cHJvcGVydGllczsKKwlzdHJ1Y3QgZ3VkX2RybV9wcm9wZXJ0eSAqcHJvcGVydGllczsKKwl1bnNp Z25lZCBpbnQgaSwgcmV0ID0gMDsKKwl1MTYgcHJvcDsKKwl1NjQgdmFsOworCisJbXV0ZXhfbG9j aygmZHJtLT5tb2RlX2NvbmZpZy5tdXRleCk7CisKKwlpZiAoIWNvbm5fcHJvcHMtPmNvdW50KQor CQlnb3RvIHVubG9jazsKKworCS8qIEFkZCByb29tIGZvciBwb3NzaWJsZSBiYWNrbGlnaHQgKi8K Kwlwcm9wZXJ0aWVzID0ga2NhbGxvYyhjb25uX3Byb3BzLT5jb3VudCArIDEsIHNpemVvZigqcHJv cGVydGllcyksIEdGUF9LRVJORUwpOworCWlmICghcHJvcGVydGllcykgeworCQlyZXQgPSAtRU5P TUVNOworCQlnb3RvIHVubG9jazsKKwl9CisKKwlnY29ubi0+cHJvcGVydGllcyA9IHByb3BlcnRp ZXM7CisKKwlmb3IgKGkgPSAwOyBpIDwgY29ubl9wcm9wcy0+Y291bnQ7IGkrKykgeworCQlzdHJ1 Y3QgZHJtX3Byb3BlcnR5ICpwcm9wZXJ0eSA9IGNvbm5fcHJvcHMtPnByb3BlcnRpZXNbaV07CisK KwkJaWYgKHByb3BlcnR5ID09IGNvbmZpZy0+dHZfc2VsZWN0X3N1YmNvbm5lY3Rvcl9wcm9wZXJ0 eSkgeworCQkJcHJvcCA9IEdVRF9EUk1fUFJPUEVSVFlfVFZfU0VMRUNUX1NVQkNPTk5FQ1RPUjsK KwkJCXZhbCA9IGNvbm5lY3Rvci0+c3RhdGUtPnR2LnN1YmNvbm5lY3RvcjsKKwkJfSBlbHNlIGlm IChwcm9wZXJ0eSA9PSBjb25maWctPnR2X2xlZnRfbWFyZ2luX3Byb3BlcnR5KSB7CisJCQlwcm9w ID0gR1VEX0RSTV9QUk9QRVJUWV9UVl9MRUZUX01BUkdJTjsKKwkJCXZhbCA9IGNvbm5lY3Rvci0+ c3RhdGUtPnR2Lm1hcmdpbnMubGVmdDsKKwkJfSBlbHNlIGlmIChwcm9wZXJ0eSA9PSBjb25maWct PnR2X3JpZ2h0X21hcmdpbl9wcm9wZXJ0eSkgeworCQkJcHJvcCA9IEdVRF9EUk1fUFJPUEVSVFlf VFZfUklHSFRfTUFSR0lOOworCQkJdmFsID0gY29ubmVjdG9yLT5zdGF0ZS0+dHYubWFyZ2lucy5y aWdodDsKKwkJfSBlbHNlIGlmIChwcm9wZXJ0eSA9PSBjb25maWctPnR2X3RvcF9tYXJnaW5fcHJv cGVydHkpIHsKKwkJCXByb3AgPSBHVURfRFJNX1BST1BFUlRZX1RWX1RPUF9NQVJHSU47CisJCQl2 YWwgPSBjb25uZWN0b3ItPnN0YXRlLT50di5tYXJnaW5zLnRvcDsKKwkJfSBlbHNlIGlmIChwcm9w ZXJ0eSA9PSBjb25maWctPnR2X2JvdHRvbV9tYXJnaW5fcHJvcGVydHkpIHsKKwkJCXByb3AgPSBH VURfRFJNX1BST1BFUlRZX1RWX0JPVFRPTV9NQVJHSU47CisJCQl2YWwgPSBjb25uZWN0b3ItPnN0 YXRlLT50di5tYXJnaW5zLmJvdHRvbTsKKwkJfSBlbHNlIGlmIChwcm9wZXJ0eSA9PSBjb25maWct PnR2X21vZGVfcHJvcGVydHkpIHsKKwkJCXN0cnVjdCBkcm1fcHJvcGVydHlfZW51bSAqcHJvcF9l bnVtOworCQkJY2hhciAqYnVmOworCisJCQlsaXN0X2Zvcl9lYWNoX2VudHJ5KHByb3BfZW51bSwg JnByb3BlcnR5LT5lbnVtX2xpc3QsIGhlYWQpCisJCQkJZ2Nvbm4tPm51bV90dl9tb2RlX2VudW1f bmFtZXMrKzsKKworCQkJaWYgKFdBUk5fT04oIWdjb25uLT5udW1fdHZfbW9kZV9lbnVtX25hbWVz KSkgeworCQkJCXJldCA9IC1FSU5WQUw7CisJCQkJZ290byB1bmxvY2s7CisJCQl9CisKKwkJCWJ1 ZiA9IGtjYWxsb2MoZ2Nvbm4tPm51bV90dl9tb2RlX2VudW1fbmFtZXMsIERSTV9QUk9QX05BTUVf TEVOLCBHRlBfS0VSTkVMKTsKKwkJCWlmICghYnVmKSB7CisJCQkJcmV0ID0gLUVOT01FTTsKKwkJ CQlnb3RvIHVubG9jazsKKwkJCX0KKworCQkJZ2Nvbm4tPnR2X21vZGVfZW51bV9uYW1lcyA9IGJ1 ZjsKKworCQkJbGlzdF9mb3JfZWFjaF9lbnRyeShwcm9wX2VudW0sICZwcm9wZXJ0eS0+ZW51bV9s aXN0LCBoZWFkKSB7CisJCQkJc3RybmNweShidWYsIHByb3BfZW51bS0+bmFtZSwgRFJNX1BST1Bf TkFNRV9MRU4pOworCQkJCWJ1ZiArPSBEUk1fUFJPUF9OQU1FX0xFTjsKKwkJCX0KKworCQkJcHJv cCA9IEdVRF9EUk1fUFJPUEVSVFlfVFZfTU9ERTsKKwkJCXZhbCA9IGNvbm5lY3Rvci0+c3RhdGUt PnR2Lm1vZGU7CisJCQl2YWwgfD0gZ2Nvbm4tPm51bV90dl9tb2RlX2VudW1fbmFtZXMgPDwgR1VE X0RSTV9VU0JfQ09OTkVDVE9SX1RWX01PREVfTlVNX1NISUZUOworCQl9IGVsc2UgaWYgKHByb3Bl cnR5ID09IGNvbmZpZy0+dHZfYnJpZ2h0bmVzc19wcm9wZXJ0eSkgeworCQkJcHJvcCA9IEdVRF9E Uk1fUFJPUEVSVFlfVFZfQlJJR0hUTkVTUzsKKwkJCXZhbCA9IGNvbm5lY3Rvci0+c3RhdGUtPnR2 LmJyaWdodG5lc3M7CisJCX0gZWxzZSBpZiAocHJvcGVydHkgPT0gY29uZmlnLT50dl9jb250cmFz dF9wcm9wZXJ0eSkgeworCQkJcHJvcCA9IEdVRF9EUk1fUFJPUEVSVFlfVFZfQ09OVFJBU1Q7CisJ CQl2YWwgPSBjb25uZWN0b3ItPnN0YXRlLT50di5jb250cmFzdDsKKwkJfSBlbHNlIGlmIChwcm9w ZXJ0eSA9PSBjb25maWctPnR2X2ZsaWNrZXJfcmVkdWN0aW9uX3Byb3BlcnR5KSB7CisJCQlwcm9w ID0gR1VEX0RSTV9QUk9QRVJUWV9UVl9GTElDS0VSX1JFRFVDVElPTjsKKwkJCXZhbCA9IGNvbm5l Y3Rvci0+c3RhdGUtPnR2LmZsaWNrZXJfcmVkdWN0aW9uOworCQl9IGVsc2UgaWYgKHByb3BlcnR5 ID09IGNvbmZpZy0+dHZfb3ZlcnNjYW5fcHJvcGVydHkpIHsKKwkJCXByb3AgPSBHVURfRFJNX1BS T1BFUlRZX1RWX09WRVJTQ0FOOworCQkJdmFsID0gY29ubmVjdG9yLT5zdGF0ZS0+dHYub3ZlcnNj YW47CisJCX0gZWxzZSBpZiAocHJvcGVydHkgPT0gY29uZmlnLT50dl9zYXR1cmF0aW9uX3Byb3Bl cnR5KSB7CisJCQlwcm9wID0gR1VEX0RSTV9QUk9QRVJUWV9UVl9TQVRVUkFUSU9OOworCQkJdmFs ID0gY29ubmVjdG9yLT5zdGF0ZS0+dHYuc2F0dXJhdGlvbjsKKwkJfSBlbHNlIGlmIChwcm9wZXJ0 eSA9PSBjb25maWctPnR2X2h1ZV9wcm9wZXJ0eSkgeworCQkJcHJvcCA9IEdVRF9EUk1fUFJPUEVS VFlfVFZfSFVFOworCQkJdmFsID0gY29ubmVjdG9yLT5zdGF0ZS0+dHYuaHVlOworCQl9IGVsc2Ug eworCQkJY29udGludWU7CisJCX0KKworCQlwcm9wZXJ0aWVzW2djb25uLT5udW1fcHJvcGVydGll c10ucHJvcCA9IGNwdV90b19sZTE2KHByb3ApOworCQlwcm9wZXJ0aWVzW2djb25uLT5udW1fcHJv cGVydGllcysrXS52YWwgPSBjcHVfdG9fbGU2NCh2YWwpOworCX0KKworCWlmICghY29ubmVjdG9y LT5pbmRleCAmJiBnZGctPmJhY2tsaWdodCkgeworCQlzdHJ1Y3QgYmFja2xpZ2h0X3Byb3BlcnRp ZXMgKnByb3BzID0gJmdkZy0+YmFja2xpZ2h0LT5wcm9wczsKKworCQlwcm9wID0gR1VEX0RSTV9Q Uk9QRVJUWV9CQUNLTElHSFRfQlJJR0hUTkVTUzsKKwkJdmFsID0gRElWNjRfVTY0X1JPVU5EX1VQ KHByb3BzLT5icmlnaHRuZXNzICogMTAwLCBwcm9wcy0+bWF4X2JyaWdodG5lc3MpOworCQlwcm9w ZXJ0aWVzW2djb25uLT5udW1fcHJvcGVydGllc10ucHJvcCA9IGNwdV90b19sZTE2KHByb3ApOwor CQlwcm9wZXJ0aWVzW2djb25uLT5udW1fcHJvcGVydGllcysrXS52YWwgPSBjcHVfdG9fbGU2NCh2 YWwpOworCQlnY29ubi0+YmFja2xpZ2h0ID0gZ2RnLT5iYWNrbGlnaHQ7CisJfQordW5sb2NrOgor CW11dGV4X3VubG9jaygmZHJtLT5tb2RlX2NvbmZpZy5tdXRleCk7CisKKwlyZXR1cm4gcmV0Owor fQorCitzdGF0aWMgaW50IGd1ZF9kcm1fZ2FkZ2V0X2dldF9jb25uZWN0b3JzKHN0cnVjdCBndWRf ZHJtX2dhZGdldCAqZ2RnKQoreworCXN0cnVjdCBndWRfZHJtX2dhZGdldF9jb25uZWN0b3IgKmNv bm5lY3RvcnMgPSBOVUxMOworCXN0cnVjdCBkcm1fY29ubmVjdG9yX2xpc3RfaXRlciBjb25uX2l0 ZXI7CisJc3RydWN0IGRybV9kZXZpY2UgKmRybSA9IGdkZy0+Y2xpZW50LmRldjsKKwl1bnNpZ25l ZCBpbnQgY29ubmVjdG9yX2NvdW50ID0gMDsKKwlzdHJ1Y3QgZHJtX2Nvbm5lY3RvciAqY29ubmVj dG9yOworCWludCByZXQgPSAwOworCisJZHJtX2Nvbm5lY3Rvcl9saXN0X2l0ZXJfYmVnaW4oZHJt LCAmY29ubl9pdGVyKTsKKwlkcm1fY2xpZW50X2Zvcl9lYWNoX2Nvbm5lY3Rvcl9pdGVyKGNvbm5l Y3RvciwgJmNvbm5faXRlcikgeworCQlzdHJ1Y3QgZ3VkX2RybV9nYWRnZXRfY29ubmVjdG9yICp0 bXAsICpnY29ubjsKKworCQl0bXAgPSBrcmVhbGxvYyhjb25uZWN0b3JzLCAoY29ubmVjdG9yX2Nv dW50ICsgMSkgKiBzaXplb2YoKmNvbm5lY3RvcnMpLAorCQkJICAgICAgIEdGUF9LRVJORUwgfCBf X0dGUF9aRVJPKTsKKwkJaWYgKCF0bXApIHsKKwkJCXJldCA9IC1FTk9NRU07CisJCQlicmVhazsK KwkJfQorCisJCWNvbm5lY3RvcnMgPSB0bXA7CisJCWRybV9jb25uZWN0b3JfZ2V0KGNvbm5lY3Rv cik7CisJCWdjb25uID0gJmNvbm5lY3RvcnNbY29ubmVjdG9yX2NvdW50KytdOworCQlnY29ubi0+ Y29ubmVjdG9yID0gY29ubmVjdG9yOworCQlzcGluX2xvY2tfaW5pdCgmZ2Nvbm4tPmxvY2spOwor CisJCXJldCA9IGd1ZF9kcm1fZ2FkZ2V0X2dldF9jb25uZWN0b3JfcHJvcGVydGllcyhnZGcsIGdj b25uKTsKKwkJaWYgKHJldCkKKwkJCWJyZWFrOworCX0KKwlkcm1fY29ubmVjdG9yX2xpc3RfaXRl cl9lbmQoJmNvbm5faXRlcik7CisKKwlnZGctPmNvbm5lY3RvcnMgPSBjb25uZWN0b3JzOworCWdk Zy0+Y29ubmVjdG9yX2NvdW50ID0gY29ubmVjdG9yX2NvdW50OworCisJcmV0dXJuIHJldDsKK30K Kworc3RhdGljIHZvaWQgZ3VkX2RybV9nYWRnZXRfcmVsZWFzZShzdHJ1Y3Qga3JlZiAqa3JlZikK K3sKKwlzdHJ1Y3QgZ3VkX2RybV9nYWRnZXQgKmdkZyA9IGNvbnRhaW5lcl9vZihrcmVmLCBzdHJ1 Y3QgZ3VkX2RybV9nYWRnZXQsIHJlZmNvdW50KTsKKworCWtmcmVlKGdkZyk7Cit9CisKK3N0YXRp YyB2b2lkIGd1ZF9kcm1fZ2FkZ2V0X3B1dChzdHJ1Y3QgZ3VkX2RybV9nYWRnZXQgKmdkZykKK3sK KwlrcmVmX3B1dCgmZ2RnLT5yZWZjb3VudCwgZ3VkX2RybV9nYWRnZXRfcmVsZWFzZSk7Cit9CisK K3N0YXRpYyB2b2lkIGd1ZF9kcm1fZ2FkZ2V0X2NsaWVudF91bnJlZ2lzdGVyKHN0cnVjdCBkcm1f Y2xpZW50X2RldiAqY2xpZW50KQoreworCXN0cnVjdCBndWRfZHJtX2dhZGdldCAqZ2RnID0gY29u dGFpbmVyX29mKGNsaWVudCwgc3RydWN0IGd1ZF9kcm1fZ2FkZ2V0LCBjbGllbnQpOworCWludCB0 aW1lb3V0ID0gMTAwMDAgLyA1MDsKKwl1bnNpZ25lZCBpbnQgaTsKKworCS8qCisJICogSWYgdXNl Y250IGRvZXNuJ3QgZHJvcCB0byB6ZXJvLCB0cnkgd2FpdGluZyBmb3IgdGhlIGdhZGdldCwgYnV0 IHdlCisJICogY2FuJ3QgYmxvY2sgdGhlIERSTSBkcml2ZXIgZm9yZXZlci4gVGhlIHdvcnN0IGNh c2Ugd2FpdCB0aGUgZ2FkZ2V0IHNpZGUKKwkgKiBjYW4gaGl0IGFyZSB0ZW5zIG9mIHNlY29uZHMg dGhyb3VnaCB0aGUgY2FsbCB0byBkcm1fY2xpZW50X21vZGVzZXRfY29tbWl0KCkuCisJICovCisJ aWYgKHJlZmNvdW50X2RlY19hbmRfdGVzdCgmZ2RnLT51c2VjbnQpKSB7CisJCWZvciAoOyB0aW1l b3V0ICYmIHJlZmNvdW50X3JlYWQoJmdkZy0+dXNlY250KTsgdGltZW91dC0tKQorCQkJbXNsZWVw KDUwKTsKKwl9CisKKwlpZiAoIXRpbWVvdXQpIHsKKwkJcHJfZXJyKCIlczogVGltZW91dCB3YWl0 aW5nIGZvciBnYWRnZXQgc2lkZSwgd2lsbCBsZWFrIG1lbW9yeVxuIiwgX19mdW5jX18pOworCQly ZXR1cm47CisJfQorCisJdmZyZWUoZ2RnLT53b3JrX2J1Zik7CisJa2ZyZWUoZ2RnLT5mb3JtYXRz KTsKKwlrZnJlZShnZGctPnByb3BlcnRpZXMpOworCisJZm9yIChpID0gMDsgaSA8IGdkZy0+Y29u bmVjdG9yX2NvdW50OyBpKyspIHsKKwkJc3RydWN0IGd1ZF9kcm1fZ2FkZ2V0X2Nvbm5lY3RvciAq Z2Nvbm4gPSAmZ2RnLT5jb25uZWN0b3JzW2ldOworCisJCWRybV9jb25uZWN0b3JfcHV0KGdjb25u LT5jb25uZWN0b3IpOworCQlrZnJlZShnY29ubi0+cHJvcGVydGllcyk7CisJCWtmcmVlKGdjb25u LT50dl9tb2RlX2VudW1fbmFtZXMpOworCQlrZnJlZShnY29ubi0+bW9kZXMpOworCQlrZnJlZShn Y29ubi0+ZWRpZCk7CisJfQorCWtmcmVlKGdkZy0+Y29ubmVjdG9ycyk7CisKKwlndWRfZHJtX2dh ZGdldF9kZWxldGVfYnVmZmVycyhnZGcpOworCWRybV9jbGllbnRfcmVsZWFzZShjbGllbnQpOwor CWd1ZF9kcm1fZ2FkZ2V0X3B1dChnZGcpOworfQorCitzdGF0aWMgaW50IGd1ZF9kcm1fZ2FkZ2V0 X2NsaWVudF9ob3RwbHVnKHN0cnVjdCBkcm1fY2xpZW50X2RldiAqY2xpZW50KQoreworCXN0cnVj dCBndWRfZHJtX2dhZGdldCAqZ2RnID0gY29udGFpbmVyX29mKGNsaWVudCwgc3RydWN0IGd1ZF9k cm1fZ2FkZ2V0LCBjbGllbnQpOworCisJZ3VkX2RybV9nYWRnZXRfcHJvYmVfY29ubmVjdG9ycyhn ZGcpOworCisJcmV0dXJuIDA7Cit9CisKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgZHJtX2NsaWVudF9m dW5jcyBnZGdfY2xpZW50X2Z1bmNzID0geworCS5vd25lcgkJPSBUSElTX01PRFVMRSwKKwkudW5y ZWdpc3Rlcgk9IGd1ZF9kcm1fZ2FkZ2V0X2NsaWVudF91bnJlZ2lzdGVyLAorCS5ob3RwbHVnCT0g Z3VkX2RybV9nYWRnZXRfY2xpZW50X2hvdHBsdWcsCit9OworCitzdHJ1Y3QgZ3VkX2RybV9nYWRn ZXQgKmd1ZF9kcm1fZ2FkZ2V0X2luaXQodW5zaWduZWQgaW50IG1pbm9yX2lkLCBjb25zdCBjaGFy ICpiYWNrbGlnaHQsCisJCQkJCSAgIHNpemVfdCAqbWF4X2J1ZmZlcl9zaXplKQoreworCXN0cnVj dCBndWRfZHJtX2dhZGdldCAqZ2RnOworCXU4IG1heF9jcHA7CisJaW50IHJldDsKKworCWdkZyA9 IGt6YWxsb2Moc2l6ZW9mKCpnZGcpLCBHRlBfS0VSTkVMKTsKKwlpZiAoIWdkZykKKwkJcmV0dXJu IEVSUl9QVFIoLUVOT01FTSk7CisKKwlyZXQgPSBkcm1fY2xpZW50X2luaXRfZnJvbV9pZChtaW5v cl9pZCwgJmdkZy0+Y2xpZW50LCAiZ3VkLWRybS1nYWRnZXQiLCAmZ2RnX2NsaWVudF9mdW5jcyk7 CisJaWYgKHJldCkgeworCQlwcl9lcnIoIkZhaWxlZCB0byBhcXVpcmUgbWlub3I9JXVcbiIsIG1p bm9yX2lkKTsKKwkJa2ZyZWUoZ2RnKTsKKwkJcmV0dXJuIEVSUl9QVFIocmV0KTsKKwl9CisKKwly ZWZjb3VudF9zZXQoJmdkZy0+dXNlY250LCAxKTsKKwkvKiBUaGUgRFJNIGRyaXZlciAodGhyb3Vn aCB0aGUgY2xpZW50KSBhbmQgZl9ndWRfZHJtIG5lZWQgb25lIHJlZiBlYWNoICovCisJa3JlZl9p bml0KCZnZGctPnJlZmNvdW50KTsKKwlrcmVmX2dldCgmZ2RnLT5yZWZjb3VudCk7CisKKwlpZiAo YmFja2xpZ2h0KSB7CisJCWdkZy0+YmFja2xpZ2h0ID0gYmFja2xpZ2h0X2RldmljZV9nZXRfYnlf bmFtZShiYWNrbGlnaHQpOworCQlpZiAoIWdkZy0+YmFja2xpZ2h0KSB7CisJCQlwcl9lcnIoIkZh aWxlZCB0byBmaW5kIGJhY2tsaWdodDogJXNcbiIsIGJhY2tsaWdodCk7CisJCQlyZXQgPSAtRU5P REVWOworCQkJZ290byBlcnJvcl9yZWxlYXNlOworCQl9CisJfQorCisJcmV0ID0gZ3VkX2RybV9n YWRnZXRfZ2V0X2Zvcm1hdHMoZ2RnLCAmbWF4X2NwcCk7CisJaWYgKHJldCkgeworCQlwcl9lcnIo IkZhaWxlZCB0byBnZXQgZm9ybWF0c1xuIik7CisJCWdvdG8gZXJyb3JfcmVsZWFzZTsKKwl9CisK KwkqbWF4X2J1ZmZlcl9zaXplID0gZ2RnLT5jbGllbnQuZGV2LT5tb2RlX2NvbmZpZy5tYXhfd2lk dGggKgorCQkJICAgZ2RnLT5jbGllbnQuZGV2LT5tb2RlX2NvbmZpZy5tYXhfaGVpZ2h0ICogbWF4 X2NwcDsKKwkvKiBmX2d1ZF9kcm0gd2lsbCBrbWFsbG9jIGEgYnVmZmVyIG9mIHRoaXMgc2l6ZSAq LworCSptYXhfYnVmZmVyX3NpemUgPSBtaW5fdChzaXplX3QsICptYXhfYnVmZmVyX3NpemUsIEtN QUxMT0NfTUFYX1NJWkUpOworCisJZ2RnLT5tYXhfYnVmZmVyX3NpemUgPSAqbWF4X2J1ZmZlcl9z aXplOworCWdkZy0+d29ya19idWYgPSB2bWFsbG9jKGdkZy0+bWF4X2J1ZmZlcl9zaXplKTsKKwlp ZiAoIWdkZy0+d29ya19idWYpIHsKKwkJcmV0ID0gLUVOT01FTTsKKwkJZ290byBlcnJvcl9yZWxl YXNlOworCX0KKworCXJldCA9IGd1ZF9kcm1fZ2FkZ2V0X2dldF9wcm9wZXJ0aWVzKGdkZyk7CisJ aWYgKHJldCkgeworCQlwcl9lcnIoIkZhaWxlZCB0byBnZXQgcHJvcGVydGllc1xuIik7CisJCWdv dG8gZXJyb3JfcmVsZWFzZTsKKwl9CisKKwlyZXQgPSBndWRfZHJtX2dhZGdldF9nZXRfY29ubmVj dG9ycyhnZGcpOworCWlmIChyZXQpIHsKKwkJcHJfZXJyKCJGYWlsZWQgdG8gZ2V0IGNvbm5lY3Rv cnNcbiIpOworCQlnb3RvIGVycm9yX3JlbGVhc2U7CisJfQorCisJaWYgKCFkcm1fY2xpZW50X3Jl Z2lzdGVyKCZnZGctPmNsaWVudCkpIHsKKwkJcHJfZXJyKCJEUk0gZGV2aWNlIGlzIGdvbmVcbiIp OworCQlyZXQgPSAtRU5PREVWOworCQlnb3RvIGVycm9yX3JlbGVhc2U7CisJfQorCisJZ3VkX2Ry bV9nYWRnZXRfcHJvYmVfY29ubmVjdG9ycyhnZGcpOworCisJcmV0dXJuIGdkZzsKKworZXJyb3Jf cmVsZWFzZToKKwlndWRfZHJtX2dhZGdldF9jbGllbnRfdW5yZWdpc3RlcigmZ2RnLT5jbGllbnQp OworCWd1ZF9kcm1fZ2FkZ2V0X2ZpbmkoZ2RnKTsKKworCXJldHVybiBFUlJfUFRSKHJldCk7Cit9 CitFWFBPUlRfU1lNQk9MKGd1ZF9kcm1fZ2FkZ2V0X2luaXQpOworCit2b2lkIGd1ZF9kcm1fZ2Fk Z2V0X2Zpbmkoc3RydWN0IGd1ZF9kcm1fZ2FkZ2V0ICpnZGcpCit7CisJYmFja2xpZ2h0X3B1dChn ZGctPmJhY2tsaWdodCk7CisJZ3VkX2RybV9nYWRnZXRfcHV0KGdkZyk7Cit9CitFWFBPUlRfU1lN Qk9MKGd1ZF9kcm1fZ2FkZ2V0X2ZpbmkpOworCitNT0RVTEVfQVVUSE9SKCJOb3JhbGYgVHLDuG5u ZXMiKTsKK01PRFVMRV9MSUNFTlNFKCJHUEwiKTsKZGlmZiAtLWdpdCBhL2luY2x1ZGUvZHJtL2d1 ZF9kcm0uaCBiL2luY2x1ZGUvZHJtL2d1ZF9kcm0uaAppbmRleCAxNWJiMzA1NzdiNTcuLjZhZmMz NjkyNzRkMCAxMDA2NDQKLS0tIGEvaW5jbHVkZS9kcm0vZ3VkX2RybS5oCisrKyBiL2luY2x1ZGUv ZHJtL2d1ZF9kcm0uaApAQCAtMzUzLDQgKzM1MywxNyBAQCBzdGF0aWMgaW5saW5lIHZvaWQgZ3Vk X2RybV90b19kaXNwbGF5X21vZGUoc3RydWN0IGRybV9kaXNwbGF5X21vZGUgKmRzdCwKIAlkcm1f bW9kZV9zZXRfbmFtZShkc3QpOwogfQogCitzdHJ1Y3QgZ3VkX2RybV9nYWRnZXQ7CisKK3N0cnVj dCBndWRfZHJtX2dhZGdldCAqZ3VkX2RybV9nYWRnZXRfaW5pdCh1bnNpZ25lZCBpbnQgbWlub3Jf aWQsIGNvbnN0IGNoYXIgKmJhY2tsaWdodCwKKwkJCQkJICAgc2l6ZV90ICptYXhfYnVmZmVyX3Np emUpOwordm9pZCBndWRfZHJtX2dhZGdldF9maW5pKHN0cnVjdCBndWRfZHJtX2dhZGdldCAqZ2Rn KTsKK2ludCBndWRfZHJtX2dhZGdldF9kaXNhYmxlX3BpcGUoc3RydWN0IGd1ZF9kcm1fZ2FkZ2V0 ICpnZGcpOworaW50IGd1ZF9kcm1fZ2FkZ2V0X2N0cmxfZ2V0KHN0cnVjdCBndWRfZHJtX2dhZGdl dCAqZ2RnLCB1OCByZXF1ZXN0LAorCQkJICAgIHUxNiBpbmRleCwgdm9pZCAqZGF0YSwgc2l6ZV90 IHNpemUpOworaW50IGd1ZF9kcm1fZ2FkZ2V0X2N0cmxfc2V0KHN0cnVjdCBndWRfZHJtX2dhZGdl dCAqZ2RnLCB1OCByZXF1ZXN0LAorCQkJICAgIHUxNiBpbmRleCwgdm9pZCAqZGF0YSwgc2l6ZV90 IHNpemUpOworaW50IGd1ZF9kcm1fZ2FkZ2V0X3NldF9idWZmZXIoc3RydWN0IGd1ZF9kcm1fZ2Fk Z2V0ICpnZGcsIHN0cnVjdCBndWRfZHJtX3JlcV9zZXRfYnVmZmVyICpyZXEpOworaW50IGd1ZF9k cm1fZ2FkZ2V0X3dyaXRlX2J1ZmZlcihzdHJ1Y3QgZ3VkX2RybV9nYWRnZXQgKmdkZywgY29uc3Qg dm9pZCAqYnVmLCBzaXplX3QgbGVuKTsKKwogI2VuZGlmCi0tIAoyLjIzLjAKCl9fX19fX19fX19f X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fCmRyaS1kZXZlbCBtYWlsaW5nIGxp c3QKZHJpLWRldmVsQGxpc3RzLmZyZWVkZXNrdG9wLm9yZwpodHRwczovL2xpc3RzLmZyZWVkZXNr dG9wLm9yZy9tYWlsbWFuL2xpc3RpbmZvL2RyaS1kZXZlbAo=