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=-14.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, MENTIONS_GIT_HOSTING,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 80C94C28CBC for ; Sat, 9 May 2020 14:16:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5D9AE21473 for ; Sat, 9 May 2020 14:16:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728073AbgEIOQx (ORCPT ); Sat, 9 May 2020 10:16:53 -0400 Received: from asav22.altibox.net ([109.247.116.9]:34192 "EHLO asav22.altibox.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727993AbgEIOQw (ORCPT ); Sat, 9 May 2020 10:16:52 -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 asav22.altibox.net (Postfix) with ESMTPSA id 3911720195; Sat, 9 May 2020 16:16:45 +0200 (CEST) From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= To: dri-devel@lists.freedesktop.org, linux-usb@vger.kernel.org, lee.jones@linaro.org Cc: sam@ravnborg.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= , Felipe Balbi Subject: [PATCH v2 10/10] usb: gadget: function: Add Generic USB Display support Date: Sat, 9 May 2020 16:16:19 +0200 Message-Id: <20200509141619.32970-11-noralf@tronnes.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20200509141619.32970-1-noralf@tronnes.org> References: <20200509141619.32970-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=R7It5+ZX c=1 sm=1 tr=0 a=OYZzhG0JTxDrWp/F2OJbnw==:117 a=OYZzhG0JTxDrWp/F2OJbnw==:17 a=IkcTkHD0fZMA:10 a=M51BFTxLslgA:10 a=VwQbUJbxAAAA:8 a=SJz97ENfAAAA:8 a=gAmX6pxEAAAA:20 a=e5mUnYsNAAAA:8 a=tKJ212r5Ezfkos4TZsYA:9 a=PStc0NqilIzMaC0L:21 a=TxacIdiMss3YJkmZ:21 a=QEXdDO2ut3YA:10 a=AjGcO6oz07-iQ99wixmX:22 a=vFet0B0WnEQeilDPIY6i:22 a=Vxmtnl_E_bksehYqCbjh:22 Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org This adds the gadget side support for the Generic USB Display. It presents a DRM display device as a USB Display configured through configfs. The display is implemented as a vendor type USB interface with one bulk out endpoint. The protocol is implemented using control requests. lz4 compressed framebuffer data/pixels are sent over the bulk endpoint. The DRM part of the gadget is placed in the DRM subsystem since it reaches into the DRM internals. Cc: Felipe Balbi Signed-off-by: Noralf Trønnes --- .../ABI/testing/configfs-usb-gadget-gud_drm | 10 + MAINTAINERS | 2 + drivers/usb/gadget/Kconfig | 12 + drivers/usb/gadget/function/Makefile | 2 + drivers/usb/gadget/function/f_gud_drm.c | 678 ++++++++++++++++++ 5 files changed, 704 insertions(+) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-gud_drm create mode 100644 drivers/usb/gadget/function/f_gud_drm.c diff --git a/Documentation/ABI/testing/configfs-usb-gadget-gud_drm b/Documentation/ABI/testing/configfs-usb-gadget-gud_drm new file mode 100644 index 000000000000..4f865e7fea58 --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-gud_drm @@ -0,0 +1,10 @@ +What: /config/usb-gadget/gadget/functions/gud_drm.name +Date: May 2020 +KernelVersion: 5.9 +Description: + The attributes: + + drm_dev - DRM device number + backlight_dev - Backlight device name (optional) + The backlight brightness scale should be + perceptual not linear. diff --git a/MAINTAINERS b/MAINTAINERS index 7494a21ea41e..4bc5dc7296b8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5296,7 +5296,9 @@ M: Noralf Trønnes S: Maintained W: https://github.com/notro/gud/wiki T: git git://anongit.freedesktop.org/drm/drm-misc +F: Documentation/ABI/testing/configfs-usb-gadget-gud_drm F: drivers/gpu/drm/gud/ +F: drivers/usb/gadget/function/f_gud_drm.c F: include/drm/gud_drm.h DRM DRIVER FOR GRAIN MEDIA GM12U320 PROJECTORS diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index c6db0a0a340c..8d90add495b6 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -216,6 +216,9 @@ config USB_F_PRINTER config USB_F_TCM tristate +config USB_F_GUD_DRM + tristate + # this first set of drivers all depend on bulk-capable hardware. config USB_CONFIGFS @@ -483,6 +486,15 @@ config USB_CONFIGFS_F_TCM Both protocols can work on USB2.0 and USB3.0. UAS utilizes the USB 3.0 feature called streams support. +config USB_CONFIGFS_F_GUD_DRM + bool "Generic USB Display Gadget function" + depends on USB_CONFIGFS + depends on DRM + select DRM_GUD_GADGET + select USB_F_GUD_DRM + help + This presents a DRM display device as a Generic USB Display. + source "drivers/usb/gadget/legacy/Kconfig" endif # USB_GADGET diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index 5d3a6cf02218..cd71caa2a34c 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -50,3 +50,5 @@ usb_f_printer-y := f_printer.o obj-$(CONFIG_USB_F_PRINTER) += usb_f_printer.o usb_f_tcm-y := f_tcm.o obj-$(CONFIG_USB_F_TCM) += usb_f_tcm.o +usb_f_gud_drm-y := f_gud_drm.o +obj-$(CONFIG_USB_F_GUD_DRM) += usb_f_gud_drm.o diff --git a/drivers/usb/gadget/function/f_gud_drm.c b/drivers/usb/gadget/function/f_gud_drm.c new file mode 100644 index 000000000000..9a2d6bb9739f --- /dev/null +++ b/drivers/usb/gadget/function/f_gud_drm.c @@ -0,0 +1,678 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Noralf Trønnes + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct f_gud_drm { + struct usb_function func; + struct work_struct worker; + size_t max_buffer_size; + void *ctrl_req_buf; + + u8 interface_id; + struct usb_request *ctrl_req; + + struct usb_ep *bulk_ep; + struct usb_request *bulk_req; + + struct gud_drm_gadget *gdg; + + spinlock_t lock; /* Protects the following members: */ + bool ctrl_pending; + bool status_pending; + bool bulk_pending; + bool disable_pending; + u8 errno; + u16 request; + u16 value; +}; + +static inline struct f_gud_drm *func_to_f_gud_drm(struct usb_function *f) +{ + return container_of(f, struct f_gud_drm, func); +} + +struct f_gud_drm_opts { + struct usb_function_instance func_inst; + struct mutex lock; + int refcnt; + + unsigned int drm_dev; + const char *backlight_dev; +}; + +static inline struct f_gud_drm_opts *fi_to_f_gud_drm_opts(const struct usb_function_instance *fi) +{ + return container_of(fi, struct f_gud_drm_opts, func_inst); +} + +static inline struct f_gud_drm_opts *ci_to_f_gud_drm_opts(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_gud_drm_opts, + func_inst.group); +} + +#define F_MUD_DEFINE_BULK_ENDPOINT_DESCRIPTOR(name, addr, size) \ + static struct usb_endpoint_descriptor name = { \ + .bLength = USB_DT_ENDPOINT_SIZE, \ + .bDescriptorType = USB_DT_ENDPOINT, \ + .bEndpointAddress = addr, \ + .bmAttributes = USB_ENDPOINT_XFER_BULK, \ + .wMaxPacketSize = cpu_to_le16(size), \ + } + +static struct usb_interface_descriptor f_gud_drm_intf = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, +}; + +F_MUD_DEFINE_BULK_ENDPOINT_DESCRIPTOR(f_gud_drm_fs_out_desc, USB_DIR_OUT, 0); + +static struct usb_descriptor_header *f_gud_drm_fs_function[] = { + (struct usb_descriptor_header *)&f_gud_drm_intf, + (struct usb_descriptor_header *)&f_gud_drm_fs_out_desc, + NULL, +}; + +F_MUD_DEFINE_BULK_ENDPOINT_DESCRIPTOR(f_gud_drm_hs_out_desc, USB_DIR_OUT, 512); + +static struct usb_descriptor_header *f_gud_drm_hs_function[] = { + (struct usb_descriptor_header *)&f_gud_drm_intf, + (struct usb_descriptor_header *)&f_gud_drm_hs_out_desc, + NULL, +}; + +F_MUD_DEFINE_BULK_ENDPOINT_DESCRIPTOR(f_gud_drm_ss_out_desc, USB_DIR_OUT, 1024); + +static struct usb_ss_ep_comp_descriptor f_gud_drm_ss_bulk_comp_desc = { + .bLength = USB_DT_SS_EP_COMP_SIZE, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, +}; + +static struct usb_descriptor_header *f_gud_drm_ss_function[] = { + (struct usb_descriptor_header *)&f_gud_drm_intf, + (struct usb_descriptor_header *)&f_gud_drm_ss_out_desc, + (struct usb_descriptor_header *)&f_gud_drm_ss_bulk_comp_desc, + NULL, +}; + +static struct usb_string f_gud_drm_string_defs[] = { + [0].s = "Generic USB Display", + { } /* end of list */ +}; + +static struct usb_gadget_strings f_gud_drm_string_table = { + .language = 0x0409, /* en-us */ + .strings = f_gud_drm_string_defs, +}; + +static struct usb_gadget_strings *f_gud_drm_strings[] = { + &f_gud_drm_string_table, + NULL, +}; + +static void f_gud_drm_bulk_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_gud_drm *fgd = req->context; + unsigned long flags; + + if (req->status || req->actual != req->length) + return; + + spin_lock_irqsave(&fgd->lock, flags); + fgd->bulk_pending = true; + spin_unlock_irqrestore(&fgd->lock, flags); + + queue_work(system_long_wq, &fgd->worker); +} + +static int f_gud_drm_ctrl_req_set_buffer(struct f_gud_drm *fgd, void *buf, size_t len) +{ + int ret; + + if (len != sizeof(struct gud_drm_req_set_buffer)) + return -EINVAL; + + ret = gud_drm_gadget_set_buffer(fgd->gdg, buf); + if (ret < 0) + return ret; + + if (ret > fgd->max_buffer_size) + return -EOVERFLOW; + + fgd->bulk_req->length = ret; + + return usb_ep_queue(fgd->bulk_ep, fgd->bulk_req, GFP_KERNEL); +} + +static void f_gud_drm_worker(struct work_struct *work) +{ + struct f_gud_drm *fgd = container_of(work, struct f_gud_drm, worker); + bool ctrl_pending, bulk_pending, disable_pending; + struct gud_drm_gadget *gdg = fgd->gdg; + unsigned long flags; + u16 request, value; + int ret; + + spin_lock_irqsave(&fgd->lock, flags); + request = fgd->request; + value = fgd->value; + ctrl_pending = fgd->ctrl_pending; + bulk_pending = fgd->bulk_pending; + disable_pending = fgd->disable_pending; + spin_unlock_irqrestore(&fgd->lock, flags); + + pr_debug("%s: bulk_pending=%u ctrl_pending=%u disable_pending=%u\n", + __func__, bulk_pending, ctrl_pending, disable_pending); + + if (disable_pending) { + gud_drm_gadget_disable_pipe(gdg); + + spin_lock_irqsave(&fgd->lock, flags); + fgd->disable_pending = false; + spin_unlock_irqrestore(&fgd->lock, flags); + return; + } + + if (bulk_pending) { + struct usb_request *req = fgd->bulk_req; + + ret = gud_drm_gadget_write_buffer(gdg, req->buf, req->actual); + if (ret) + pr_err("%s: Failed to write buffer, error=%d\n", __func__, ret); + + spin_lock_irqsave(&fgd->lock, flags); + fgd->bulk_pending = false; + spin_unlock_irqrestore(&fgd->lock, flags); + } + + if (ctrl_pending) { + unsigned int length = fgd->ctrl_req->length; + void *buf = fgd->ctrl_req->buf; + + if (request == GUD_DRM_USB_REQ_SET_BUFFER) + ret = f_gud_drm_ctrl_req_set_buffer(fgd, buf, length); + else + ret = gud_drm_gadget_ctrl_set(gdg, request, value, buf, length); + + spin_lock_irqsave(&fgd->lock, flags); + if (!fgd->errno) /* Don't scribble over an EBUSY or ESHUTDOWN */ + fgd->errno = -ret; + fgd->ctrl_pending = false; + fgd->status_pending = false; + spin_unlock_irqrestore(&fgd->lock, flags); + } +} + +static void f_gud_drm_ctrl_req_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_gud_drm *fgd = req->context; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&fgd->lock, flags); + + if (req->status) + ret = req->status; + else if (req->actual != req->length) + ret = -EREMOTEIO; + if (ret) { + fgd->errno = -ret; + fgd->status_pending = false; + } else { + fgd->ctrl_pending = true; + } + + spin_unlock_irqrestore(&fgd->lock, flags); + + if (!ret) + queue_work(system_long_wq, &fgd->worker); +} + +static int f_gud_drm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) +{ + struct usb_composite_dev *cdev = f->config->cdev; + struct f_gud_drm *fgd = func_to_f_gud_drm(f); + bool in = ctrl->bRequestType & USB_DIR_IN; + u16 length = le16_to_cpu(ctrl->wLength); + u16 value = le16_to_cpu(ctrl->wValue); + unsigned long flags; + int ret; + + if (ctrl->bRequest == USB_REQ_GET_STATUS) { + struct gud_drm_req_get_status *status = cdev->req->buf; + + if (!in || length != sizeof(*status)) + return -EINVAL; + + spin_lock_irqsave(&fgd->lock, flags); + status->flags = 0; + if (fgd->status_pending) + status->flags |= GUD_DRM_STATUS_PENDING; + status->errno = fgd->errno; + spin_unlock_irqrestore(&fgd->lock, flags); + } else if (in) { + if (length > USB_COMP_EP0_BUFSIZ) /* 4k */ + return -EOVERFLOW; + + ret = gud_drm_gadget_ctrl_get(fgd->gdg, ctrl->bRequest, value, + cdev->req->buf, length); + spin_lock_irqsave(&fgd->lock, flags); + fgd->status_pending = false; + fgd->errno = ret < 0 ? -ret : 0; + spin_unlock_irqrestore(&fgd->lock, flags); + if (ret < 0) + return ret; + + length = ret; + } else { + if (length > GUD_DRM_MAX_TRANSFER_SIZE) + return -EOVERFLOW; + + spin_lock_irqsave(&fgd->lock, flags); + if (fgd->ctrl_pending) { + /* If we get here the host has timed out on the previous request */ + ret = -EBUSY; + fgd->status_pending = false; + fgd->errno = -ret; + } else { + ret = 0; + fgd->errno = 0; + fgd->request = ctrl->bRequest; + fgd->value = value; + fgd->status_pending = true; + } + spin_unlock_irqrestore(&fgd->lock, flags); + + if (ret) + return ret; + + fgd->ctrl_req->length = length; + + return usb_ep_queue(cdev->gadget->ep0, fgd->ctrl_req, GFP_ATOMIC); + } + + cdev->req->length = length; + + return usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC); +} + +static bool f_gud_drm_req_match(struct usb_function *f, const struct usb_ctrlrequest *ctrl, + bool config0) +{ + struct f_gud_drm *fgd = func_to_f_gud_drm(f); + + if (config0) + return false; + + if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_VENDOR) + return false; + + if ((ctrl->bRequestType & USB_RECIP_MASK) != USB_RECIP_INTERFACE) + return false; + + return fgd->interface_id == le16_to_cpu(ctrl->wIndex); +} + +static int f_gud_drm_set_alt(struct usb_function *f, unsigned int intf, unsigned int alt) +{ + struct usb_composite_dev *cdev = f->config->cdev; + struct f_gud_drm *fgd = func_to_f_gud_drm(f); + unsigned long flags; + + if (alt || intf != fgd->interface_id) + return -EINVAL; + + if (!fgd->bulk_ep->desc) { + pr_debug("%s: init\n", __func__); + if (config_ep_by_speed(cdev->gadget, f, fgd->bulk_ep)) { + fgd->bulk_ep->desc = NULL; + return -EINVAL; + } + } + + pr_debug("%s: reset\n", __func__); + + usb_ep_disable(fgd->bulk_ep); + usb_ep_enable(fgd->bulk_ep); + + spin_lock_irqsave(&fgd->lock, flags); + fgd->ctrl_pending = false; + fgd->bulk_pending = false; + fgd->disable_pending = false; + spin_unlock_irqrestore(&fgd->lock, flags); + + return 0; +} + +static void f_gud_drm_disable(struct usb_function *f) +{ + struct f_gud_drm *fgd = func_to_f_gud_drm(f); + unsigned long flags; + + pr_debug("%s\n", __func__); + + usb_ep_disable(fgd->bulk_ep); + + spin_lock_irqsave(&fgd->lock, flags); + fgd->ctrl_pending = false; + fgd->bulk_pending = false; + fgd->status_pending = false; + fgd->disable_pending = true; + fgd->errno = ESHUTDOWN; + spin_unlock_irqrestore(&fgd->lock, flags); + + queue_work(system_long_wq, &fgd->worker); +} + +static void f_gud_drm_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_gud_drm *fgd = func_to_f_gud_drm(f); + struct usb_composite_dev *cdev = fgd->func.config->cdev; + + flush_work(&fgd->worker); + + gud_drm_gadget_fini(fgd->gdg); + fgd->gdg = NULL; + + kfree(fgd->bulk_req->buf); + usb_ep_free_request(fgd->bulk_ep, fgd->bulk_req); + usb_ep_free_request(cdev->gadget->ep0, fgd->ctrl_req); + fgd->ctrl_req = NULL; + fgd->bulk_req = NULL; + fgd->bulk_ep = NULL; + + usb_free_all_descriptors(f); +} + +static int f_gud_drm_bind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_gud_drm_opts *opts = fi_to_f_gud_drm_opts(f->fi); + struct usb_composite_dev *cdev = c->cdev; + struct f_gud_drm *fgd = func_to_f_gud_drm(f); + struct usb_request *ctrl_req, *bulk_req; + struct gud_drm_gadget *gdg; + struct usb_string *us; + void *buf; + int ret; + + us = usb_gstrings_attach(cdev, f_gud_drm_strings, + ARRAY_SIZE(f_gud_drm_string_defs)); + if (IS_ERR(us)) + return PTR_ERR(us); + + f_gud_drm_intf.iInterface = us[0].id; + + ret = usb_interface_id(c, f); + if (ret < 0) + return ret; + + fgd->interface_id = ret; + f_gud_drm_intf.bInterfaceNumber = fgd->interface_id; + + fgd->bulk_ep = usb_ep_autoconfig(cdev->gadget, &f_gud_drm_fs_out_desc); + if (!fgd->bulk_ep) + return -ENODEV; + + f_gud_drm_hs_out_desc.bEndpointAddress = f_gud_drm_fs_out_desc.bEndpointAddress; + + f_gud_drm_ss_out_desc.bEndpointAddress = f_gud_drm_fs_out_desc.bEndpointAddress; + + ret = usb_assign_descriptors(f, f_gud_drm_fs_function, f_gud_drm_hs_function, + f_gud_drm_ss_function, NULL); + if (ret) + return ret; + + ctrl_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); + if (!ctrl_req) { + ret = -ENOMEM; + goto fail_free_descs; + } + + ctrl_req->buf = fgd->ctrl_req_buf; + ctrl_req->complete = f_gud_drm_ctrl_req_complete; + ctrl_req->context = fgd; + + gdg = gud_drm_gadget_init(opts->drm_dev, opts->backlight_dev, &fgd->max_buffer_size); + if (IS_ERR(gdg)) { + ret = PTR_ERR(gdg); + goto fail_free_ctrl_req; + } + + bulk_req = usb_ep_alloc_request(fgd->bulk_ep, GFP_KERNEL); + if (!bulk_req) { + ret = -ENOMEM; + goto fail_free_ctrl_req; + } + + buf = kmalloc(fgd->max_buffer_size, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto fail_free_bulk_req; + } + + bulk_req->complete = f_gud_drm_bulk_complete; + bulk_req->context = fgd; + bulk_req->buf = buf; + + fgd->ctrl_req = ctrl_req; + fgd->bulk_req = bulk_req; + fgd->gdg = gdg; + + return 0; + +fail_free_bulk_req: + usb_ep_free_request(fgd->bulk_ep, bulk_req); +fail_free_ctrl_req: + usb_ep_free_request(cdev->gadget->ep0, ctrl_req); +fail_free_descs: + usb_free_all_descriptors(f); + + return ret; +} + +static void f_gud_drm_free_func(struct usb_function *f) +{ + struct f_gud_drm_opts *opts = container_of(f->fi, struct f_gud_drm_opts, func_inst); + struct f_gud_drm *fgd = func_to_f_gud_drm(f); + + mutex_lock(&opts->lock); + opts->refcnt--; + mutex_unlock(&opts->lock); + + kfree(fgd->ctrl_req_buf); + kfree(fgd); +} + +static struct usb_function *f_gud_drm_alloc_func(struct usb_function_instance *fi) +{ + struct f_gud_drm_opts *opts = fi_to_f_gud_drm_opts(fi); + struct usb_function *func; + struct f_gud_drm *fgd; + + fgd = kzalloc(sizeof(*fgd), GFP_KERNEL); + if (!fgd) + return ERR_PTR(-ENOMEM); + + fgd->ctrl_req_buf = kmalloc(GUD_DRM_MAX_TRANSFER_SIZE, GFP_KERNEL); + if (!fgd->ctrl_req_buf) + goto error; + + spin_lock_init(&fgd->lock); + INIT_WORK(&fgd->worker, f_gud_drm_worker); + + mutex_lock(&opts->lock); + opts->refcnt++; + mutex_unlock(&opts->lock); + + func = &fgd->func; + func->name = "gud_drm"; + func->bind = f_gud_drm_bind; + func->unbind = f_gud_drm_unbind; + func->set_alt = f_gud_drm_set_alt; + func->req_match = f_gud_drm_req_match; + func->setup = f_gud_drm_setup; + func->disable = f_gud_drm_disable; + func->free_func = f_gud_drm_free_func; + + return func; + +error: + kfree(fgd); + + return ERR_PTR(-ENOMEM); +} + +static ssize_t f_gud_drm_opts_drm_dev_show(struct config_item *item, char *page) +{ + struct f_gud_drm_opts *opts = ci_to_f_gud_drm_opts(item); + int result; + + mutex_lock(&opts->lock); + result = sprintf(page, "%u\n", opts->drm_dev); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_gud_drm_opts_drm_dev_store(struct config_item *item, + const char *page, size_t len) +{ + struct f_gud_drm_opts *opts = ci_to_f_gud_drm_opts(item); + unsigned int num; + int ret; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto unlock; + } + + ret = kstrtouint(page, 0, &num); + if (ret) + goto unlock; + + opts->drm_dev = num; + ret = len; +unlock: + mutex_unlock(&opts->lock); + + return ret; +} + +CONFIGFS_ATTR(f_gud_drm_opts_, drm_dev); + +static ssize_t f_gud_drm_opts_backlight_dev_show(struct config_item *item, char *page) +{ + struct f_gud_drm_opts *opts = ci_to_f_gud_drm_opts(item); + ssize_t ret = 0; + + mutex_lock(&opts->lock); + if (opts->backlight_dev) + ret = strscpy(page, opts->backlight_dev, PAGE_SIZE); + else + page[0] = '\0'; + mutex_unlock(&opts->lock); + + return ret; +} + +static ssize_t f_gud_drm_opts_backlight_dev_store(struct config_item *item, + const char *page, size_t len) +{ + struct f_gud_drm_opts *opts = ci_to_f_gud_drm_opts(item); + ssize_t ret; + char *name; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto unlock; + } + + name = kstrndup(page, len, GFP_KERNEL); + if (!name) { + ret = -ENOMEM; + goto unlock; + } + + kfree(opts->backlight_dev); + opts->backlight_dev = name; + ret = len; +unlock: + mutex_unlock(&opts->lock); + + return ret; +} + +CONFIGFS_ATTR(f_gud_drm_opts_, backlight_dev); + +static struct configfs_attribute *f_gud_drm_attrs[] = { + &f_gud_drm_opts_attr_drm_dev, + &f_gud_drm_opts_attr_backlight_dev, + NULL, +}; + +static void f_gud_drm_attr_release(struct config_item *item) +{ + struct f_gud_drm_opts *opts = ci_to_f_gud_drm_opts(item); + + usb_put_function_instance(&opts->func_inst); +} + +static struct configfs_item_operations f_gud_drm_item_ops = { + .release = f_gud_drm_attr_release, +}; + +static const struct config_item_type f_gud_drm_func_type = { + .ct_item_ops = &f_gud_drm_item_ops, + .ct_attrs = f_gud_drm_attrs, + .ct_owner = THIS_MODULE, +}; + +static void f_gud_drm_free_func_inst(struct usb_function_instance *fi) +{ + struct f_gud_drm_opts *opts = fi_to_f_gud_drm_opts(fi); + + mutex_destroy(&opts->lock); + kfree(opts->backlight_dev); + kfree(opts); +} + +static struct usb_function_instance *f_gud_drm_alloc_func_inst(void) +{ + struct f_gud_drm_opts *opts; + + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); + + mutex_init(&opts->lock); + opts->func_inst.free_func_inst = f_gud_drm_free_func_inst; + + config_group_init_type_name(&opts->func_inst.group, "", &f_gud_drm_func_type); + + return &opts->func_inst; +} + +DECLARE_USB_FUNCTION_INIT(gud_drm, f_gud_drm_alloc_func_inst, f_gud_drm_alloc_func); + +MODULE_DESCRIPTION("Generic USB Display Gadget"); +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=-14.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, MENTIONS_GIT_HOSTING,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 1E8DAC47255 for ; Sat, 9 May 2020 14:16:56 +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 F020521473 for ; Sat, 9 May 2020 14:16:55 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org F020521473 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 1CC076E356; Sat, 9 May 2020 14:16:49 +0000 (UTC) Received: from asav22.altibox.net (asav22.altibox.net [109.247.116.9]) by gabe.freedesktop.org (Postfix) with ESMTPS id 7B84C6E359 for ; Sat, 9 May 2020 14:16:47 +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 3911720195; Sat, 9 May 2020 16:16:45 +0200 (CEST) From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= To: dri-devel@lists.freedesktop.org, linux-usb@vger.kernel.org, lee.jones@linaro.org Subject: [PATCH v2 10/10] usb: gadget: function: Add Generic USB Display support Date: Sat, 9 May 2020 16:16:19 +0200 Message-Id: <20200509141619.32970-11-noralf@tronnes.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20200509141619.32970-1-noralf@tronnes.org> References: <20200509141619.32970-1-noralf@tronnes.org> MIME-Version: 1.0 X-CMAE-Score: 0 X-CMAE-Analysis: v=2.3 cv=R7It5+ZX c=1 sm=1 tr=0 a=OYZzhG0JTxDrWp/F2OJbnw==:117 a=OYZzhG0JTxDrWp/F2OJbnw==:17 a=IkcTkHD0fZMA:10 a=M51BFTxLslgA:10 a=VwQbUJbxAAAA:8 a=SJz97ENfAAAA:8 a=gAmX6pxEAAAA:20 a=e5mUnYsNAAAA:8 a=tKJ212r5Ezfkos4TZsYA:9 a=PStc0NqilIzMaC0L:21 a=TxacIdiMss3YJkmZ:21 a=QEXdDO2ut3YA:10 a=AjGcO6oz07-iQ99wixmX:22 a=vFet0B0WnEQeilDPIY6i:22 a=Vxmtnl_E_bksehYqCbjh: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: jingoohan1@gmail.com, daniel.thompson@linaro.org, sam@ravnborg.org, Felipe Balbi Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" VGhpcyBhZGRzIHRoZSBnYWRnZXQgc2lkZSBzdXBwb3J0IGZvciB0aGUgR2VuZXJpYyBVU0IgRGlz cGxheS4gSXQgcHJlc2VudHMKYSBEUk0gZGlzcGxheSBkZXZpY2UgYXMgYSBVU0IgRGlzcGxheSBj b25maWd1cmVkIHRocm91Z2ggY29uZmlnZnMuCgpUaGUgZGlzcGxheSBpcyBpbXBsZW1lbnRlZCBh cyBhIHZlbmRvciB0eXBlIFVTQiBpbnRlcmZhY2Ugd2l0aCBvbmUgYnVsawpvdXQgZW5kcG9pbnQu IFRoZSBwcm90b2NvbCBpcyBpbXBsZW1lbnRlZCB1c2luZyBjb250cm9sIHJlcXVlc3RzLgpsejQg Y29tcHJlc3NlZCBmcmFtZWJ1ZmZlciBkYXRhL3BpeGVscyBhcmUgc2VudCBvdmVyIHRoZSBidWxr IGVuZHBvaW50LgoKVGhlIERSTSBwYXJ0IG9mIHRoZSBnYWRnZXQgaXMgcGxhY2VkIGluIHRoZSBE Uk0gc3Vic3lzdGVtIHNpbmNlIGl0IHJlYWNoZXMKaW50byB0aGUgRFJNIGludGVybmFscy4KCkNj OiBGZWxpcGUgQmFsYmkgPGJhbGJpQGtlcm5lbC5vcmc+ClNpZ25lZC1vZmYtYnk6IE5vcmFsZiBU csO4bm5lcyA8bm9yYWxmQHRyb25uZXMub3JnPgotLS0KIC4uLi9BQkkvdGVzdGluZy9jb25maWdm cy11c2ItZ2FkZ2V0LWd1ZF9kcm0gICB8ICAxMCArCiBNQUlOVEFJTkVSUyAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgfCAgIDIgKwogZHJpdmVycy91c2IvZ2FkZ2V0L0tjb25maWcg ICAgICAgICAgICAgICAgICAgIHwgIDEyICsKIGRyaXZlcnMvdXNiL2dhZGdldC9mdW5jdGlvbi9N YWtlZmlsZSAgICAgICAgICB8ICAgMiArCiBkcml2ZXJzL3VzYi9nYWRnZXQvZnVuY3Rpb24vZl9n dWRfZHJtLmMgICAgICAgfCA2NzggKysrKysrKysrKysrKysrKysrCiA1IGZpbGVzIGNoYW5nZWQs IDcwNCBpbnNlcnRpb25zKCspCiBjcmVhdGUgbW9kZSAxMDA2NDQgRG9jdW1lbnRhdGlvbi9BQkkv dGVzdGluZy9jb25maWdmcy11c2ItZ2FkZ2V0LWd1ZF9kcm0KIGNyZWF0ZSBtb2RlIDEwMDY0NCBk cml2ZXJzL3VzYi9nYWRnZXQvZnVuY3Rpb24vZl9ndWRfZHJtLmMKCmRpZmYgLS1naXQgYS9Eb2N1 bWVudGF0aW9uL0FCSS90ZXN0aW5nL2NvbmZpZ2ZzLXVzYi1nYWRnZXQtZ3VkX2RybSBiL0RvY3Vt ZW50YXRpb24vQUJJL3Rlc3RpbmcvY29uZmlnZnMtdXNiLWdhZGdldC1ndWRfZHJtCm5ldyBmaWxl IG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAwMDAwMC4uNGY4NjVlN2ZlYTU4Ci0tLSAvZGV2L251 bGwKKysrIGIvRG9jdW1lbnRhdGlvbi9BQkkvdGVzdGluZy9jb25maWdmcy11c2ItZ2FkZ2V0LWd1 ZF9kcm0KQEAgLTAsMCArMSwxMCBAQAorV2hhdDoJCS9jb25maWcvdXNiLWdhZGdldC9nYWRnZXQv ZnVuY3Rpb25zL2d1ZF9kcm0ubmFtZQorRGF0ZToJCU1heSAyMDIwCitLZXJuZWxWZXJzaW9uOgk1 LjkKK0Rlc2NyaXB0aW9uOgorCQlUaGUgYXR0cmlidXRlczoKKworCQlkcm1fZGV2IC0gRFJNIGRl dmljZSBudW1iZXIKKwkJYmFja2xpZ2h0X2RldiAtIEJhY2tsaWdodCBkZXZpY2UgbmFtZSAob3B0 aW9uYWwpCisJCQkJVGhlIGJhY2tsaWdodCBicmlnaHRuZXNzIHNjYWxlIHNob3VsZCBiZQorCQkJ CXBlcmNlcHR1YWwgbm90IGxpbmVhci4KZGlmZiAtLWdpdCBhL01BSU5UQUlORVJTIGIvTUFJTlRB SU5FUlMKaW5kZXggNzQ5NGEyMWVhNDFlLi40YmM1ZGM3Mjk2YjggMTAwNjQ0Ci0tLSBhL01BSU5U QUlORVJTCisrKyBiL01BSU5UQUlORVJTCkBAIC01Mjk2LDcgKzUyOTYsOSBAQCBNOglOb3JhbGYg VHLDuG5uZXMgPG5vcmFsZkB0cm9ubmVzLm9yZz4KIFM6CU1haW50YWluZWQKIFc6CWh0dHBzOi8v Z2l0aHViLmNvbS9ub3Ryby9ndWQvd2lraQogVDoJZ2l0IGdpdDovL2Fub25naXQuZnJlZWRlc2t0 b3Aub3JnL2RybS9kcm0tbWlzYworRjoJRG9jdW1lbnRhdGlvbi9BQkkvdGVzdGluZy9jb25maWdm cy11c2ItZ2FkZ2V0LWd1ZF9kcm0KIEY6CWRyaXZlcnMvZ3B1L2RybS9ndWQvCitGOglkcml2ZXJz L3VzYi9nYWRnZXQvZnVuY3Rpb24vZl9ndWRfZHJtLmMKIEY6CWluY2x1ZGUvZHJtL2d1ZF9kcm0u aAogCiBEUk0gRFJJVkVSIEZPUiBHUkFJTiBNRURJQSBHTTEyVTMyMCBQUk9KRUNUT1JTCmRpZmYg LS1naXQgYS9kcml2ZXJzL3VzYi9nYWRnZXQvS2NvbmZpZyBiL2RyaXZlcnMvdXNiL2dhZGdldC9L Y29uZmlnCmluZGV4IGM2ZGIwYTBhMzQwYy4uOGQ5MGFkZDQ5NWI2IDEwMDY0NAotLS0gYS9kcml2 ZXJzL3VzYi9nYWRnZXQvS2NvbmZpZworKysgYi9kcml2ZXJzL3VzYi9nYWRnZXQvS2NvbmZpZwpA QCAtMjE2LDYgKzIxNiw5IEBAIGNvbmZpZyBVU0JfRl9QUklOVEVSCiBjb25maWcgVVNCX0ZfVENN CiAJdHJpc3RhdGUKIAorY29uZmlnIFVTQl9GX0dVRF9EUk0KKwl0cmlzdGF0ZQorCiAjIHRoaXMg Zmlyc3Qgc2V0IG9mIGRyaXZlcnMgYWxsIGRlcGVuZCBvbiBidWxrLWNhcGFibGUgaGFyZHdhcmUu CiAKIGNvbmZpZyBVU0JfQ09ORklHRlMKQEAgLTQ4Myw2ICs0ODYsMTUgQEAgY29uZmlnIFVTQl9D T05GSUdGU19GX1RDTQogCSAgQm90aCBwcm90b2NvbHMgY2FuIHdvcmsgb24gVVNCMi4wIGFuZCBV U0IzLjAuCiAJICBVQVMgdXRpbGl6ZXMgdGhlIFVTQiAzLjAgZmVhdHVyZSBjYWxsZWQgc3RyZWFt cyBzdXBwb3J0LgogCitjb25maWcgVVNCX0NPTkZJR0ZTX0ZfR1VEX0RSTQorCWJvb2wgIkdlbmVy aWMgVVNCIERpc3BsYXkgR2FkZ2V0IGZ1bmN0aW9uIgorCWRlcGVuZHMgb24gVVNCX0NPTkZJR0ZT CisJZGVwZW5kcyBvbiBEUk0KKwlzZWxlY3QgRFJNX0dVRF9HQURHRVQKKwlzZWxlY3QgVVNCX0Zf R1VEX0RSTQorCWhlbHAKKwkgIFRoaXMgcHJlc2VudHMgYSBEUk0gZGlzcGxheSBkZXZpY2UgYXMg YSBHZW5lcmljIFVTQiBEaXNwbGF5LgorCiBzb3VyY2UgImRyaXZlcnMvdXNiL2dhZGdldC9sZWdh Y3kvS2NvbmZpZyIKIAogZW5kaWYgIyBVU0JfR0FER0VUCmRpZmYgLS1naXQgYS9kcml2ZXJzL3Vz Yi9nYWRnZXQvZnVuY3Rpb24vTWFrZWZpbGUgYi9kcml2ZXJzL3VzYi9nYWRnZXQvZnVuY3Rpb24v TWFrZWZpbGUKaW5kZXggNWQzYTZjZjAyMjE4Li5jZDcxY2FhMmEzNGMgMTAwNjQ0Ci0tLSBhL2Ry aXZlcnMvdXNiL2dhZGdldC9mdW5jdGlvbi9NYWtlZmlsZQorKysgYi9kcml2ZXJzL3VzYi9nYWRn ZXQvZnVuY3Rpb24vTWFrZWZpbGUKQEAgLTUwLDMgKzUwLDUgQEAgdXNiX2ZfcHJpbnRlci15CQkJ Oj0gZl9wcmludGVyLm8KIG9iai0kKENPTkZJR19VU0JfRl9QUklOVEVSKQkrPSB1c2JfZl9wcmlu dGVyLm8KIHVzYl9mX3RjbS15CQkJOj0gZl90Y20ubwogb2JqLSQoQ09ORklHX1VTQl9GX1RDTSkJ CSs9IHVzYl9mX3RjbS5vCit1c2JfZl9ndWRfZHJtLXkJCQk6PSBmX2d1ZF9kcm0ubworb2JqLSQo Q09ORklHX1VTQl9GX0dVRF9EUk0pCSs9IHVzYl9mX2d1ZF9kcm0ubwpkaWZmIC0tZ2l0IGEvZHJp dmVycy91c2IvZ2FkZ2V0L2Z1bmN0aW9uL2ZfZ3VkX2RybS5jIGIvZHJpdmVycy91c2IvZ2FkZ2V0 L2Z1bmN0aW9uL2ZfZ3VkX2RybS5jCm5ldyBmaWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAw MDAwMC4uOWEyZDZiYjk3MzlmCi0tLSAvZGV2L251bGwKKysrIGIvZHJpdmVycy91c2IvZ2FkZ2V0 L2Z1bmN0aW9uL2ZfZ3VkX2RybS5jCkBAIC0wLDAgKzEsNjc4IEBACisvLyBTUERYLUxpY2Vuc2Ut SWRlbnRpZmllcjogR1BMLTIuMAorLyoKKyAqIENvcHlyaWdodCAoQykgMjAyMCBOb3JhbGYgVHLD uG5uZXMKKyAqLworCisjaW5jbHVkZSA8bGludXgvY29uZmlnZnMuaD4KKyNpbmNsdWRlIDxsaW51 eC9kZXZpY2UuaD4KKyNpbmNsdWRlIDxsaW51eC9rZXJuZWwuaD4KKyNpbmNsdWRlIDxsaW51eC9s aXN0Lmg+CisjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+CisjaW5jbHVkZSA8bGludXgvbXV0ZXgu aD4KKyNpbmNsdWRlIDxsaW51eC9zbGFiLmg+CisjaW5jbHVkZSA8bGludXgvc3BpbmxvY2suaD4K KyNpbmNsdWRlIDxsaW51eC91c2IvY29tcG9zaXRlLmg+CisjaW5jbHVkZSA8bGludXgvdXNiL2dh ZGdldC5oPgorI2luY2x1ZGUgPGxpbnV4L3dvcmtxdWV1ZS5oPgorCisjaW5jbHVkZSA8ZHJtL2d1 ZF9kcm0uaD4KKworc3RydWN0IGZfZ3VkX2RybSB7CisJc3RydWN0IHVzYl9mdW5jdGlvbiBmdW5j OworCXN0cnVjdCB3b3JrX3N0cnVjdCB3b3JrZXI7CisJc2l6ZV90IG1heF9idWZmZXJfc2l6ZTsK Kwl2b2lkICpjdHJsX3JlcV9idWY7CisKKwl1OCBpbnRlcmZhY2VfaWQ7CisJc3RydWN0IHVzYl9y ZXF1ZXN0ICpjdHJsX3JlcTsKKworCXN0cnVjdCB1c2JfZXAgKmJ1bGtfZXA7CisJc3RydWN0IHVz Yl9yZXF1ZXN0ICpidWxrX3JlcTsKKworCXN0cnVjdCBndWRfZHJtX2dhZGdldCAqZ2RnOworCisJ c3BpbmxvY2tfdCBsb2NrOyAvKiBQcm90ZWN0cyB0aGUgZm9sbG93aW5nIG1lbWJlcnM6ICovCisJ Ym9vbCBjdHJsX3BlbmRpbmc7CisJYm9vbCBzdGF0dXNfcGVuZGluZzsKKwlib29sIGJ1bGtfcGVu ZGluZzsKKwlib29sIGRpc2FibGVfcGVuZGluZzsKKwl1OCBlcnJubzsKKwl1MTYgcmVxdWVzdDsK Kwl1MTYgdmFsdWU7Cit9OworCitzdGF0aWMgaW5saW5lIHN0cnVjdCBmX2d1ZF9kcm0gKmZ1bmNf dG9fZl9ndWRfZHJtKHN0cnVjdCB1c2JfZnVuY3Rpb24gKmYpCit7CisJcmV0dXJuIGNvbnRhaW5l cl9vZihmLCBzdHJ1Y3QgZl9ndWRfZHJtLCBmdW5jKTsKK30KKworc3RydWN0IGZfZ3VkX2RybV9v cHRzIHsKKwlzdHJ1Y3QgdXNiX2Z1bmN0aW9uX2luc3RhbmNlIGZ1bmNfaW5zdDsKKwlzdHJ1Y3Qg bXV0ZXggbG9jazsKKwlpbnQgcmVmY250OworCisJdW5zaWduZWQgaW50IGRybV9kZXY7CisJY29u c3QgY2hhciAqYmFja2xpZ2h0X2RldjsKK307CisKK3N0YXRpYyBpbmxpbmUgc3RydWN0IGZfZ3Vk X2RybV9vcHRzICpmaV90b19mX2d1ZF9kcm1fb3B0cyhjb25zdCBzdHJ1Y3QgdXNiX2Z1bmN0aW9u X2luc3RhbmNlICpmaSkKK3sKKwlyZXR1cm4gY29udGFpbmVyX29mKGZpLCBzdHJ1Y3QgZl9ndWRf ZHJtX29wdHMsIGZ1bmNfaW5zdCk7Cit9CisKK3N0YXRpYyBpbmxpbmUgc3RydWN0IGZfZ3VkX2Ry bV9vcHRzICpjaV90b19mX2d1ZF9kcm1fb3B0cyhzdHJ1Y3QgY29uZmlnX2l0ZW0gKml0ZW0pCit7 CisJcmV0dXJuIGNvbnRhaW5lcl9vZih0b19jb25maWdfZ3JvdXAoaXRlbSksIHN0cnVjdCBmX2d1 ZF9kcm1fb3B0cywKKwkJCSAgICBmdW5jX2luc3QuZ3JvdXApOworfQorCisjZGVmaW5lIEZfTVVE X0RFRklORV9CVUxLX0VORFBPSU5UX0RFU0NSSVBUT1IobmFtZSwgYWRkciwgc2l6ZSkJXAorCXN0 YXRpYyBzdHJ1Y3QgdXNiX2VuZHBvaW50X2Rlc2NyaXB0b3IgbmFtZSA9IHsJCVwKKwkJLmJMZW5n dGggPQkJVVNCX0RUX0VORFBPSU5UX1NJWkUsCVwKKwkJLmJEZXNjcmlwdG9yVHlwZSA9CVVTQl9E VF9FTkRQT0lOVCwJXAorCQkuYkVuZHBvaW50QWRkcmVzcyA9CWFkZHIsCQkJXAorCQkuYm1BdHRy aWJ1dGVzID0JCVVTQl9FTkRQT0lOVF9YRkVSX0JVTEssCVwKKwkJLndNYXhQYWNrZXRTaXplID0J Y3B1X3RvX2xlMTYoc2l6ZSksCVwKKwl9CisKK3N0YXRpYyBzdHJ1Y3QgdXNiX2ludGVyZmFjZV9k ZXNjcmlwdG9yIGZfZ3VkX2RybV9pbnRmID0geworCS5iTGVuZ3RoID0JCVVTQl9EVF9JTlRFUkZB Q0VfU0laRSwKKwkuYkRlc2NyaXB0b3JUeXBlID0JVVNCX0RUX0lOVEVSRkFDRSwKKwkuYk51bUVu ZHBvaW50cyA9CTEsCisJLmJJbnRlcmZhY2VDbGFzcyA9CVVTQl9DTEFTU19WRU5ET1JfU1BFQywK K307CisKK0ZfTVVEX0RFRklORV9CVUxLX0VORFBPSU5UX0RFU0NSSVBUT1IoZl9ndWRfZHJtX2Zz X291dF9kZXNjLCBVU0JfRElSX09VVCwgMCk7CisKK3N0YXRpYyBzdHJ1Y3QgdXNiX2Rlc2NyaXB0 b3JfaGVhZGVyICpmX2d1ZF9kcm1fZnNfZnVuY3Rpb25bXSA9IHsKKwkoc3RydWN0IHVzYl9kZXNj cmlwdG9yX2hlYWRlciAqKSZmX2d1ZF9kcm1faW50ZiwKKwkoc3RydWN0IHVzYl9kZXNjcmlwdG9y X2hlYWRlciAqKSZmX2d1ZF9kcm1fZnNfb3V0X2Rlc2MsCisJTlVMTCwKK307CisKK0ZfTVVEX0RF RklORV9CVUxLX0VORFBPSU5UX0RFU0NSSVBUT1IoZl9ndWRfZHJtX2hzX291dF9kZXNjLCBVU0Jf RElSX09VVCwgNTEyKTsKKworc3RhdGljIHN0cnVjdCB1c2JfZGVzY3JpcHRvcl9oZWFkZXIgKmZf Z3VkX2RybV9oc19mdW5jdGlvbltdID0geworCShzdHJ1Y3QgdXNiX2Rlc2NyaXB0b3JfaGVhZGVy ICopJmZfZ3VkX2RybV9pbnRmLAorCShzdHJ1Y3QgdXNiX2Rlc2NyaXB0b3JfaGVhZGVyICopJmZf Z3VkX2RybV9oc19vdXRfZGVzYywKKwlOVUxMLAorfTsKKworRl9NVURfREVGSU5FX0JVTEtfRU5E UE9JTlRfREVTQ1JJUFRPUihmX2d1ZF9kcm1fc3Nfb3V0X2Rlc2MsIFVTQl9ESVJfT1VULCAxMDI0 KTsKKworc3RhdGljIHN0cnVjdCB1c2Jfc3NfZXBfY29tcF9kZXNjcmlwdG9yIGZfZ3VkX2RybV9z c19idWxrX2NvbXBfZGVzYyA9IHsKKwkuYkxlbmd0aCA9CQlVU0JfRFRfU1NfRVBfQ09NUF9TSVpF LAorCS5iRGVzY3JpcHRvclR5cGUgPQlVU0JfRFRfU1NfRU5EUE9JTlRfQ09NUCwKK307CisKK3N0 YXRpYyBzdHJ1Y3QgdXNiX2Rlc2NyaXB0b3JfaGVhZGVyICpmX2d1ZF9kcm1fc3NfZnVuY3Rpb25b XSA9IHsKKwkoc3RydWN0IHVzYl9kZXNjcmlwdG9yX2hlYWRlciAqKSZmX2d1ZF9kcm1faW50ZiwK Kwkoc3RydWN0IHVzYl9kZXNjcmlwdG9yX2hlYWRlciAqKSZmX2d1ZF9kcm1fc3Nfb3V0X2Rlc2Ms CisJKHN0cnVjdCB1c2JfZGVzY3JpcHRvcl9oZWFkZXIgKikmZl9ndWRfZHJtX3NzX2J1bGtfY29t cF9kZXNjLAorCU5VTEwsCit9OworCitzdGF0aWMgc3RydWN0IHVzYl9zdHJpbmcgZl9ndWRfZHJt X3N0cmluZ19kZWZzW10gPSB7CisJWzBdLnMgPSAiR2VuZXJpYyBVU0IgRGlzcGxheSIsCisJeyAg fSAvKiBlbmQgb2YgbGlzdCAqLworfTsKKworc3RhdGljIHN0cnVjdCB1c2JfZ2FkZ2V0X3N0cmlu Z3MgZl9ndWRfZHJtX3N0cmluZ190YWJsZSA9IHsKKwkubGFuZ3VhZ2UgPQkweDA0MDksCS8qIGVu LXVzICovCisJLnN0cmluZ3MgPQlmX2d1ZF9kcm1fc3RyaW5nX2RlZnMsCit9OworCitzdGF0aWMg c3RydWN0IHVzYl9nYWRnZXRfc3RyaW5ncyAqZl9ndWRfZHJtX3N0cmluZ3NbXSA9IHsKKwkmZl9n dWRfZHJtX3N0cmluZ190YWJsZSwKKwlOVUxMLAorfTsKKworc3RhdGljIHZvaWQgZl9ndWRfZHJt X2J1bGtfY29tcGxldGUoc3RydWN0IHVzYl9lcCAqZXAsIHN0cnVjdCB1c2JfcmVxdWVzdCAqcmVx KQoreworCXN0cnVjdCBmX2d1ZF9kcm0gKmZnZCA9IHJlcS0+Y29udGV4dDsKKwl1bnNpZ25lZCBs b25nIGZsYWdzOworCisJaWYgKHJlcS0+c3RhdHVzIHx8IHJlcS0+YWN0dWFsICE9IHJlcS0+bGVu Z3RoKQorCQlyZXR1cm47CisKKwlzcGluX2xvY2tfaXJxc2F2ZSgmZmdkLT5sb2NrLCBmbGFncyk7 CisJZmdkLT5idWxrX3BlbmRpbmcgPSB0cnVlOworCXNwaW5fdW5sb2NrX2lycXJlc3RvcmUoJmZn ZC0+bG9jaywgZmxhZ3MpOworCisJcXVldWVfd29yayhzeXN0ZW1fbG9uZ193cSwgJmZnZC0+d29y a2VyKTsKK30KKworc3RhdGljIGludCBmX2d1ZF9kcm1fY3RybF9yZXFfc2V0X2J1ZmZlcihzdHJ1 Y3QgZl9ndWRfZHJtICpmZ2QsIHZvaWQgKmJ1Ziwgc2l6ZV90IGxlbikKK3sKKwlpbnQgcmV0Owor CisJaWYgKGxlbiAhPSBzaXplb2Yoc3RydWN0IGd1ZF9kcm1fcmVxX3NldF9idWZmZXIpKQorCQly ZXR1cm4gLUVJTlZBTDsKKworCXJldCA9IGd1ZF9kcm1fZ2FkZ2V0X3NldF9idWZmZXIoZmdkLT5n ZGcsIGJ1Zik7CisJaWYgKHJldCA8IDApCisJCXJldHVybiByZXQ7CisKKwlpZiAocmV0ID4gZmdk LT5tYXhfYnVmZmVyX3NpemUpCisJCXJldHVybiAtRU9WRVJGTE9XOworCisJZmdkLT5idWxrX3Jl cS0+bGVuZ3RoID0gcmV0OworCisJcmV0dXJuIHVzYl9lcF9xdWV1ZShmZ2QtPmJ1bGtfZXAsIGZn ZC0+YnVsa19yZXEsIEdGUF9LRVJORUwpOworfQorCitzdGF0aWMgdm9pZCBmX2d1ZF9kcm1fd29y a2VyKHN0cnVjdCB3b3JrX3N0cnVjdCAqd29yaykKK3sKKwlzdHJ1Y3QgZl9ndWRfZHJtICpmZ2Qg PSBjb250YWluZXJfb2Yod29yaywgc3RydWN0IGZfZ3VkX2RybSwgd29ya2VyKTsKKwlib29sIGN0 cmxfcGVuZGluZywgYnVsa19wZW5kaW5nLCBkaXNhYmxlX3BlbmRpbmc7CisJc3RydWN0IGd1ZF9k cm1fZ2FkZ2V0ICpnZGcgPSBmZ2QtPmdkZzsKKwl1bnNpZ25lZCBsb25nIGZsYWdzOworCXUxNiBy ZXF1ZXN0LCB2YWx1ZTsKKwlpbnQgcmV0OworCisJc3Bpbl9sb2NrX2lycXNhdmUoJmZnZC0+bG9j aywgZmxhZ3MpOworCXJlcXVlc3QgPSBmZ2QtPnJlcXVlc3Q7CisJdmFsdWUgPSBmZ2QtPnZhbHVl OworCWN0cmxfcGVuZGluZyA9IGZnZC0+Y3RybF9wZW5kaW5nOworCWJ1bGtfcGVuZGluZyA9IGZn ZC0+YnVsa19wZW5kaW5nOworCWRpc2FibGVfcGVuZGluZyA9IGZnZC0+ZGlzYWJsZV9wZW5kaW5n OworCXNwaW5fdW5sb2NrX2lycXJlc3RvcmUoJmZnZC0+bG9jaywgZmxhZ3MpOworCisJcHJfZGVi dWcoIiVzOiBidWxrX3BlbmRpbmc9JXUgY3RybF9wZW5kaW5nPSV1IGRpc2FibGVfcGVuZGluZz0l dVxuIiwKKwkJIF9fZnVuY19fLCBidWxrX3BlbmRpbmcsIGN0cmxfcGVuZGluZywgZGlzYWJsZV9w ZW5kaW5nKTsKKworCWlmIChkaXNhYmxlX3BlbmRpbmcpIHsKKwkJZ3VkX2RybV9nYWRnZXRfZGlz YWJsZV9waXBlKGdkZyk7CisKKwkJc3Bpbl9sb2NrX2lycXNhdmUoJmZnZC0+bG9jaywgZmxhZ3Mp OworCQlmZ2QtPmRpc2FibGVfcGVuZGluZyA9IGZhbHNlOworCQlzcGluX3VubG9ja19pcnFyZXN0 b3JlKCZmZ2QtPmxvY2ssIGZsYWdzKTsKKwkJcmV0dXJuOworCX0KKworCWlmIChidWxrX3BlbmRp bmcpIHsKKwkJc3RydWN0IHVzYl9yZXF1ZXN0ICpyZXEgPSBmZ2QtPmJ1bGtfcmVxOworCisJCXJl dCA9IGd1ZF9kcm1fZ2FkZ2V0X3dyaXRlX2J1ZmZlcihnZGcsIHJlcS0+YnVmLCByZXEtPmFjdHVh bCk7CisJCWlmIChyZXQpCisJCQlwcl9lcnIoIiVzOiBGYWlsZWQgdG8gd3JpdGUgYnVmZmVyLCBl cnJvcj0lZFxuIiwgX19mdW5jX18sIHJldCk7CisKKwkJc3Bpbl9sb2NrX2lycXNhdmUoJmZnZC0+ bG9jaywgZmxhZ3MpOworCQlmZ2QtPmJ1bGtfcGVuZGluZyA9IGZhbHNlOworCQlzcGluX3VubG9j a19pcnFyZXN0b3JlKCZmZ2QtPmxvY2ssIGZsYWdzKTsKKwl9CisKKwlpZiAoY3RybF9wZW5kaW5n KSB7CisJCXVuc2lnbmVkIGludCBsZW5ndGggPSBmZ2QtPmN0cmxfcmVxLT5sZW5ndGg7CisJCXZv aWQgKmJ1ZiA9IGZnZC0+Y3RybF9yZXEtPmJ1ZjsKKworCQlpZiAocmVxdWVzdCA9PSBHVURfRFJN X1VTQl9SRVFfU0VUX0JVRkZFUikKKwkJCXJldCA9IGZfZ3VkX2RybV9jdHJsX3JlcV9zZXRfYnVm ZmVyKGZnZCwgYnVmLCBsZW5ndGgpOworCQllbHNlCisJCQlyZXQgPSBndWRfZHJtX2dhZGdldF9j dHJsX3NldChnZGcsIHJlcXVlc3QsIHZhbHVlLCBidWYsIGxlbmd0aCk7CisKKwkJc3Bpbl9sb2Nr X2lycXNhdmUoJmZnZC0+bG9jaywgZmxhZ3MpOworCQlpZiAoIWZnZC0+ZXJybm8pIC8qIERvbid0 IHNjcmliYmxlIG92ZXIgYW4gRUJVU1kgb3IgRVNIVVRET1dOICovCisJCQlmZ2QtPmVycm5vID0g LXJldDsKKwkJZmdkLT5jdHJsX3BlbmRpbmcgPSBmYWxzZTsKKwkJZmdkLT5zdGF0dXNfcGVuZGlu ZyA9IGZhbHNlOworCQlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZmZ2QtPmxvY2ssIGZsYWdzKTsK Kwl9Cit9CisKK3N0YXRpYyB2b2lkIGZfZ3VkX2RybV9jdHJsX3JlcV9jb21wbGV0ZShzdHJ1Y3Qg dXNiX2VwICplcCwgc3RydWN0IHVzYl9yZXF1ZXN0ICpyZXEpCit7CisJc3RydWN0IGZfZ3VkX2Ry bSAqZmdkID0gcmVxLT5jb250ZXh0OworCXVuc2lnbmVkIGxvbmcgZmxhZ3M7CisJaW50IHJldCA9 IDA7CisKKwlzcGluX2xvY2tfaXJxc2F2ZSgmZmdkLT5sb2NrLCBmbGFncyk7CisKKwlpZiAocmVx LT5zdGF0dXMpCisJCXJldCA9IHJlcS0+c3RhdHVzOworCWVsc2UgaWYgKHJlcS0+YWN0dWFsICE9 IHJlcS0+bGVuZ3RoKQorCQlyZXQgPSAtRVJFTU9URUlPOworCWlmIChyZXQpIHsKKwkJZmdkLT5l cnJubyA9IC1yZXQ7CisJCWZnZC0+c3RhdHVzX3BlbmRpbmcgPSBmYWxzZTsKKwl9IGVsc2Ugewor CQlmZ2QtPmN0cmxfcGVuZGluZyA9IHRydWU7CisJfQorCisJc3Bpbl91bmxvY2tfaXJxcmVzdG9y ZSgmZmdkLT5sb2NrLCBmbGFncyk7CisKKwlpZiAoIXJldCkKKwkJcXVldWVfd29yayhzeXN0ZW1f bG9uZ193cSwgJmZnZC0+d29ya2VyKTsKK30KKworc3RhdGljIGludCBmX2d1ZF9kcm1fc2V0dXAo c3RydWN0IHVzYl9mdW5jdGlvbiAqZiwgY29uc3Qgc3RydWN0IHVzYl9jdHJscmVxdWVzdCAqY3Ry bCkKK3sKKwlzdHJ1Y3QgdXNiX2NvbXBvc2l0ZV9kZXYgKmNkZXYgPSBmLT5jb25maWctPmNkZXY7 CisJc3RydWN0IGZfZ3VkX2RybSAqZmdkID0gZnVuY190b19mX2d1ZF9kcm0oZik7CisJYm9vbCBp biA9IGN0cmwtPmJSZXF1ZXN0VHlwZSAmIFVTQl9ESVJfSU47CisJdTE2IGxlbmd0aCA9IGxlMTZf dG9fY3B1KGN0cmwtPndMZW5ndGgpOworCXUxNiB2YWx1ZSA9IGxlMTZfdG9fY3B1KGN0cmwtPndW YWx1ZSk7CisJdW5zaWduZWQgbG9uZyBmbGFnczsKKwlpbnQgcmV0OworCisJaWYgKGN0cmwtPmJS ZXF1ZXN0ID09IFVTQl9SRVFfR0VUX1NUQVRVUykgeworCQlzdHJ1Y3QgZ3VkX2RybV9yZXFfZ2V0 X3N0YXR1cyAqc3RhdHVzID0gY2Rldi0+cmVxLT5idWY7CisKKwkJaWYgKCFpbiB8fCBsZW5ndGgg IT0gc2l6ZW9mKCpzdGF0dXMpKQorCQkJcmV0dXJuIC1FSU5WQUw7CisKKwkJc3Bpbl9sb2NrX2ly cXNhdmUoJmZnZC0+bG9jaywgZmxhZ3MpOworCQlzdGF0dXMtPmZsYWdzID0gMDsKKwkJaWYgKGZn ZC0+c3RhdHVzX3BlbmRpbmcpCisJCQlzdGF0dXMtPmZsYWdzIHw9IEdVRF9EUk1fU1RBVFVTX1BF TkRJTkc7CisJCXN0YXR1cy0+ZXJybm8gPSBmZ2QtPmVycm5vOworCQlzcGluX3VubG9ja19pcnFy ZXN0b3JlKCZmZ2QtPmxvY2ssIGZsYWdzKTsKKwl9IGVsc2UgaWYgKGluKSB7CisJCWlmIChsZW5n dGggPiBVU0JfQ09NUF9FUDBfQlVGU0laKSAvKiA0ayAqLworCQkJcmV0dXJuIC1FT1ZFUkZMT1c7 CisKKwkJcmV0ID0gZ3VkX2RybV9nYWRnZXRfY3RybF9nZXQoZmdkLT5nZGcsIGN0cmwtPmJSZXF1 ZXN0LCB2YWx1ZSwKKwkJCQkJICAgICAgY2Rldi0+cmVxLT5idWYsIGxlbmd0aCk7CisJCXNwaW5f bG9ja19pcnFzYXZlKCZmZ2QtPmxvY2ssIGZsYWdzKTsKKwkJZmdkLT5zdGF0dXNfcGVuZGluZyA9 IGZhbHNlOworCQlmZ2QtPmVycm5vID0gcmV0IDwgMCA/IC1yZXQgOiAwOworCQlzcGluX3VubG9j a19pcnFyZXN0b3JlKCZmZ2QtPmxvY2ssIGZsYWdzKTsKKwkJaWYgKHJldCA8IDApCisJCQlyZXR1 cm4gcmV0OworCisJCWxlbmd0aCA9IHJldDsKKwl9IGVsc2UgeworCQlpZiAobGVuZ3RoID4gR1VE X0RSTV9NQVhfVFJBTlNGRVJfU0laRSkKKwkJCXJldHVybiAtRU9WRVJGTE9XOworCisJCXNwaW5f bG9ja19pcnFzYXZlKCZmZ2QtPmxvY2ssIGZsYWdzKTsKKwkJaWYgKGZnZC0+Y3RybF9wZW5kaW5n KSB7CisJCQkvKiBJZiB3ZSBnZXQgaGVyZSB0aGUgaG9zdCBoYXMgdGltZWQgb3V0IG9uIHRoZSBw cmV2aW91cyByZXF1ZXN0ICovCisJCQlyZXQgPSAtRUJVU1k7CisJCQlmZ2QtPnN0YXR1c19wZW5k aW5nID0gZmFsc2U7CisJCQlmZ2QtPmVycm5vID0gLXJldDsKKwkJfSBlbHNlIHsKKwkJCXJldCA9 IDA7CisJCQlmZ2QtPmVycm5vID0gMDsKKwkJCWZnZC0+cmVxdWVzdCA9IGN0cmwtPmJSZXF1ZXN0 OworCQkJZmdkLT52YWx1ZSA9IHZhbHVlOworCQkJZmdkLT5zdGF0dXNfcGVuZGluZyA9IHRydWU7 CisJCX0KKwkJc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgmZmdkLT5sb2NrLCBmbGFncyk7CisKKwkJ aWYgKHJldCkKKwkJCXJldHVybiByZXQ7CisKKwkJZmdkLT5jdHJsX3JlcS0+bGVuZ3RoID0gbGVu Z3RoOworCisJCXJldHVybiB1c2JfZXBfcXVldWUoY2Rldi0+Z2FkZ2V0LT5lcDAsIGZnZC0+Y3Ry bF9yZXEsIEdGUF9BVE9NSUMpOworCX0KKworCWNkZXYtPnJlcS0+bGVuZ3RoID0gbGVuZ3RoOwor CisJcmV0dXJuIHVzYl9lcF9xdWV1ZShjZGV2LT5nYWRnZXQtPmVwMCwgY2Rldi0+cmVxLCBHRlBf QVRPTUlDKTsKK30KKworc3RhdGljIGJvb2wgZl9ndWRfZHJtX3JlcV9tYXRjaChzdHJ1Y3QgdXNi X2Z1bmN0aW9uICpmLCBjb25zdCBzdHJ1Y3QgdXNiX2N0cmxyZXF1ZXN0ICpjdHJsLAorCQkJCWJv b2wgY29uZmlnMCkKK3sKKwlzdHJ1Y3QgZl9ndWRfZHJtICpmZ2QgPSBmdW5jX3RvX2ZfZ3VkX2Ry bShmKTsKKworCWlmIChjb25maWcwKQorCQlyZXR1cm4gZmFsc2U7CisKKwlpZiAoKGN0cmwtPmJS ZXF1ZXN0VHlwZSAmIFVTQl9UWVBFX01BU0spICE9IFVTQl9UWVBFX1ZFTkRPUikKKwkJcmV0dXJu IGZhbHNlOworCisJaWYgKChjdHJsLT5iUmVxdWVzdFR5cGUgJiBVU0JfUkVDSVBfTUFTSykgIT0g VVNCX1JFQ0lQX0lOVEVSRkFDRSkKKwkJcmV0dXJuIGZhbHNlOworCisJcmV0dXJuIGZnZC0+aW50 ZXJmYWNlX2lkID09IGxlMTZfdG9fY3B1KGN0cmwtPndJbmRleCk7Cit9CisKK3N0YXRpYyBpbnQg Zl9ndWRfZHJtX3NldF9hbHQoc3RydWN0IHVzYl9mdW5jdGlvbiAqZiwgdW5zaWduZWQgaW50IGlu dGYsIHVuc2lnbmVkIGludCBhbHQpCit7CisJc3RydWN0IHVzYl9jb21wb3NpdGVfZGV2ICpjZGV2 ID0gZi0+Y29uZmlnLT5jZGV2OworCXN0cnVjdCBmX2d1ZF9kcm0gKmZnZCA9IGZ1bmNfdG9fZl9n dWRfZHJtKGYpOworCXVuc2lnbmVkIGxvbmcgZmxhZ3M7CisKKwlpZiAoYWx0IHx8IGludGYgIT0g ZmdkLT5pbnRlcmZhY2VfaWQpCisJCXJldHVybiAtRUlOVkFMOworCisJaWYgKCFmZ2QtPmJ1bGtf ZXAtPmRlc2MpIHsKKwkJcHJfZGVidWcoIiVzOiBpbml0XG4iLCBfX2Z1bmNfXyk7CisJCWlmIChj b25maWdfZXBfYnlfc3BlZWQoY2Rldi0+Z2FkZ2V0LCBmLCBmZ2QtPmJ1bGtfZXApKSB7CisJCQlm Z2QtPmJ1bGtfZXAtPmRlc2MgPSBOVUxMOworCQkJcmV0dXJuIC1FSU5WQUw7CisJCX0KKwl9CisK Kwlwcl9kZWJ1ZygiJXM6IHJlc2V0XG4iLCBfX2Z1bmNfXyk7CisKKwl1c2JfZXBfZGlzYWJsZShm Z2QtPmJ1bGtfZXApOworCXVzYl9lcF9lbmFibGUoZmdkLT5idWxrX2VwKTsKKworCXNwaW5fbG9j a19pcnFzYXZlKCZmZ2QtPmxvY2ssIGZsYWdzKTsKKwlmZ2QtPmN0cmxfcGVuZGluZyA9IGZhbHNl OworCWZnZC0+YnVsa19wZW5kaW5nID0gZmFsc2U7CisJZmdkLT5kaXNhYmxlX3BlbmRpbmcgPSBm YWxzZTsKKwlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZmZ2QtPmxvY2ssIGZsYWdzKTsKKworCXJl dHVybiAwOworfQorCitzdGF0aWMgdm9pZCBmX2d1ZF9kcm1fZGlzYWJsZShzdHJ1Y3QgdXNiX2Z1 bmN0aW9uICpmKQoreworCXN0cnVjdCBmX2d1ZF9kcm0gKmZnZCA9IGZ1bmNfdG9fZl9ndWRfZHJt KGYpOworCXVuc2lnbmVkIGxvbmcgZmxhZ3M7CisKKwlwcl9kZWJ1ZygiJXNcbiIsIF9fZnVuY19f KTsKKworCXVzYl9lcF9kaXNhYmxlKGZnZC0+YnVsa19lcCk7CisKKwlzcGluX2xvY2tfaXJxc2F2 ZSgmZmdkLT5sb2NrLCBmbGFncyk7CisJZmdkLT5jdHJsX3BlbmRpbmcgPSBmYWxzZTsKKwlmZ2Qt PmJ1bGtfcGVuZGluZyA9IGZhbHNlOworCWZnZC0+c3RhdHVzX3BlbmRpbmcgPSBmYWxzZTsKKwlm Z2QtPmRpc2FibGVfcGVuZGluZyA9IHRydWU7CisJZmdkLT5lcnJubyA9IEVTSFVURE9XTjsKKwlz cGluX3VubG9ja19pcnFyZXN0b3JlKCZmZ2QtPmxvY2ssIGZsYWdzKTsKKworCXF1ZXVlX3dvcmso c3lzdGVtX2xvbmdfd3EsICZmZ2QtPndvcmtlcik7Cit9CisKK3N0YXRpYyB2b2lkIGZfZ3VkX2Ry bV91bmJpbmQoc3RydWN0IHVzYl9jb25maWd1cmF0aW9uICpjLCBzdHJ1Y3QgdXNiX2Z1bmN0aW9u ICpmKQoreworCXN0cnVjdCBmX2d1ZF9kcm0gKmZnZCA9IGZ1bmNfdG9fZl9ndWRfZHJtKGYpOwor CXN0cnVjdCB1c2JfY29tcG9zaXRlX2RldiAqY2RldiA9IGZnZC0+ZnVuYy5jb25maWctPmNkZXY7 CisKKwlmbHVzaF93b3JrKCZmZ2QtPndvcmtlcik7CisKKwlndWRfZHJtX2dhZGdldF9maW5pKGZn ZC0+Z2RnKTsKKwlmZ2QtPmdkZyA9IE5VTEw7CisKKwlrZnJlZShmZ2QtPmJ1bGtfcmVxLT5idWYp OworCXVzYl9lcF9mcmVlX3JlcXVlc3QoZmdkLT5idWxrX2VwLCBmZ2QtPmJ1bGtfcmVxKTsKKwl1 c2JfZXBfZnJlZV9yZXF1ZXN0KGNkZXYtPmdhZGdldC0+ZXAwLCBmZ2QtPmN0cmxfcmVxKTsKKwlm Z2QtPmN0cmxfcmVxID0gTlVMTDsKKwlmZ2QtPmJ1bGtfcmVxID0gTlVMTDsKKwlmZ2QtPmJ1bGtf ZXAgPSBOVUxMOworCisJdXNiX2ZyZWVfYWxsX2Rlc2NyaXB0b3JzKGYpOworfQorCitzdGF0aWMg aW50IGZfZ3VkX2RybV9iaW5kKHN0cnVjdCB1c2JfY29uZmlndXJhdGlvbiAqYywgc3RydWN0IHVz Yl9mdW5jdGlvbiAqZikKK3sKKwlzdHJ1Y3QgZl9ndWRfZHJtX29wdHMgKm9wdHMgPSBmaV90b19m X2d1ZF9kcm1fb3B0cyhmLT5maSk7CisJc3RydWN0IHVzYl9jb21wb3NpdGVfZGV2ICpjZGV2ID0g Yy0+Y2RldjsKKwlzdHJ1Y3QgZl9ndWRfZHJtICpmZ2QgPSBmdW5jX3RvX2ZfZ3VkX2RybShmKTsK KwlzdHJ1Y3QgdXNiX3JlcXVlc3QgKmN0cmxfcmVxLCAqYnVsa19yZXE7CisJc3RydWN0IGd1ZF9k cm1fZ2FkZ2V0ICpnZGc7CisJc3RydWN0IHVzYl9zdHJpbmcgKnVzOworCXZvaWQgKmJ1ZjsKKwlp bnQgcmV0OworCisJdXMgPSB1c2JfZ3N0cmluZ3NfYXR0YWNoKGNkZXYsIGZfZ3VkX2RybV9zdHJp bmdzLAorCQkJCSBBUlJBWV9TSVpFKGZfZ3VkX2RybV9zdHJpbmdfZGVmcykpOworCWlmIChJU19F UlIodXMpKQorCQlyZXR1cm4gUFRSX0VSUih1cyk7CisKKwlmX2d1ZF9kcm1faW50Zi5pSW50ZXJm YWNlID0gdXNbMF0uaWQ7CisKKwlyZXQgPSB1c2JfaW50ZXJmYWNlX2lkKGMsIGYpOworCWlmIChy ZXQgPCAwKQorCQlyZXR1cm4gcmV0OworCisJZmdkLT5pbnRlcmZhY2VfaWQgPSByZXQ7CisJZl9n dWRfZHJtX2ludGYuYkludGVyZmFjZU51bWJlciA9IGZnZC0+aW50ZXJmYWNlX2lkOworCisJZmdk LT5idWxrX2VwID0gdXNiX2VwX2F1dG9jb25maWcoY2Rldi0+Z2FkZ2V0LCAmZl9ndWRfZHJtX2Zz X291dF9kZXNjKTsKKwlpZiAoIWZnZC0+YnVsa19lcCkKKwkJcmV0dXJuIC1FTk9ERVY7CisKKwlm X2d1ZF9kcm1faHNfb3V0X2Rlc2MuYkVuZHBvaW50QWRkcmVzcyA9IGZfZ3VkX2RybV9mc19vdXRf ZGVzYy5iRW5kcG9pbnRBZGRyZXNzOworCisJZl9ndWRfZHJtX3NzX291dF9kZXNjLmJFbmRwb2lu dEFkZHJlc3MgPSBmX2d1ZF9kcm1fZnNfb3V0X2Rlc2MuYkVuZHBvaW50QWRkcmVzczsKKworCXJl dCA9IHVzYl9hc3NpZ25fZGVzY3JpcHRvcnMoZiwgZl9ndWRfZHJtX2ZzX2Z1bmN0aW9uLCBmX2d1 ZF9kcm1faHNfZnVuY3Rpb24sCisJCQkJICAgICBmX2d1ZF9kcm1fc3NfZnVuY3Rpb24sIE5VTEwp OworCWlmIChyZXQpCisJCXJldHVybiByZXQ7CisKKwljdHJsX3JlcSA9IHVzYl9lcF9hbGxvY19y ZXF1ZXN0KGNkZXYtPmdhZGdldC0+ZXAwLCBHRlBfS0VSTkVMKTsKKwlpZiAoIWN0cmxfcmVxKSB7 CisJCXJldCA9IC1FTk9NRU07CisJCWdvdG8gZmFpbF9mcmVlX2Rlc2NzOworCX0KKworCWN0cmxf cmVxLT5idWYgPSBmZ2QtPmN0cmxfcmVxX2J1ZjsKKwljdHJsX3JlcS0+Y29tcGxldGUgPSBmX2d1 ZF9kcm1fY3RybF9yZXFfY29tcGxldGU7CisJY3RybF9yZXEtPmNvbnRleHQgPSBmZ2Q7CisKKwln ZGcgPSBndWRfZHJtX2dhZGdldF9pbml0KG9wdHMtPmRybV9kZXYsIG9wdHMtPmJhY2tsaWdodF9k ZXYsICZmZ2QtPm1heF9idWZmZXJfc2l6ZSk7CisJaWYgKElTX0VSUihnZGcpKSB7CisJCXJldCA9 IFBUUl9FUlIoZ2RnKTsKKwkJZ290byBmYWlsX2ZyZWVfY3RybF9yZXE7CisJfQorCisJYnVsa19y ZXEgPSB1c2JfZXBfYWxsb2NfcmVxdWVzdChmZ2QtPmJ1bGtfZXAsIEdGUF9LRVJORUwpOworCWlm ICghYnVsa19yZXEpIHsKKwkJcmV0ID0gLUVOT01FTTsKKwkJZ290byBmYWlsX2ZyZWVfY3RybF9y ZXE7CisJfQorCisJYnVmID0ga21hbGxvYyhmZ2QtPm1heF9idWZmZXJfc2l6ZSwgR0ZQX0tFUk5F TCk7CisJaWYgKCFidWYpIHsKKwkJcmV0ID0gLUVOT01FTTsKKwkJZ290byBmYWlsX2ZyZWVfYnVs a19yZXE7CisJfQorCisJYnVsa19yZXEtPmNvbXBsZXRlID0gZl9ndWRfZHJtX2J1bGtfY29tcGxl dGU7CisJYnVsa19yZXEtPmNvbnRleHQgPSBmZ2Q7CisJYnVsa19yZXEtPmJ1ZiA9IGJ1ZjsKKwor CWZnZC0+Y3RybF9yZXEgPSBjdHJsX3JlcTsKKwlmZ2QtPmJ1bGtfcmVxID0gYnVsa19yZXE7CisJ ZmdkLT5nZGcgPSBnZGc7CisKKwlyZXR1cm4gMDsKKworZmFpbF9mcmVlX2J1bGtfcmVxOgorCXVz Yl9lcF9mcmVlX3JlcXVlc3QoZmdkLT5idWxrX2VwLCBidWxrX3JlcSk7CitmYWlsX2ZyZWVfY3Ry bF9yZXE6CisJdXNiX2VwX2ZyZWVfcmVxdWVzdChjZGV2LT5nYWRnZXQtPmVwMCwgY3RybF9yZXEp OworZmFpbF9mcmVlX2Rlc2NzOgorCXVzYl9mcmVlX2FsbF9kZXNjcmlwdG9ycyhmKTsKKworCXJl dHVybiByZXQ7Cit9CisKK3N0YXRpYyB2b2lkIGZfZ3VkX2RybV9mcmVlX2Z1bmMoc3RydWN0IHVz Yl9mdW5jdGlvbiAqZikKK3sKKwlzdHJ1Y3QgZl9ndWRfZHJtX29wdHMgKm9wdHMgPSBjb250YWlu ZXJfb2YoZi0+ZmksIHN0cnVjdCBmX2d1ZF9kcm1fb3B0cywgZnVuY19pbnN0KTsKKwlzdHJ1Y3Qg Zl9ndWRfZHJtICpmZ2QgPSBmdW5jX3RvX2ZfZ3VkX2RybShmKTsKKworCW11dGV4X2xvY2soJm9w dHMtPmxvY2spOworCW9wdHMtPnJlZmNudC0tOworCW11dGV4X3VubG9jaygmb3B0cy0+bG9jayk7 CisKKwlrZnJlZShmZ2QtPmN0cmxfcmVxX2J1Zik7CisJa2ZyZWUoZmdkKTsKK30KKworc3RhdGlj IHN0cnVjdCB1c2JfZnVuY3Rpb24gKmZfZ3VkX2RybV9hbGxvY19mdW5jKHN0cnVjdCB1c2JfZnVu Y3Rpb25faW5zdGFuY2UgKmZpKQoreworCXN0cnVjdCBmX2d1ZF9kcm1fb3B0cyAqb3B0cyA9IGZp X3RvX2ZfZ3VkX2RybV9vcHRzKGZpKTsKKwlzdHJ1Y3QgdXNiX2Z1bmN0aW9uICpmdW5jOworCXN0 cnVjdCBmX2d1ZF9kcm0gKmZnZDsKKworCWZnZCA9IGt6YWxsb2Moc2l6ZW9mKCpmZ2QpLCBHRlBf S0VSTkVMKTsKKwlpZiAoIWZnZCkKKwkJcmV0dXJuIEVSUl9QVFIoLUVOT01FTSk7CisKKwlmZ2Qt PmN0cmxfcmVxX2J1ZiA9IGttYWxsb2MoR1VEX0RSTV9NQVhfVFJBTlNGRVJfU0laRSwgR0ZQX0tF Uk5FTCk7CisJaWYgKCFmZ2QtPmN0cmxfcmVxX2J1ZikKKwkJZ290byBlcnJvcjsKKworCXNwaW5f bG9ja19pbml0KCZmZ2QtPmxvY2spOworCUlOSVRfV09SSygmZmdkLT53b3JrZXIsIGZfZ3VkX2Ry bV93b3JrZXIpOworCisJbXV0ZXhfbG9jaygmb3B0cy0+bG9jayk7CisJb3B0cy0+cmVmY250Kys7 CisJbXV0ZXhfdW5sb2NrKCZvcHRzLT5sb2NrKTsKKworCWZ1bmMgPSAmZmdkLT5mdW5jOworCWZ1 bmMtPm5hbWUgPSAiZ3VkX2RybSI7CisJZnVuYy0+YmluZCA9IGZfZ3VkX2RybV9iaW5kOworCWZ1 bmMtPnVuYmluZCA9IGZfZ3VkX2RybV91bmJpbmQ7CisJZnVuYy0+c2V0X2FsdCA9IGZfZ3VkX2Ry bV9zZXRfYWx0OworCWZ1bmMtPnJlcV9tYXRjaCA9IGZfZ3VkX2RybV9yZXFfbWF0Y2g7CisJZnVu Yy0+c2V0dXAgPSBmX2d1ZF9kcm1fc2V0dXA7CisJZnVuYy0+ZGlzYWJsZSA9IGZfZ3VkX2RybV9k aXNhYmxlOworCWZ1bmMtPmZyZWVfZnVuYyA9IGZfZ3VkX2RybV9mcmVlX2Z1bmM7CisKKwlyZXR1 cm4gZnVuYzsKKworZXJyb3I6CisJa2ZyZWUoZmdkKTsKKworCXJldHVybiBFUlJfUFRSKC1FTk9N RU0pOworfQorCitzdGF0aWMgc3NpemVfdCBmX2d1ZF9kcm1fb3B0c19kcm1fZGV2X3Nob3coc3Ry dWN0IGNvbmZpZ19pdGVtICppdGVtLCBjaGFyICpwYWdlKQoreworCXN0cnVjdCBmX2d1ZF9kcm1f b3B0cyAqb3B0cyA9IGNpX3RvX2ZfZ3VkX2RybV9vcHRzKGl0ZW0pOworCWludCByZXN1bHQ7CisK KwltdXRleF9sb2NrKCZvcHRzLT5sb2NrKTsKKwlyZXN1bHQgPSBzcHJpbnRmKHBhZ2UsICIldVxu Iiwgb3B0cy0+ZHJtX2Rldik7CisJbXV0ZXhfdW5sb2NrKCZvcHRzLT5sb2NrKTsKKworCXJldHVy biByZXN1bHQ7Cit9CisKK3N0YXRpYyBzc2l6ZV90IGZfZ3VkX2RybV9vcHRzX2RybV9kZXZfc3Rv cmUoc3RydWN0IGNvbmZpZ19pdGVtICppdGVtLAorCQkJCQkgICAgY29uc3QgY2hhciAqcGFnZSwg c2l6ZV90IGxlbikKK3sKKwlzdHJ1Y3QgZl9ndWRfZHJtX29wdHMgKm9wdHMgPSBjaV90b19mX2d1 ZF9kcm1fb3B0cyhpdGVtKTsKKwl1bnNpZ25lZCBpbnQgbnVtOworCWludCByZXQ7CisKKwltdXRl eF9sb2NrKCZvcHRzLT5sb2NrKTsKKwlpZiAob3B0cy0+cmVmY250KSB7CisJCXJldCA9IC1FQlVT WTsKKwkJZ290byB1bmxvY2s7CisJfQorCisJcmV0ID0ga3N0cnRvdWludChwYWdlLCAwLCAmbnVt KTsKKwlpZiAocmV0KQorCQlnb3RvIHVubG9jazsKKworCW9wdHMtPmRybV9kZXYgPSBudW07CisJ cmV0ID0gbGVuOwordW5sb2NrOgorCW11dGV4X3VubG9jaygmb3B0cy0+bG9jayk7CisKKwlyZXR1 cm4gcmV0OworfQorCitDT05GSUdGU19BVFRSKGZfZ3VkX2RybV9vcHRzXywgZHJtX2Rldik7CisK K3N0YXRpYyBzc2l6ZV90IGZfZ3VkX2RybV9vcHRzX2JhY2tsaWdodF9kZXZfc2hvdyhzdHJ1Y3Qg Y29uZmlnX2l0ZW0gKml0ZW0sIGNoYXIgKnBhZ2UpCit7CisJc3RydWN0IGZfZ3VkX2RybV9vcHRz ICpvcHRzID0gY2lfdG9fZl9ndWRfZHJtX29wdHMoaXRlbSk7CisJc3NpemVfdCByZXQgPSAwOwor CisJbXV0ZXhfbG9jaygmb3B0cy0+bG9jayk7CisJaWYgKG9wdHMtPmJhY2tsaWdodF9kZXYpCisJ CXJldCA9IHN0cnNjcHkocGFnZSwgb3B0cy0+YmFja2xpZ2h0X2RldiwgUEFHRV9TSVpFKTsKKwll bHNlCisJCXBhZ2VbMF0gPSAnXDAnOworCW11dGV4X3VubG9jaygmb3B0cy0+bG9jayk7CisKKwly ZXR1cm4gcmV0OworfQorCitzdGF0aWMgc3NpemVfdCBmX2d1ZF9kcm1fb3B0c19iYWNrbGlnaHRf ZGV2X3N0b3JlKHN0cnVjdCBjb25maWdfaXRlbSAqaXRlbSwKKwkJCQkJCSAgY29uc3QgY2hhciAq cGFnZSwgc2l6ZV90IGxlbikKK3sKKwlzdHJ1Y3QgZl9ndWRfZHJtX29wdHMgKm9wdHMgPSBjaV90 b19mX2d1ZF9kcm1fb3B0cyhpdGVtKTsKKwlzc2l6ZV90IHJldDsKKwljaGFyICpuYW1lOworCisJ bXV0ZXhfbG9jaygmb3B0cy0+bG9jayk7CisJaWYgKG9wdHMtPnJlZmNudCkgeworCQlyZXQgPSAt RUJVU1k7CisJCWdvdG8gdW5sb2NrOworCX0KKworCW5hbWUgPSBrc3RybmR1cChwYWdlLCBsZW4s IEdGUF9LRVJORUwpOworCWlmICghbmFtZSkgeworCQlyZXQgPSAtRU5PTUVNOworCQlnb3RvIHVu bG9jazsKKwl9CisKKwlrZnJlZShvcHRzLT5iYWNrbGlnaHRfZGV2KTsKKwlvcHRzLT5iYWNrbGln aHRfZGV2ID0gbmFtZTsKKwlyZXQgPSBsZW47Cit1bmxvY2s6CisJbXV0ZXhfdW5sb2NrKCZvcHRz LT5sb2NrKTsKKworCXJldHVybiByZXQ7Cit9CisKK0NPTkZJR0ZTX0FUVFIoZl9ndWRfZHJtX29w dHNfLCBiYWNrbGlnaHRfZGV2KTsKKworc3RhdGljIHN0cnVjdCBjb25maWdmc19hdHRyaWJ1dGUg KmZfZ3VkX2RybV9hdHRyc1tdID0geworCSZmX2d1ZF9kcm1fb3B0c19hdHRyX2RybV9kZXYsCisJ JmZfZ3VkX2RybV9vcHRzX2F0dHJfYmFja2xpZ2h0X2RldiwKKwlOVUxMLAorfTsKKworc3RhdGlj IHZvaWQgZl9ndWRfZHJtX2F0dHJfcmVsZWFzZShzdHJ1Y3QgY29uZmlnX2l0ZW0gKml0ZW0pCit7 CisJc3RydWN0IGZfZ3VkX2RybV9vcHRzICpvcHRzID0gY2lfdG9fZl9ndWRfZHJtX29wdHMoaXRl bSk7CisKKwl1c2JfcHV0X2Z1bmN0aW9uX2luc3RhbmNlKCZvcHRzLT5mdW5jX2luc3QpOworfQor CitzdGF0aWMgc3RydWN0IGNvbmZpZ2ZzX2l0ZW1fb3BlcmF0aW9ucyBmX2d1ZF9kcm1faXRlbV9v cHMgPSB7CisJLnJlbGVhc2UJPSBmX2d1ZF9kcm1fYXR0cl9yZWxlYXNlLAorfTsKKworc3RhdGlj IGNvbnN0IHN0cnVjdCBjb25maWdfaXRlbV90eXBlIGZfZ3VkX2RybV9mdW5jX3R5cGUgPSB7CisJ LmN0X2l0ZW1fb3BzCT0gJmZfZ3VkX2RybV9pdGVtX29wcywKKwkuY3RfYXR0cnMJPSBmX2d1ZF9k cm1fYXR0cnMsCisJLmN0X293bmVyCT0gVEhJU19NT0RVTEUsCit9OworCitzdGF0aWMgdm9pZCBm X2d1ZF9kcm1fZnJlZV9mdW5jX2luc3Qoc3RydWN0IHVzYl9mdW5jdGlvbl9pbnN0YW5jZSAqZmkp Cit7CisJc3RydWN0IGZfZ3VkX2RybV9vcHRzICpvcHRzID0gZmlfdG9fZl9ndWRfZHJtX29wdHMo ZmkpOworCisJbXV0ZXhfZGVzdHJveSgmb3B0cy0+bG9jayk7CisJa2ZyZWUob3B0cy0+YmFja2xp Z2h0X2Rldik7CisJa2ZyZWUob3B0cyk7Cit9CisKK3N0YXRpYyBzdHJ1Y3QgdXNiX2Z1bmN0aW9u X2luc3RhbmNlICpmX2d1ZF9kcm1fYWxsb2NfZnVuY19pbnN0KHZvaWQpCit7CisJc3RydWN0IGZf Z3VkX2RybV9vcHRzICpvcHRzOworCisJb3B0cyA9IGt6YWxsb2Moc2l6ZW9mKCpvcHRzKSwgR0ZQ X0tFUk5FTCk7CisJaWYgKCFvcHRzKQorCQlyZXR1cm4gRVJSX1BUUigtRU5PTUVNKTsKKworCW11 dGV4X2luaXQoJm9wdHMtPmxvY2spOworCW9wdHMtPmZ1bmNfaW5zdC5mcmVlX2Z1bmNfaW5zdCA9 IGZfZ3VkX2RybV9mcmVlX2Z1bmNfaW5zdDsKKworCWNvbmZpZ19ncm91cF9pbml0X3R5cGVfbmFt ZSgmb3B0cy0+ZnVuY19pbnN0Lmdyb3VwLCAiIiwgJmZfZ3VkX2RybV9mdW5jX3R5cGUpOworCisJ cmV0dXJuICZvcHRzLT5mdW5jX2luc3Q7Cit9CisKK0RFQ0xBUkVfVVNCX0ZVTkNUSU9OX0lOSVQo Z3VkX2RybSwgZl9ndWRfZHJtX2FsbG9jX2Z1bmNfaW5zdCwgZl9ndWRfZHJtX2FsbG9jX2Z1bmMp OworCitNT0RVTEVfREVTQ1JJUFRJT04oIkdlbmVyaWMgVVNCIERpc3BsYXkgR2FkZ2V0Iik7CitN T0RVTEVfQVVUSE9SKCJOb3JhbGYgVHLDuG5uZXMiKTsKK01PRFVMRV9MSUNFTlNFKCJHUEwiKTsK LS0gCjIuMjMuMAoKX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f X18KZHJpLWRldmVsIG1haWxpbmcgbGlzdApkcmktZGV2ZWxAbGlzdHMuZnJlZWRlc2t0b3Aub3Jn Cmh0dHBzOi8vbGlzdHMuZnJlZWRlc2t0b3Aub3JnL21haWxtYW4vbGlzdGluZm8vZHJpLWRldmVs Cg==