From mboxrd@z Thu Jan 1 00:00:00 1970 From: architt@codeaurora.org (Archit Taneja) Date: Fri, 26 Feb 2016 14:24:18 +0530 Subject: [PATCH v6 02/11] drm/hisilicon: Add hisilicon kirin drm master driver In-Reply-To: <1456476028-36880-3-git-send-email-xinliang.liu@linaro.org> References: <1456476028-36880-1-git-send-email-xinliang.liu@linaro.org> <1456476028-36880-3-git-send-email-xinliang.liu@linaro.org> Message-ID: <56D012BA.9000509@codeaurora.org> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Hi, I had some minor comments. Sorry about sharing this late. Otherwise, the looks good to me. On 02/26/2016 02:10 PM, Xinliang Liu wrote: > Add kirin DRM master driver for hi6220 SoC which used in HiKey board. > Add dumb buffer feature. > Add prime dmabuf feature. > > v6: None. > v5: None. > v4: None. > v3: > - Move and rename all the files to kirin sub-directory. > So that we could separate different seires SoCs' driver. > - Replace drm_platform_init, load, unload implementation. > v2: > - Remove abtraction layer. > > Signed-off-by: Xinliang Liu > --- > drivers/gpu/drm/Kconfig | 2 + > drivers/gpu/drm/Makefile | 1 + > drivers/gpu/drm/hisilicon/Kconfig | 5 + > drivers/gpu/drm/hisilicon/Makefile | 5 + > drivers/gpu/drm/hisilicon/kirin/Kconfig | 9 + > drivers/gpu/drm/hisilicon/kirin/Makefile | 3 + > drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c | 321 ++++++++++++++++++++++++ > drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h | 20 ++ > 8 files changed, 366 insertions(+) > create mode 100644 drivers/gpu/drm/hisilicon/Kconfig > create mode 100644 drivers/gpu/drm/hisilicon/Makefile > create mode 100644 drivers/gpu/drm/hisilicon/kirin/Kconfig > create mode 100644 drivers/gpu/drm/hisilicon/kirin/Makefile > create mode 100644 drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c > create mode 100644 drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h > > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig > index b50ae60f5f50..f5c5656e2547 100644 > --- a/drivers/gpu/drm/Kconfig > +++ b/drivers/gpu/drm/Kconfig > @@ -277,3 +277,5 @@ source "drivers/gpu/drm/imx/Kconfig" > source "drivers/gpu/drm/vc4/Kconfig" > > source "drivers/gpu/drm/etnaviv/Kconfig" > + > +source "drivers/gpu/drm/hisilicon/Kconfig" > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile > index 61766dec6a8d..60554832079c 100644 > --- a/drivers/gpu/drm/Makefile > +++ b/drivers/gpu/drm/Makefile > @@ -74,3 +74,4 @@ obj-y += panel/ > obj-y += bridge/ > obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/ > obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/ > +obj-y += hisilicon/ > diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig > new file mode 100644 > index 000000000000..558c61b1b8e8 > --- /dev/null > +++ b/drivers/gpu/drm/hisilicon/Kconfig > @@ -0,0 +1,5 @@ > +# > +# hisilicon drm device configuration. > +# Please keep this list sorted alphabetically > + > +source "drivers/gpu/drm/hisilicon/kirin/Kconfig" > diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile > new file mode 100644 > index 000000000000..e3f6d493c996 > --- /dev/null > +++ b/drivers/gpu/drm/hisilicon/Makefile > @@ -0,0 +1,5 @@ > +# > +# Makefile for hisilicon drm drivers. > +# Please keep this list sorted alphabetically > + > +obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/ > diff --git a/drivers/gpu/drm/hisilicon/kirin/Kconfig b/drivers/gpu/drm/hisilicon/kirin/Kconfig > new file mode 100644 > index 000000000000..3ac4b8edeac1 > --- /dev/null > +++ b/drivers/gpu/drm/hisilicon/kirin/Kconfig > @@ -0,0 +1,9 @@ > +config DRM_HISI_KIRIN > + tristate "DRM Support for Hisilicon Kirin series SoCs Platform" > + depends on DRM > + select DRM_KMS_HELPER > + select DRM_GEM_CMA_HELPER > + select DRM_KMS_CMA_HELPER > + help > + Choose this option if you have a hisilicon Kirin chipsets(hi6220). > + If M is selected the module will be called kirin-drm. > diff --git a/drivers/gpu/drm/hisilicon/kirin/Makefile b/drivers/gpu/drm/hisilicon/kirin/Makefile > new file mode 100644 > index 000000000000..cb346de47d48 > --- /dev/null > +++ b/drivers/gpu/drm/hisilicon/kirin/Makefile > @@ -0,0 +1,3 @@ > +kirin-drm-y := kirin_drm_drv.o > + > +obj-$(CONFIG_DRM_HISI_KIRIN) += kirin-drm.o > diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c > new file mode 100644 > index 000000000000..789ebd1f5922 > --- /dev/null > +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c > @@ -0,0 +1,321 @@ > +/* > + * Hisilicon Kirin SoCs drm master driver > + * > + * Copyright (c) 2016 Linaro Limited. > + * Copyright (c) 2014-2016 Hisilicon Limited. > + * > + * Author: > + * Xinliang Liu > + * Xinliang Liu > + * Xinwei Kong > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + */ > + > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > + > +#include "kirin_drm_drv.h" > + > +static struct kirin_dc_ops *dc_ops; > + > +static int kirin_drm_kms_cleanup(struct drm_device *dev) > +{ > + dc_ops->cleanup(dev); > + drm_mode_config_cleanup(dev); > + > + return 0; > +} > + > +static const struct drm_mode_config_funcs kirin_drm_mode_config_funcs = { > + .fb_create = drm_fb_cma_create, > + .atomic_check = drm_atomic_helper_check, > + .atomic_commit = drm_atomic_helper_commit, > +}; > + > +static void kirin_drm_mode_config_init(struct drm_device *dev) > +{ > + dev->mode_config.min_width = 0; > + dev->mode_config.min_height = 0; > + > + dev->mode_config.max_width = 2048; > + dev->mode_config.max_height = 2048; > + > + dev->mode_config.funcs = &kirin_drm_mode_config_funcs; > +} > + > +static int kirin_drm_kms_init(struct drm_device *dev) > +{ > + int ret; > + > + dev_set_drvdata(dev->dev, dev); > + > + /* dev->mode_config initialization */ > + drm_mode_config_init(dev); > + kirin_drm_mode_config_init(dev); > + > + /* display controller init */ > + ret = dc_ops->init(dev); > + if (ret) > + goto err_mode_config_cleanup; > + > + /* bind and init sub drivers */ > + ret = component_bind_all(dev->dev, dev); > + if (ret) { > + DRM_ERROR("failed to bind all component.\n"); > + goto err_dc_cleanup; > + } > + > + /* reset all the states of crtc/plane/encoder/connector */ > + drm_mode_config_reset(dev); > + > + return 0; > + > +err_dc_cleanup: > + dc_ops->cleanup(dev); > +err_mode_config_cleanup: > + drm_mode_config_cleanup(dev); > + > + return ret; > +} > + > +static const struct file_operations kirin_drm_fops = { > + .owner = THIS_MODULE, > + .open = drm_open, > + .release = drm_release, > + .unlocked_ioctl = drm_ioctl, > +#ifdef CONFIG_COMPAT > + .compat_ioctl = drm_compat_ioctl, > +#endif > + .poll = drm_poll, > + .read = drm_read, > + .llseek = no_llseek, > + .mmap = drm_gem_cma_mmap, > +}; > + > +static int kirin_gem_cma_dumb_create(struct drm_file *file, > + struct drm_device *dev, > + struct drm_mode_create_dumb *args) > +{ > + return drm_gem_cma_dumb_create_internal(file, dev, args); > +} > + > +static struct drm_driver kirin_drm_driver = { > + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | > + DRIVER_ATOMIC, > + .fops = &kirin_drm_fops, > + .set_busid = drm_platform_set_busid, > + > + .gem_free_object = drm_gem_cma_free_object, > + .gem_vm_ops = &drm_gem_cma_vm_ops, > + .dumb_create = kirin_gem_cma_dumb_create, > + .dumb_map_offset = drm_gem_cma_dumb_map_offset, > + .dumb_destroy = drm_gem_dumb_destroy, > + > + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, > + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, > + .gem_prime_export = drm_gem_prime_export, > + .gem_prime_import = drm_gem_prime_import, > + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, > + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, > + .gem_prime_vmap = drm_gem_cma_prime_vmap, > + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, > + .gem_prime_mmap = drm_gem_cma_prime_mmap, > + > + .name = "kirin", > + .desc = "Hisilicon Kirin SoCs' DRM Driver", > + .date = "20150718", > + .major = 1, > + .minor = 0, > +}; > + > +static int compare_of(struct device *dev, void *data) > +{ > + return dev->of_node == data; > +} > + > +static int kirin_drm_connectors_register(struct drm_device *dev) > +{ > + struct drm_connector *connector; > + struct drm_connector *failed_connector; > + int ret; > + This access needs to be protected by the dev->mode_config.mutex > + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { The above can be replaced with: drm_for_each_connector(connector, dev) { > + ret = drm_connector_register(connector); > + if (ret) { > + failed_connector = connector; > + goto err; > + } > + } > + > + return 0; > + > +err: > + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { > + if (failed_connector == connector) > + break; > + drm_connector_unregister(connector); > + } Same points as above. > + > + return ret; > +} > + > +static int kirin_drm_bind(struct device *dev) > +{ > + struct drm_driver *driver = &kirin_drm_driver; > + struct drm_device *drm_dev; > + int ret; > + > + drm_dev = drm_dev_alloc(driver, dev); > + if (!drm_dev) > + return -ENOMEM; > + > + drm_dev->platformdev = to_platform_device(dev); > + > + ret = kirin_drm_kms_init(drm_dev); > + if (ret) > + goto err_drm_dev_unref; > + > + ret = drm_dev_register(drm_dev, 0); > + if (ret) > + goto err_kms_cleanup; > + > + /* connectors should be registered after drm device register */ > + ret = kirin_drm_connectors_register(drm_dev); > + if (ret) > + goto err_drm_dev_unregister; > + > + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", > + driver->name, driver->major, driver->minor, driver->patchlevel, > + driver->date, drm_dev->primary->index); > + > + return 0; > + > +err_drm_dev_unregister: > + drm_dev_unregister(drm_dev); > +err_kms_cleanup: > + kirin_drm_kms_cleanup(drm_dev); > +err_drm_dev_unref: > + drm_dev_unref(drm_dev); > + > + return ret; > +} > + > +static void kirin_drm_unbind(struct device *dev) > +{ > + drm_put_dev(dev_get_drvdata(dev)); > +} > + > +static const struct component_master_ops kirin_drm_ops = { > + .bind = kirin_drm_bind, > + .unbind = kirin_drm_unbind, > +}; > + > +static const struct of_device_id kirin_drm_dt_ids[] = { > + { /* end node */ }, > +}; > +MODULE_DEVICE_TABLE(of, kirin_drm_dt_ids); > + > +static int kirin_get_dc_ops(struct device_node *np) > +{ > + const struct of_device_id *match_id; > + > + match_id = of_match_node(kirin_drm_dt_ids, np); > + if (!match_id) { > + DRM_ERROR("failed to match dt id\n"); > + return -EINVAL; > + } > + > + dc_ops = (struct kirin_dc_ops *)match_id->data; > + if (!dc_ops) { > + DRM_ERROR("dt id data is null\n"); > + return -EINVAL; > + } We can use of_device_get_match_data to get the match data, and move the kirin_drm_dt_ids table down where the driver is defined. Thanks, Archit -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation From mboxrd@z Thu Jan 1 00:00:00 1970 From: Archit Taneja Subject: Re: [PATCH v6 02/11] drm/hisilicon: Add hisilicon kirin drm master driver Date: Fri, 26 Feb 2016 14:24:18 +0530 Message-ID: <56D012BA.9000509@codeaurora.org> References: <1456476028-36880-1-git-send-email-xinliang.liu@linaro.org> <1456476028-36880-3-git-send-email-xinliang.liu@linaro.org> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8"; Format="flowed" Content-Transfer-Encoding: base64 Return-path: In-Reply-To: <1456476028-36880-3-git-send-email-xinliang.liu@linaro.org> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: Xinliang Liu , dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, daniel@ffwll.ch, robh@kernel.org, daniel@fooishbar.org, airlied@linux.ie, corbet@lwn.net, catalin.marinas@arm.com, will.deacon@arm.com, emil.l.velikov@gmail.com, mark.rutland@arm.com Cc: andy.green@linaro.org, xuyiping@hisilicon.com, guodong.xu@linaro.org, linux-doc@vger.kernel.org, w.f@huawei.com, zourongrong@huawei.com, linuxarm@huawei.com, xuwei5@hisilicon.com, bintian.wang@huawei.com, haojian.zhuang@linaro.org, benjamin.gaignard@linaro.org, puck.chen@hisilicon.com, liguozhu@hisilicon.com, linux-arm-kernel@lists.infradead.org List-Id: devicetree@vger.kernel.org SGksCgpJIGhhZCBzb21lIG1pbm9yIGNvbW1lbnRzLiBTb3JyeSBhYm91dCBzaGFyaW5nIHRoaXMg bGF0ZS4gT3RoZXJ3aXNlLAp0aGUgbG9va3MgZ29vZCB0byBtZS4KCk9uIDAyLzI2LzIwMTYgMDI6 MTAgUE0sIFhpbmxpYW5nIExpdSB3cm90ZToKPiBBZGQga2lyaW4gRFJNIG1hc3RlciBkcml2ZXIg Zm9yIGhpNjIyMCBTb0Mgd2hpY2ggdXNlZCBpbiBIaUtleSBib2FyZC4KPiBBZGQgZHVtYiBidWZm ZXIgZmVhdHVyZS4KPiBBZGQgcHJpbWUgZG1hYnVmIGZlYXR1cmUuCj4KPiB2NjogTm9uZS4KPiB2 NTogTm9uZS4KPiB2NDogTm9uZS4KPiB2MzoKPiAtIE1vdmUgYW5kIHJlbmFtZSBhbGwgdGhlIGZp bGVzIHRvIGtpcmluIHN1Yi1kaXJlY3RvcnkuCj4gICAgU28gdGhhdCB3ZSBjb3VsZCBzZXBhcmF0 ZSBkaWZmZXJlbnQgc2VpcmVzIFNvQ3MnIGRyaXZlci4KPiAtIFJlcGxhY2UgZHJtX3BsYXRmb3Jt X2luaXQsIGxvYWQsIHVubG9hZCBpbXBsZW1lbnRhdGlvbi4KPiB2MjoKPiAtIFJlbW92ZSBhYnRy YWN0aW9uIGxheWVyLgo+Cj4gU2lnbmVkLW9mZi1ieTogWGlubGlhbmcgTGl1IDx4aW5saWFuZy5s aXVAbGluYXJvLm9yZz4KPiAtLS0KPiAgIGRyaXZlcnMvZ3B1L2RybS9LY29uZmlnICAgICAgICAg ICAgICAgICAgICAgICAgIHwgICAyICsKPiAgIGRyaXZlcnMvZ3B1L2RybS9NYWtlZmlsZSAgICAg ICAgICAgICAgICAgICAgICAgIHwgICAxICsKPiAgIGRyaXZlcnMvZ3B1L2RybS9oaXNpbGljb24v S2NvbmZpZyAgICAgICAgICAgICAgIHwgICA1ICsKPiAgIGRyaXZlcnMvZ3B1L2RybS9oaXNpbGlj b24vTWFrZWZpbGUgICAgICAgICAgICAgIHwgICA1ICsKPiAgIGRyaXZlcnMvZ3B1L2RybS9oaXNp bGljb24va2lyaW4vS2NvbmZpZyAgICAgICAgIHwgICA5ICsKPiAgIGRyaXZlcnMvZ3B1L2RybS9o aXNpbGljb24va2lyaW4vTWFrZWZpbGUgICAgICAgIHwgICAzICsKPiAgIGRyaXZlcnMvZ3B1L2Ry bS9oaXNpbGljb24va2lyaW4va2lyaW5fZHJtX2Rydi5jIHwgMzIxICsrKysrKysrKysrKysrKysr KysrKysrKwo+ICAgZHJpdmVycy9ncHUvZHJtL2hpc2lsaWNvbi9raXJpbi9raXJpbl9kcm1fZHJ2 LmggfCAgMjAgKysKPiAgIDggZmlsZXMgY2hhbmdlZCwgMzY2IGluc2VydGlvbnMoKykKPiAgIGNy ZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL2dwdS9kcm0vaGlzaWxpY29uL0tjb25maWcKPiAgIGNy ZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL2dwdS9kcm0vaGlzaWxpY29uL01ha2VmaWxlCj4gICBj cmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9ncHUvZHJtL2hpc2lsaWNvbi9raXJpbi9LY29uZmln Cj4gICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9ncHUvZHJtL2hpc2lsaWNvbi9raXJpbi9N YWtlZmlsZQo+ICAgY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvZ3B1L2RybS9oaXNpbGljb24v a2lyaW4va2lyaW5fZHJtX2Rydi5jCj4gICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9ncHUv ZHJtL2hpc2lsaWNvbi9raXJpbi9raXJpbl9kcm1fZHJ2LmgKPgo+IGRpZmYgLS1naXQgYS9kcml2 ZXJzL2dwdS9kcm0vS2NvbmZpZyBiL2RyaXZlcnMvZ3B1L2RybS9LY29uZmlnCj4gaW5kZXggYjUw YWU2MGY1ZjUwLi5mNWM1NjU2ZTI1NDcgMTAwNjQ0Cj4gLS0tIGEvZHJpdmVycy9ncHUvZHJtL0tj b25maWcKPiArKysgYi9kcml2ZXJzL2dwdS9kcm0vS2NvbmZpZwo+IEBAIC0yNzcsMyArMjc3LDUg QEAgc291cmNlICJkcml2ZXJzL2dwdS9kcm0vaW14L0tjb25maWciCj4gICBzb3VyY2UgImRyaXZl cnMvZ3B1L2RybS92YzQvS2NvbmZpZyIKPgo+ICAgc291cmNlICJkcml2ZXJzL2dwdS9kcm0vZXRu YXZpdi9LY29uZmlnIgo+ICsKPiArc291cmNlICJkcml2ZXJzL2dwdS9kcm0vaGlzaWxpY29uL0tj b25maWciCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvZ3B1L2RybS9NYWtlZmlsZSBiL2RyaXZlcnMv Z3B1L2RybS9NYWtlZmlsZQo+IGluZGV4IDYxNzY2ZGVjNmE4ZC4uNjA1NTQ4MzIwNzljIDEwMDY0 NAo+IC0tLSBhL2RyaXZlcnMvZ3B1L2RybS9NYWtlZmlsZQo+ICsrKyBiL2RyaXZlcnMvZ3B1L2Ry bS9NYWtlZmlsZQo+IEBAIC03NCwzICs3NCw0IEBAIG9iai15CQkJKz0gcGFuZWwvCj4gICBvYmot eQkJCSs9IGJyaWRnZS8KPiAgIG9iai0kKENPTkZJR19EUk1fRlNMX0RDVSkgKz0gZnNsLWRjdS8K PiAgIG9iai0kKENPTkZJR19EUk1fRVROQVZJVikgKz0gZXRuYXZpdi8KPiArb2JqLXkJCQkrPSBo aXNpbGljb24vCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvZ3B1L2RybS9oaXNpbGljb24vS2NvbmZp ZyBiL2RyaXZlcnMvZ3B1L2RybS9oaXNpbGljb24vS2NvbmZpZwo+IG5ldyBmaWxlIG1vZGUgMTAw NjQ0Cj4gaW5kZXggMDAwMDAwMDAwMDAwLi41NThjNjFiMWI4ZTgKPiAtLS0gL2Rldi9udWxsCj4g KysrIGIvZHJpdmVycy9ncHUvZHJtL2hpc2lsaWNvbi9LY29uZmlnCj4gQEAgLTAsMCArMSw1IEBA Cj4gKyMKPiArIyBoaXNpbGljb24gZHJtIGRldmljZSBjb25maWd1cmF0aW9uLgo+ICsjIFBsZWFz ZSBrZWVwIHRoaXMgbGlzdCBzb3J0ZWQgYWxwaGFiZXRpY2FsbHkKPiArCj4gK3NvdXJjZSAiZHJp dmVycy9ncHUvZHJtL2hpc2lsaWNvbi9raXJpbi9LY29uZmlnIgo+IGRpZmYgLS1naXQgYS9kcml2 ZXJzL2dwdS9kcm0vaGlzaWxpY29uL01ha2VmaWxlIGIvZHJpdmVycy9ncHUvZHJtL2hpc2lsaWNv bi9NYWtlZmlsZQo+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0Cj4gaW5kZXggMDAwMDAwMDAwMDAwLi5l M2Y2ZDQ5M2M5OTYKPiAtLS0gL2Rldi9udWxsCj4gKysrIGIvZHJpdmVycy9ncHUvZHJtL2hpc2ls aWNvbi9NYWtlZmlsZQo+IEBAIC0wLDAgKzEsNSBAQAo+ICsjCj4gKyMgTWFrZWZpbGUgZm9yIGhp c2lsaWNvbiBkcm0gZHJpdmVycy4KPiArIyBQbGVhc2Uga2VlcCB0aGlzIGxpc3Qgc29ydGVkIGFs cGhhYmV0aWNhbGx5Cj4gKwo+ICtvYmotJChDT05GSUdfRFJNX0hJU0lfS0lSSU4pICs9IGtpcmlu Lwo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2dwdS9kcm0vaGlzaWxpY29uL2tpcmluL0tjb25maWcg Yi9kcml2ZXJzL2dwdS9kcm0vaGlzaWxpY29uL2tpcmluL0tjb25maWcKPiBuZXcgZmlsZSBtb2Rl IDEwMDY0NAo+IGluZGV4IDAwMDAwMDAwMDAwMC4uM2FjNGI4ZWRlYWMxCj4gLS0tIC9kZXYvbnVs bAo+ICsrKyBiL2RyaXZlcnMvZ3B1L2RybS9oaXNpbGljb24va2lyaW4vS2NvbmZpZwo+IEBAIC0w LDAgKzEsOSBAQAo+ICtjb25maWcgRFJNX0hJU0lfS0lSSU4KPiArCXRyaXN0YXRlICJEUk0gU3Vw cG9ydCBmb3IgSGlzaWxpY29uIEtpcmluIHNlcmllcyBTb0NzIFBsYXRmb3JtIgo+ICsJZGVwZW5k cyBvbiBEUk0KPiArCXNlbGVjdCBEUk1fS01TX0hFTFBFUgo+ICsJc2VsZWN0IERSTV9HRU1fQ01B X0hFTFBFUgo+ICsJc2VsZWN0IERSTV9LTVNfQ01BX0hFTFBFUgo+ICsJaGVscAo+ICsJICBDaG9v c2UgdGhpcyBvcHRpb24gaWYgeW91IGhhdmUgYSBoaXNpbGljb24gS2lyaW4gY2hpcHNldHMoaGk2 MjIwKS4KPiArCSAgSWYgTSBpcyBzZWxlY3RlZCB0aGUgbW9kdWxlIHdpbGwgYmUgY2FsbGVkIGtp cmluLWRybS4KPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJtL2hpc2lsaWNvbi9raXJpbi9N YWtlZmlsZSBiL2RyaXZlcnMvZ3B1L2RybS9oaXNpbGljb24va2lyaW4vTWFrZWZpbGUKPiBuZXcg ZmlsZSBtb2RlIDEwMDY0NAo+IGluZGV4IDAwMDAwMDAwMDAwMC4uY2IzNDZkZTQ3ZDQ4Cj4gLS0t IC9kZXYvbnVsbAo+ICsrKyBiL2RyaXZlcnMvZ3B1L2RybS9oaXNpbGljb24va2lyaW4vTWFrZWZp bGUKPiBAQCAtMCwwICsxLDMgQEAKPiAra2lyaW4tZHJtLXkgOj0ga2lyaW5fZHJtX2Rydi5vCj4g Kwo+ICtvYmotJChDT05GSUdfRFJNX0hJU0lfS0lSSU4pICs9IGtpcmluLWRybS5vCj4gZGlmZiAt LWdpdCBhL2RyaXZlcnMvZ3B1L2RybS9oaXNpbGljb24va2lyaW4va2lyaW5fZHJtX2Rydi5jIGIv ZHJpdmVycy9ncHUvZHJtL2hpc2lsaWNvbi9raXJpbi9raXJpbl9kcm1fZHJ2LmMKPiBuZXcgZmls ZSBtb2RlIDEwMDY0NAo+IGluZGV4IDAwMDAwMDAwMDAwMC4uNzg5ZWJkMWY1OTIyCj4gLS0tIC9k ZXYvbnVsbAo+ICsrKyBiL2RyaXZlcnMvZ3B1L2RybS9oaXNpbGljb24va2lyaW4va2lyaW5fZHJt X2Rydi5jCj4gQEAgLTAsMCArMSwzMjEgQEAKPiArLyoKPiArICogSGlzaWxpY29uIEtpcmluIFNv Q3MgZHJtIG1hc3RlciBkcml2ZXIKPiArICoKPiArICogQ29weXJpZ2h0IChjKSAyMDE2IExpbmFy byBMaW1pdGVkLgo+ICsgKiBDb3B5cmlnaHQgKGMpIDIwMTQtMjAxNiBIaXNpbGljb24gTGltaXRl ZC4KPiArICoKPiArICogQXV0aG9yOgo+ICsgKglYaW5saWFuZyBMaXUgPHoubGl1eGlubGlhbmdA aGlzaWxpY29uLmNvbT4KPiArICoJWGlubGlhbmcgTGl1IDx4aW5saWFuZy5saXVAbGluYXJvLm9y Zz4KPiArICoJWGlud2VpIEtvbmcgPGtvbmcua29uZ3hpbndlaUBoaXNpbGljb24uY29tPgo+ICsg Kgo+ICsgKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1 dGUgaXQgYW5kL29yIG1vZGlmeQo+ICsgKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBH ZW5lcmFsIFB1YmxpYyBMaWNlbnNlIHZlcnNpb24gMiBhcwo+ICsgKiBwdWJsaXNoZWQgYnkgdGhl IEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbi4KPiArICoKPiArICovCj4gKwo+ICsjaW5jbHVkZSA8 bGludXgvb2ZfcGxhdGZvcm0uaD4KPiArI2luY2x1ZGUgPGxpbnV4L2NvbXBvbmVudC5oPgo+ICsj aW5jbHVkZSA8bGludXgvb2ZfZ3JhcGguaD4KPiArCj4gKyNpbmNsdWRlIDxkcm0vZHJtUC5oPgo+ ICsjaW5jbHVkZSA8ZHJtL2RybV9nZW1fY21hX2hlbHBlci5oPgo+ICsjaW5jbHVkZSA8ZHJtL2Ry bV9mYl9jbWFfaGVscGVyLmg+Cj4gKyNpbmNsdWRlIDxkcm0vZHJtX2F0b21pY19oZWxwZXIuaD4K PiArCj4gKyNpbmNsdWRlICJraXJpbl9kcm1fZHJ2LmgiCj4gKwo+ICtzdGF0aWMgc3RydWN0IGtp cmluX2RjX29wcyAqZGNfb3BzOwo+ICsKPiArc3RhdGljIGludCBraXJpbl9kcm1fa21zX2NsZWFu dXAoc3RydWN0IGRybV9kZXZpY2UgKmRldikKPiArewo+ICsJZGNfb3BzLT5jbGVhbnVwKGRldik7 Cj4gKwlkcm1fbW9kZV9jb25maWdfY2xlYW51cChkZXYpOwo+ICsKPiArCXJldHVybiAwOwo+ICt9 Cj4gKwo+ICtzdGF0aWMgY29uc3Qgc3RydWN0IGRybV9tb2RlX2NvbmZpZ19mdW5jcyBraXJpbl9k cm1fbW9kZV9jb25maWdfZnVuY3MgPSB7Cj4gKwkuZmJfY3JlYXRlID0gZHJtX2ZiX2NtYV9jcmVh dGUsCj4gKwkuYXRvbWljX2NoZWNrID0gZHJtX2F0b21pY19oZWxwZXJfY2hlY2ssCj4gKwkuYXRv bWljX2NvbW1pdCA9IGRybV9hdG9taWNfaGVscGVyX2NvbW1pdCwKPiArfTsKPiArCj4gK3N0YXRp YyB2b2lkIGtpcmluX2RybV9tb2RlX2NvbmZpZ19pbml0KHN0cnVjdCBkcm1fZGV2aWNlICpkZXYp Cj4gK3sKPiArCWRldi0+bW9kZV9jb25maWcubWluX3dpZHRoID0gMDsKPiArCWRldi0+bW9kZV9j b25maWcubWluX2hlaWdodCA9IDA7Cj4gKwo+ICsJZGV2LT5tb2RlX2NvbmZpZy5tYXhfd2lkdGgg PSAyMDQ4Owo+ICsJZGV2LT5tb2RlX2NvbmZpZy5tYXhfaGVpZ2h0ID0gMjA0ODsKPiArCj4gKwlk ZXYtPm1vZGVfY29uZmlnLmZ1bmNzID0gJmtpcmluX2RybV9tb2RlX2NvbmZpZ19mdW5jczsKPiAr fQo+ICsKPiArc3RhdGljIGludCBraXJpbl9kcm1fa21zX2luaXQoc3RydWN0IGRybV9kZXZpY2Ug KmRldikKPiArewo+ICsJaW50IHJldDsKPiArCj4gKwlkZXZfc2V0X2RydmRhdGEoZGV2LT5kZXYs IGRldik7Cj4gKwo+ICsJLyogZGV2LT5tb2RlX2NvbmZpZyBpbml0aWFsaXphdGlvbiAqLwo+ICsJ ZHJtX21vZGVfY29uZmlnX2luaXQoZGV2KTsKPiArCWtpcmluX2RybV9tb2RlX2NvbmZpZ19pbml0 KGRldik7Cj4gKwo+ICsJLyogZGlzcGxheSBjb250cm9sbGVyIGluaXQgKi8KPiArCXJldCA9IGRj X29wcy0+aW5pdChkZXYpOwo+ICsJaWYgKHJldCkKPiArCQlnb3RvIGVycl9tb2RlX2NvbmZpZ19j bGVhbnVwOwo+ICsKPiArCS8qIGJpbmQgYW5kIGluaXQgc3ViIGRyaXZlcnMgKi8KPiArCXJldCA9 IGNvbXBvbmVudF9iaW5kX2FsbChkZXYtPmRldiwgZGV2KTsKPiArCWlmIChyZXQpIHsKPiArCQlE Uk1fRVJST1IoImZhaWxlZCB0byBiaW5kIGFsbCBjb21wb25lbnQuXG4iKTsKPiArCQlnb3RvIGVy cl9kY19jbGVhbnVwOwo+ICsJfQo+ICsKPiArCS8qIHJlc2V0IGFsbCB0aGUgc3RhdGVzIG9mIGNy dGMvcGxhbmUvZW5jb2Rlci9jb25uZWN0b3IgKi8KPiArCWRybV9tb2RlX2NvbmZpZ19yZXNldChk ZXYpOwo+ICsKPiArCXJldHVybiAwOwo+ICsKPiArZXJyX2RjX2NsZWFudXA6Cj4gKwlkY19vcHMt PmNsZWFudXAoZGV2KTsKPiArZXJyX21vZGVfY29uZmlnX2NsZWFudXA6Cj4gKwlkcm1fbW9kZV9j b25maWdfY2xlYW51cChkZXYpOwo+ICsKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gK3N0YXRp YyBjb25zdCBzdHJ1Y3QgZmlsZV9vcGVyYXRpb25zIGtpcmluX2RybV9mb3BzID0gewo+ICsJLm93 bmVyCQk9IFRISVNfTU9EVUxFLAo+ICsJLm9wZW4JCT0gZHJtX29wZW4sCj4gKwkucmVsZWFzZQk9 IGRybV9yZWxlYXNlLAo+ICsJLnVubG9ja2VkX2lvY3RsCT0gZHJtX2lvY3RsLAo+ICsjaWZkZWYg Q09ORklHX0NPTVBBVAo+ICsJLmNvbXBhdF9pb2N0bAk9IGRybV9jb21wYXRfaW9jdGwsCj4gKyNl bmRpZgo+ICsJLnBvbGwJCT0gZHJtX3BvbGwsCj4gKwkucmVhZAkJPSBkcm1fcmVhZCwKPiArCS5s bHNlZWsJCT0gbm9fbGxzZWVrLAo+ICsJLm1tYXAJCT0gZHJtX2dlbV9jbWFfbW1hcCwKPiArfTsK PiArCj4gK3N0YXRpYyBpbnQga2lyaW5fZ2VtX2NtYV9kdW1iX2NyZWF0ZShzdHJ1Y3QgZHJtX2Zp bGUgKmZpbGUsCj4gKwkJCQkgICAgIHN0cnVjdCBkcm1fZGV2aWNlICpkZXYsCj4gKwkJCQkgICAg IHN0cnVjdCBkcm1fbW9kZV9jcmVhdGVfZHVtYiAqYXJncykKPiArewo+ICsJcmV0dXJuIGRybV9n ZW1fY21hX2R1bWJfY3JlYXRlX2ludGVybmFsKGZpbGUsIGRldiwgYXJncyk7Cj4gK30KPiArCj4g K3N0YXRpYyBzdHJ1Y3QgZHJtX2RyaXZlciBraXJpbl9kcm1fZHJpdmVyID0gewo+ICsJLmRyaXZl cl9mZWF0dXJlcwk9IERSSVZFUl9HRU0gfCBEUklWRVJfTU9ERVNFVCB8IERSSVZFUl9QUklNRSB8 Cj4gKwkJCQkgIERSSVZFUl9BVE9NSUMsCj4gKwkuZm9wcwkJCT0gJmtpcmluX2RybV9mb3BzLAo+ ICsJLnNldF9idXNpZAkJPSBkcm1fcGxhdGZvcm1fc2V0X2J1c2lkLAo+ICsKPiArCS5nZW1fZnJl ZV9vYmplY3QJPSBkcm1fZ2VtX2NtYV9mcmVlX29iamVjdCwKPiArCS5nZW1fdm1fb3BzCQk9ICZk cm1fZ2VtX2NtYV92bV9vcHMsCj4gKwkuZHVtYl9jcmVhdGUJCT0ga2lyaW5fZ2VtX2NtYV9kdW1i X2NyZWF0ZSwKPiArCS5kdW1iX21hcF9vZmZzZXQJPSBkcm1fZ2VtX2NtYV9kdW1iX21hcF9vZmZz ZXQsCj4gKwkuZHVtYl9kZXN0cm95CQk9IGRybV9nZW1fZHVtYl9kZXN0cm95LAo+ICsKPiArCS5w cmltZV9oYW5kbGVfdG9fZmQJPSBkcm1fZ2VtX3ByaW1lX2hhbmRsZV90b19mZCwKPiArCS5wcmlt ZV9mZF90b19oYW5kbGUJPSBkcm1fZ2VtX3ByaW1lX2ZkX3RvX2hhbmRsZSwKPiArCS5nZW1fcHJp bWVfZXhwb3J0CT0gZHJtX2dlbV9wcmltZV9leHBvcnQsCj4gKwkuZ2VtX3ByaW1lX2ltcG9ydAk9 IGRybV9nZW1fcHJpbWVfaW1wb3J0LAo+ICsJLmdlbV9wcmltZV9nZXRfc2dfdGFibGUgPSBkcm1f Z2VtX2NtYV9wcmltZV9nZXRfc2dfdGFibGUsCj4gKwkuZ2VtX3ByaW1lX2ltcG9ydF9zZ190YWJs ZSA9IGRybV9nZW1fY21hX3ByaW1lX2ltcG9ydF9zZ190YWJsZSwKPiArCS5nZW1fcHJpbWVfdm1h cAkJPSBkcm1fZ2VtX2NtYV9wcmltZV92bWFwLAo+ICsJLmdlbV9wcmltZV92dW5tYXAJPSBkcm1f Z2VtX2NtYV9wcmltZV92dW5tYXAsCj4gKwkuZ2VtX3ByaW1lX21tYXAJCT0gZHJtX2dlbV9jbWFf cHJpbWVfbW1hcCwKPiArCj4gKwkubmFtZQkJCT0gImtpcmluIiwKPiArCS5kZXNjCQkJPSAiSGlz aWxpY29uIEtpcmluIFNvQ3MnIERSTSBEcml2ZXIiLAo+ICsJLmRhdGUJCQk9ICIyMDE1MDcxOCIs Cj4gKwkubWFqb3IJCQk9IDEsCj4gKwkubWlub3IJCQk9IDAsCj4gK307Cj4gKwo+ICtzdGF0aWMg aW50IGNvbXBhcmVfb2Yoc3RydWN0IGRldmljZSAqZGV2LCB2b2lkICpkYXRhKQo+ICt7Cj4gKwly ZXR1cm4gZGV2LT5vZl9ub2RlID09IGRhdGE7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQga2lyaW5f ZHJtX2Nvbm5lY3RvcnNfcmVnaXN0ZXIoc3RydWN0IGRybV9kZXZpY2UgKmRldikKPiArewo+ICsJ c3RydWN0IGRybV9jb25uZWN0b3IgKmNvbm5lY3RvcjsKPiArCXN0cnVjdCBkcm1fY29ubmVjdG9y ICpmYWlsZWRfY29ubmVjdG9yOwo+ICsJaW50IHJldDsKPiArCgpUaGlzIGFjY2VzcyBuZWVkcyB0 byBiZSBwcm90ZWN0ZWQgYnkgdGhlIGRldi0+bW9kZV9jb25maWcubXV0ZXgKCj4gKwlsaXN0X2Zv cl9lYWNoX2VudHJ5KGNvbm5lY3RvciwgJmRldi0+bW9kZV9jb25maWcuY29ubmVjdG9yX2xpc3Qs IGhlYWQpIHsKClRoZSBhYm92ZSBjYW4gYmUgcmVwbGFjZWQgd2l0aDoKCmRybV9mb3JfZWFjaF9j b25uZWN0b3IoY29ubmVjdG9yLCBkZXYpIHsKCj4gKwkJcmV0ID0gZHJtX2Nvbm5lY3Rvcl9yZWdp c3Rlcihjb25uZWN0b3IpOwo+ICsJCWlmIChyZXQpIHsKPiArCQkJZmFpbGVkX2Nvbm5lY3RvciA9 IGNvbm5lY3RvcjsKPiArCQkJZ290byBlcnI7Cj4gKwkJfQo+ICsJfQo+ICsKPiArCXJldHVybiAw Owo+ICsKPiArZXJyOgo+ICsJbGlzdF9mb3JfZWFjaF9lbnRyeShjb25uZWN0b3IsICZkZXYtPm1v ZGVfY29uZmlnLmNvbm5lY3Rvcl9saXN0LCBoZWFkKSB7Cj4gKwkJaWYgKGZhaWxlZF9jb25uZWN0 b3IgPT0gY29ubmVjdG9yKQo+ICsJCQlicmVhazsKPiArCQlkcm1fY29ubmVjdG9yX3VucmVnaXN0 ZXIoY29ubmVjdG9yKTsKPiArCX0KClNhbWUgcG9pbnRzIGFzIGFib3ZlLgoKPiArCj4gKwlyZXR1 cm4gcmV0Owo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGtpcmluX2RybV9iaW5kKHN0cnVjdCBkZXZp Y2UgKmRldikKPiArewo+ICsJc3RydWN0IGRybV9kcml2ZXIgKmRyaXZlciA9ICZraXJpbl9kcm1f ZHJpdmVyOwo+ICsJc3RydWN0IGRybV9kZXZpY2UgKmRybV9kZXY7Cj4gKwlpbnQgcmV0Owo+ICsK PiArCWRybV9kZXYgPSBkcm1fZGV2X2FsbG9jKGRyaXZlciwgZGV2KTsKPiArCWlmICghZHJtX2Rl dikKPiArCQlyZXR1cm4gLUVOT01FTTsKPiArCj4gKwlkcm1fZGV2LT5wbGF0Zm9ybWRldiA9IHRv X3BsYXRmb3JtX2RldmljZShkZXYpOwo+ICsKPiArCXJldCA9IGtpcmluX2RybV9rbXNfaW5pdChk cm1fZGV2KTsKPiArCWlmIChyZXQpCj4gKwkJZ290byBlcnJfZHJtX2Rldl91bnJlZjsKPiArCj4g KwlyZXQgPSBkcm1fZGV2X3JlZ2lzdGVyKGRybV9kZXYsIDApOwo+ICsJaWYgKHJldCkKPiArCQln b3RvIGVycl9rbXNfY2xlYW51cDsKPiArCj4gKwkvKiBjb25uZWN0b3JzIHNob3VsZCBiZSByZWdp c3RlcmVkIGFmdGVyIGRybSBkZXZpY2UgcmVnaXN0ZXIgKi8KPiArCXJldCA9IGtpcmluX2RybV9j b25uZWN0b3JzX3JlZ2lzdGVyKGRybV9kZXYpOwo+ICsJaWYgKHJldCkKPiArCQlnb3RvIGVycl9k cm1fZGV2X3VucmVnaXN0ZXI7Cj4gKwo+ICsJRFJNX0lORk8oIkluaXRpYWxpemVkICVzICVkLiVk LiVkICVzIG9uIG1pbm9yICVkXG4iLAo+ICsJCSBkcml2ZXItPm5hbWUsIGRyaXZlci0+bWFqb3Is IGRyaXZlci0+bWlub3IsIGRyaXZlci0+cGF0Y2hsZXZlbCwKPiArCQkgZHJpdmVyLT5kYXRlLCBk cm1fZGV2LT5wcmltYXJ5LT5pbmRleCk7Cj4gKwo+ICsJcmV0dXJuIDA7Cj4gKwo+ICtlcnJfZHJt X2Rldl91bnJlZ2lzdGVyOgo+ICsJZHJtX2Rldl91bnJlZ2lzdGVyKGRybV9kZXYpOwo+ICtlcnJf a21zX2NsZWFudXA6Cj4gKwlraXJpbl9kcm1fa21zX2NsZWFudXAoZHJtX2Rldik7Cj4gK2Vycl9k cm1fZGV2X3VucmVmOgo+ICsJZHJtX2Rldl91bnJlZihkcm1fZGV2KTsKPiArCj4gKwlyZXR1cm4g cmV0Owo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBraXJpbl9kcm1fdW5iaW5kKHN0cnVjdCBkZXZp Y2UgKmRldikKPiArewo+ICsJZHJtX3B1dF9kZXYoZGV2X2dldF9kcnZkYXRhKGRldikpOwo+ICt9 Cj4gKwo+ICtzdGF0aWMgY29uc3Qgc3RydWN0IGNvbXBvbmVudF9tYXN0ZXJfb3BzIGtpcmluX2Ry bV9vcHMgPSB7Cj4gKwkuYmluZCA9IGtpcmluX2RybV9iaW5kLAo+ICsJLnVuYmluZCA9IGtpcmlu X2RybV91bmJpbmQsCj4gK307Cj4gKwo+ICtzdGF0aWMgY29uc3Qgc3RydWN0IG9mX2RldmljZV9p ZCBraXJpbl9kcm1fZHRfaWRzW10gPSB7Cj4gKwl7IC8qIGVuZCBub2RlICovIH0sCj4gK307Cj4g K01PRFVMRV9ERVZJQ0VfVEFCTEUob2YsIGtpcmluX2RybV9kdF9pZHMpOwo+ICsKPiArc3RhdGlj IGludCBraXJpbl9nZXRfZGNfb3BzKHN0cnVjdCBkZXZpY2Vfbm9kZSAqbnApCj4gK3sKPiArCWNv bnN0IHN0cnVjdCBvZl9kZXZpY2VfaWQgKm1hdGNoX2lkOwo+ICsKPiArCW1hdGNoX2lkID0gb2Zf bWF0Y2hfbm9kZShraXJpbl9kcm1fZHRfaWRzLCBucCk7Cj4gKwlpZiAoIW1hdGNoX2lkKSB7Cj4g KwkJRFJNX0VSUk9SKCJmYWlsZWQgdG8gbWF0Y2ggZHQgaWRcbiIpOwo+ICsJCXJldHVybiAtRUlO VkFMOwo+ICsJfQo+ICsKPiArCWRjX29wcyA9IChzdHJ1Y3Qga2lyaW5fZGNfb3BzICopbWF0Y2hf aWQtPmRhdGE7Cj4gKwlpZiAoIWRjX29wcykgewo+ICsJCURSTV9FUlJPUigiZHQgaWQgZGF0YSBp cyBudWxsXG4iKTsKPiArCQlyZXR1cm4gLUVJTlZBTDsKPiArCX0KCldlIGNhbiB1c2Ugb2ZfZGV2 aWNlX2dldF9tYXRjaF9kYXRhIHRvIGdldCB0aGUgbWF0Y2ggZGF0YSwKYW5kIG1vdmUgdGhlIGtp cmluX2RybV9kdF9pZHMgdGFibGUgZG93biB3aGVyZSB0aGUgZHJpdmVyIGlzCmRlZmluZWQuCgo8 c25pcD4KClRoYW5rcywKQXJjaGl0CgotLSAKVGhlIFF1YWxjb21tIElubm92YXRpb24gQ2VudGVy LCBJbmMuIGlzIGEgbWVtYmVyIG9mIHRoZSBDb2RlIEF1cm9yYSAKRm9ydW0sIGhvc3RlZCBieSBU aGUgTGludXggRm91bmRhdGlvbgpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fXwpkcmktZGV2ZWwgbWFpbGluZyBsaXN0CmRyaS1kZXZlbEBsaXN0cy5mcmVlZGVz a3RvcC5vcmcKaHR0cHM6Ly9saXN0cy5mcmVlZGVza3RvcC5vcmcvbWFpbG1hbi9saXN0aW5mby9k cmktZGV2ZWwK