From 7b8ca11798bc4273ea1944c285121d647680bfe2 Mon Sep 17 00:00:00 2001 From: hhb Date: Sun, 27 May 2012 15:52:01 +0800 Subject: [PATCH] rk30 phone loauqt: add touch screen synaptics s3202 standar drivers --- drivers/input/touchscreen/rmi4/Kconfig | 198 ++ drivers/input/touchscreen/rmi4/Makefile | 34 + drivers/input/touchscreen/rmi4/rmi_bus.c | 482 +++ drivers/input/touchscreen/rmi4/rmi_dev.c | 448 +++ drivers/input/touchscreen/rmi4/rmi_driver.c | 1616 ++++++++++ drivers/input/touchscreen/rmi4/rmi_driver.h | 405 +++ drivers/input/touchscreen/rmi4/rmi_f01.c | 1389 +++++++++ drivers/input/touchscreen/rmi4/rmi_f09.c | 771 +++++ drivers/input/touchscreen/rmi4/rmi_f11.c | 1947 ++++++++++++ drivers/input/touchscreen/rmi4/rmi_f17.c | 731 +++++ drivers/input/touchscreen/rmi4/rmi_f19.c | 1505 +++++++++ drivers/input/touchscreen/rmi4/rmi_f1a.c | 1809 +++++++++++ drivers/input/touchscreen/rmi4/rmi_f21.c | 751 +++++ drivers/input/touchscreen/rmi4/rmi_f34.c | 962 ++++++ drivers/input/touchscreen/rmi4/rmi_f54.c | 2272 ++++++++++++++ drivers/input/touchscreen/rmi4/rmi_i2c.c | 453 +++ drivers/input/touchscreen/rmi4/rmi_reflash.c | 670 ++++ drivers/input/touchscreen/rmi4/rmi_reflash.h | 2916 ++++++++++++++++++ drivers/input/touchscreen/rmi4/rmi_spi.c | 909 ++++++ include/linux/rmi.h | 609 ++++ 20 files changed, 20877 insertions(+) create mode 100755 drivers/input/touchscreen/rmi4/Kconfig create mode 100755 drivers/input/touchscreen/rmi4/Makefile create mode 100755 drivers/input/touchscreen/rmi4/rmi_bus.c create mode 100755 drivers/input/touchscreen/rmi4/rmi_dev.c create mode 100755 drivers/input/touchscreen/rmi4/rmi_driver.c create mode 100755 drivers/input/touchscreen/rmi4/rmi_driver.h create mode 100755 drivers/input/touchscreen/rmi4/rmi_f01.c create mode 100755 drivers/input/touchscreen/rmi4/rmi_f09.c create mode 100755 drivers/input/touchscreen/rmi4/rmi_f11.c create mode 100755 drivers/input/touchscreen/rmi4/rmi_f17.c create mode 100755 drivers/input/touchscreen/rmi4/rmi_f19.c create mode 100755 drivers/input/touchscreen/rmi4/rmi_f1a.c create mode 100755 drivers/input/touchscreen/rmi4/rmi_f21.c create mode 100755 drivers/input/touchscreen/rmi4/rmi_f34.c create mode 100755 drivers/input/touchscreen/rmi4/rmi_f54.c create mode 100755 drivers/input/touchscreen/rmi4/rmi_i2c.c create mode 100644 drivers/input/touchscreen/rmi4/rmi_reflash.c create mode 100644 drivers/input/touchscreen/rmi4/rmi_reflash.h create mode 100755 drivers/input/touchscreen/rmi4/rmi_spi.c create mode 100755 include/linux/rmi.h diff --git a/drivers/input/touchscreen/rmi4/Kconfig b/drivers/input/touchscreen/rmi4/Kconfig new file mode 100755 index 000000000000..3adf21d3c9eb --- /dev/null +++ b/drivers/input/touchscreen/rmi4/Kconfig @@ -0,0 +1,198 @@ +# +# RMI4 configuration +# +config RMI4_BUS + bool "Synaptics RMI4 bus support" + depends on TOUCHSCREEN_SYNAPTICS_RMI4_I2C_RK + help + Say Y here if you want to support the Synaptics RMI4 bus. + + If unsure, say Y. + + This feature is not currently available as + a loadable module. + +config RMI4_DEBUG + bool "Synaptics RMI4 debugging" + depends on RMI4_BUS + help + Say Y here to enable debug feature in the RMI4 driver. + + Note that the RMI4 driver debug features can generate a lot of + output (potentially clogging up your dmesg output) and generally + slow down driver operation. It's recommended to enable them only + if you are actively developing/debugging RMI4 features. + + If unsure, say N. + +config RMI4_I2C + bool "RMI4 I2C Support" + depends on RMI4_BUS && I2C + help + Say Y here if you want to support RMI4 devices connected to an I2C + bus. + + If unsure, say Y. + + This feature is not currently available as a loadable module. + +config RMI4_I2C_SCL_RATE + int "RMI4 I2C SCL RATE Support" + depends on RMI4_I2C + +config RMI4_SPI + bool "RMI4 SPI Support" + depends on RMI4_BUS && SPI + help + Say Y here if you want to support RMI4 devices connected to an SPI + bus. + + If unsure, say Y. + + This feature is not currently available as a loadable module. + +config RMI4_GENERIC + bool "RMI4 Generic driver" + depends on RMI4_BUS + help + Say Y here if you want to support generic RMI4 devices. + + This is pretty much required if you want to do anything useful with + your RMI device. + + This feature is not currently available as a loadable module. + + +config RMI4_F1A + tristate "RMI4 Function 1A (capacitive button sensor)" + depends on RMI4_BUS && RMI4_GENERIC + help + Say Y here if you want to add support for RMI4 function 1A. + + Function 1A provides self testing for touchscreens and touchpads. + + To compile this driver as a module, choose M here: the + module will be called rmi-f1a. + +config RMI4_F09 + tristate "RMI4 Function 09 (self testing)" + depends on RMI4_BUS && RMI4_GENERIC + help + Say Y here if you want to add support for RMI4 function 09. + + Function 09 provides self testing for touchscreens and touchpads. + + To compile this driver as a module, choose M here: the + module will be called rmi-f09. + +config RMI4_F11 + tristate "RMI4 Function 11 (2D pointing)" + depends on RMI4_BUS && RMI4_GENERIC + help + Say Y here if you want to add support for RMI4 function 11. + + Function 11 provides 2D multifinger pointing for touchscreens and + touchpads. For sensors that support relative pointing, F11 also + provides mouse input. + + To compile this driver as a module, choose M here: the + module will be called rmi-f11. + +config RMI4_F11_PEN + bool "RMI4 F11 Pen Support" + depends on RMI4_F11 + help + Say Y here to add support for pen input to RMI4 function 11. + + If this feature is enabled, when pen inputs are detected they + will be reported to the input stream as MT_TOOL_PEN. Otherwise, + pens will be treated the same as fingers. + + Not all UI implementations deal gracefully with pen discrimination. + If your system is not recognizing pen touches and you know your + sensor supports pen input, you probably want to turn this feature + off. + +config RMI4_VIRTUAL_BUTTON + tristate "RMI4 Vitual Button" + depends on RMI4_F11 + help + Say Y here if you want to add support for RMI4 virtual button to F11. + + The virtual button feature implement the virtual button device in + certain RMI4 touch sensors. + + This works only if your sensor supports F11 gestures. + +config RMI4_F17 + tristate "RMI4 Function 17 (pointing sticks)" + depends on RMI4_BUS && RMI4_GENERIC + help + Say Y here if you want to add support for RMI4 function 17. + + Function 19 provides support for capacitive and resistive + pointing sticks. + + To compile this driver as a module, choose M here: the + module will be called rmi-f17. + +config RMI4_F19 + tristate "RMI4 Function 19 (0D pointing)" + depends on RMI4_BUS && RMI4_GENERIC + help + Say Y here if you want to add support for RMI4 function 19. + + Function 19 provides support for capacitive buttons for sensors + that implement capacitive buttons. + + To compile this driver as a module, choose M here: the + module will be called rmi-f19. + +config RMI4_F21 + tristate "RMI4 Function 21 (2D Force)" + depends on RMI4_BUS && RMI4_GENERIC + help + Say Y here if you want to add support for RMI4 function 21. + + Function 21 provides 2D Force Sensing for ForcePad products. + + To compile this driver as a module, choose M here: the + module will be called rmi-f21. + +config RMI4_F34 + tristate "RMI4 Function 34 (device reflash)" + depends on RMI4_BUS && RMI4_GENERIC + help + Say Y here if you want to add support for RMI4 function 34. + + Function 34 provides firmware upgrade capability for your sensor. + + To compile this driver as a module, choose M here: the + module will be called rmi-f34. +config RMI4_REFLASH_WHEN_BOOT + tristate "RMI4 Function 34 (device reflash when system boot)" + depends on RMI4_BUS && RMI4_GENERIC + +config RMI4_F54 + tristate "RMI4 Function 54 (analog diagnostics)" + depends on RMI4_BUS && RMI4_GENERIC + help + Say Y here if you want to add support for RMI4 function 54. + + Function 54 provides access to various diagnostic features in + certain RMI4 touch sensors. + + To compile this driver as a module, choose M here: the + module will be called rmi-f54. + +config RMI4_DEV + tristate "Synaptics direct RMI device support (rmidev)" + depends on GPIO_SYSFS && (RMI4_I2C || RMI4_SPI) + help + Say Y here to add support for rmidev. + + The rmidev feature implements a character device providing access + to RMI4 sensor register maps. + + To compile this driver as a module, choose M here: the + module will be called rmi-dev. diff --git a/drivers/input/touchscreen/rmi4/Makefile b/drivers/input/touchscreen/rmi4/Makefile new file mode 100755 index 000000000000..81db85bb8295 --- /dev/null +++ b/drivers/input/touchscreen/rmi4/Makefile @@ -0,0 +1,34 @@ +obj-$(CONFIG_RMI4_BUS) += rmi_bus.o +obj-$(CONFIG_RMI4_I2C) += rmi_i2c.o +obj-$(CONFIG_RMI4_SPI) += rmi_spi.o +obj-$(CONFIG_RMI4_GENERIC) += rmi_driver.o rmi_f01.o +obj-$(CONFIG_RMI4_F09) += rmi_f09.o +obj-$(CONFIG_RMI4_F1A) += rmi_f1a.o +obj-$(CONFIG_RMI4_F11) += rmi_f11.o +obj-$(CONFIG_RMI4_F17) += rmi_f17.o +obj-$(CONFIG_RMI4_F19) += rmi_f19.o +obj-$(CONFIG_RMI4_F21) += rmi_f21.o +obj-$(CONFIG_RMI4_F34) += rmi_f34.o +obj-$(CONFIG_RMI4_F54) += rmi_f54.o +obj-$(CONFIG_RMI4_DEV) += rmi_dev.o +obj-y += rmi_reflash.o + +ifeq ($(KERNELRELEASE),) + +# KERNELDIR ?= /home/ +PWD := $(shell pwd) + +.PHONY: build clean + +build: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c +else + +$(info Building with KERNELRELEASE = ${KERNELRELEASE}) +obj-m += rmi_dev.o + +endif + diff --git a/drivers/input/touchscreen/rmi4/rmi_bus.c b/drivers/input/touchscreen/rmi4/rmi_bus.c new file mode 100755 index 000000000000..b055a4a20eb3 --- /dev/null +++ b/drivers/input/touchscreen/rmi4/rmi_bus.c @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2011 Synaptics Incorporated + * Copyright (c) 2011 Unixphere + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_RMI4_DEBUG +#include +#endif +#include "rmi_driver.h" +DEFINE_MUTEX(rmi_bus_mutex); + +static struct rmi_function_list { + struct list_head list; + struct rmi_function_handler *fh; +} rmi_supported_functions; + +static struct rmi_character_driver_list { + struct list_head list; + struct rmi_char_driver *cd; +} rmi_character_drivers; + +static atomic_t physical_device_count; + +#ifdef CONFIG_RMI4_DEBUG +static struct dentry *rmi_debugfs_root; +#endif + +static int rmi_bus_match(struct device *dev, struct device_driver *driver) +{ + struct rmi_driver *rmi_driver; + struct rmi_device *rmi_dev; + struct rmi_device_platform_data *pdata; + + rmi_driver = to_rmi_driver(driver); + rmi_dev = to_rmi_device(dev); + pdata = to_rmi_platform_data(rmi_dev); + dev_dbg(dev, "%s: Matching %s.\n", __func__, pdata->sensor_name); + + if (!strcmp(pdata->driver_name, rmi_driver->driver.name)) { + rmi_dev->driver = rmi_driver; + dev_dbg(dev, "%s: Match %s to %s succeeded.\n", __func__, + pdata->driver_name, rmi_driver->driver.name); + return 1; + } + + dev_vdbg(dev, "%s: Match %s to %s failed.\n", __func__, + pdata->driver_name, rmi_driver->driver.name); + return 0; +} + +#ifdef CONFIG_PM +static int rmi_bus_suspend(struct device *dev) +{ +#ifdef GENERIC_SUBSYS_PM_OPS + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm && pm->suspend) + return pm->suspend(dev); +#endif + + return 0; +} + +static int rmi_bus_resume(struct device *dev) +{ +#ifdef GENERIC_SUBSYS_PM_OPS + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm && pm->resume) + return pm->resume(dev); + else if (dev->driver && dev->driver->resume) + return dev->driver->resume(dev); +#else + if (dev->driver && dev->driver->resume) + return dev->driver->resume(dev); +#endif + + return 0; +} +#endif + +static int rmi_bus_probe(struct device *dev) +{ + struct rmi_driver *driver; + struct rmi_device *rmi_dev = to_rmi_device(dev); + + driver = rmi_dev->driver; + if (driver && driver->probe) + return driver->probe(rmi_dev); + + return 0; +} + +static int rmi_bus_remove(struct device *dev) +{ + struct rmi_driver *driver; + struct rmi_device *rmi_dev = to_rmi_device(dev); + + driver = rmi_dev->driver; + if (driver && driver->remove) + return driver->remove(rmi_dev); + + return 0; +} + +static void rmi_bus_shutdown(struct device *dev) +{ + struct rmi_driver *driver; + struct rmi_device *rmi_dev = to_rmi_device(dev); + + driver = rmi_dev->driver; + if (driver && driver->shutdown) + driver->shutdown(rmi_dev); +} + +static SIMPLE_DEV_PM_OPS(rmi_bus_pm_ops, + rmi_bus_suspend, rmi_bus_resume); + +struct bus_type rmi_bus_type = { + .name = "rmi", + .match = rmi_bus_match, + .probe = rmi_bus_probe, + .remove = rmi_bus_remove, + .shutdown = rmi_bus_shutdown, + .pm = &rmi_bus_pm_ops +}; + +static void release_rmidev_device(struct device *dev) { + device_unregister(dev); +} + +int rmi_register_phys_device(struct rmi_phys_device *phys) +{ + struct rmi_device_platform_data *pdata = phys->dev->platform_data; + struct rmi_device *rmi_dev; + + if (!pdata) { + dev_err(phys->dev, "no platform data!\n"); + return -EINVAL; + } + + rmi_dev = kzalloc(sizeof(struct rmi_device), GFP_KERNEL); + if (!rmi_dev) + return -ENOMEM; + + rmi_dev->phys = phys; + rmi_dev->dev.bus = &rmi_bus_type; + + rmi_dev->number = atomic_inc_return(&physical_device_count) - 1; + rmi_dev->dev.release = release_rmidev_device; + + dev_set_name(&rmi_dev->dev, "sensor%02d", rmi_dev->number); + dev_dbg(phys->dev, "%s: Registered %s as %s.\n", __func__, + pdata->sensor_name, dev_name(&rmi_dev->dev)); + +#ifdef CONFIG_RMI4_DEBUG + if (rmi_debugfs_root) { + rmi_dev->debugfs_root = debugfs_create_dir( + dev_name(&rmi_dev->dev), rmi_debugfs_root); + if (!rmi_dev->debugfs_root) + dev_err(&rmi_dev->dev, "Failed to create debugfs root.\n"); + } +#endif + phys->rmi_dev = rmi_dev; + return device_register(&rmi_dev->dev); +} +EXPORT_SYMBOL(rmi_register_phys_device); + +void rmi_unregister_phys_device(struct rmi_phys_device *phys) +{ + struct rmi_device *rmi_dev = phys->rmi_dev; + +#ifdef CONFIG_RMI4_DEBUG + if (rmi_dev->debugfs_root) + debugfs_remove(rmi_dev->debugfs_root); +#endif + + kfree(rmi_dev); +} +EXPORT_SYMBOL(rmi_unregister_phys_device); + +int rmi_register_driver(struct rmi_driver *driver) +{ + driver->driver.bus = &rmi_bus_type; + return driver_register(&driver->driver); +} +EXPORT_SYMBOL(rmi_register_driver); + +static int __rmi_driver_remove(struct device *dev, void *data) +{ + struct rmi_driver *driver = data; + struct rmi_device *rmi_dev = to_rmi_device(dev); + + if (rmi_dev->driver == driver) + rmi_dev->driver = NULL; + + return 0; +} + +void rmi_unregister_driver(struct rmi_driver *driver) +{ + bus_for_each_dev(&rmi_bus_type, NULL, driver, __rmi_driver_remove); + driver_unregister(&driver->driver); +} +EXPORT_SYMBOL(rmi_unregister_driver); + +static int __rmi_bus_fh_add(struct device *dev, void *data) +{ + struct rmi_driver *driver; + struct rmi_device *rmi_dev = to_rmi_device(dev); + + driver = rmi_dev->driver; + if (driver && driver->fh_add) + driver->fh_add(rmi_dev, data); + + return 0; +} + +int rmi_register_function_driver(struct rmi_function_handler *fh) +{ + struct rmi_function_list *entry; + struct rmi_function_handler *fh_dup; + + fh_dup = rmi_get_function_handler(fh->func); + if (fh_dup) { + pr_err("%s: function f%.2x already registered!\n", __func__, + fh->func); + return -EINVAL; + } + + entry = kzalloc(sizeof(struct rmi_function_list), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + entry->fh = fh; + INIT_LIST_HEAD(&entry->list); + list_add_tail(&entry->list, &rmi_supported_functions.list); + + /* notify devices of the new function handler */ + bus_for_each_dev(&rmi_bus_type, NULL, fh, __rmi_bus_fh_add); + + return 0; +} +EXPORT_SYMBOL(rmi_register_function_driver); + +static int __rmi_bus_fh_remove(struct device *dev, void *data) +{ + struct rmi_driver *driver; + struct rmi_device *rmi_dev = to_rmi_device(dev); + + driver = rmi_dev->driver; + if (driver && driver->fh_remove) + driver->fh_remove(rmi_dev, data); + + return 0; +} + +void rmi_unregister_function_driver(struct rmi_function_handler *fh) +{ + struct rmi_function_list *entry, *n; + + /* notify devices of the removal of the function handler */ + bus_for_each_dev(&rmi_bus_type, NULL, fh, __rmi_bus_fh_remove); + + if (list_empty(&rmi_supported_functions.list)) + return; + + list_for_each_entry_safe(entry, n, &rmi_supported_functions.list, + list) { + if (entry->fh->func == fh->func) { + list_del(&entry->list); + kfree(entry); + } + } + +} +EXPORT_SYMBOL(rmi_unregister_function_driver); + +struct rmi_function_handler *rmi_get_function_handler(int id) +{ + struct rmi_function_list *entry; + + if (list_empty(&rmi_supported_functions.list)) + return NULL; + + list_for_each_entry(entry, &rmi_supported_functions.list, list) + if (entry->fh->func == id) + return entry->fh; + + return NULL; +} +EXPORT_SYMBOL(rmi_get_function_handler); + +static void rmi_release_character_device(struct device *dev) +{ + dev_dbg(dev, "%s: Called.\n", __func__); + return; +} + +static int rmi_register_character_device(struct device *dev, void *data) +{ + struct rmi_device *rmi_dev; + struct rmi_char_driver *char_driver = data; + struct rmi_char_device *char_dev; + int retval; + + dev_dbg(dev, "Attaching character device.\n"); + rmi_dev = to_rmi_device(dev); + if (char_driver->match && !char_driver->match(rmi_dev)) + return 0; + + if (!char_driver->init) { + dev_err(dev, "ERROR: No init() function in %s.\n", __func__); + return -EINVAL; + } + + char_dev = kzalloc(sizeof(struct rmi_char_device), GFP_KERNEL); + if (!char_dev) + return -ENOMEM; + + char_dev->rmi_dev = rmi_dev; + char_dev->driver = char_driver; + + char_dev->dev.parent = dev; + char_dev->dev.release = rmi_release_character_device; + char_dev->dev.driver = &char_driver->driver; + retval = device_register(&char_dev->dev); + if (!retval) { + dev_err(dev, "Failed to register character device.\n"); + goto error_exit; + } + + retval = char_driver->init(char_dev); + if (retval) { + dev_err(dev, "Failed to initialize character device.\n"); + goto error_exit; + } + + mutex_lock(&rmi_bus_mutex); + list_add_tail(&char_dev->list, &char_driver->devices); + mutex_unlock(&rmi_bus_mutex); + dev_info(&char_dev->dev, "Registered a device.\n"); + return retval; + +error_exit: + kfree(char_dev); + return retval; +} + +int rmi_register_character_driver(struct rmi_char_driver *char_driver) +{ + struct rmi_character_driver_list *entry; + int retval; + + pr_debug("%s: Registering character driver %s.\n", __func__, + char_driver->driver.name); + + char_driver->driver.bus = &rmi_bus_type; + INIT_LIST_HEAD(&char_driver->devices); + retval = driver_register(&char_driver->driver); + if (retval) { + pr_err("%s: Failed to register %s, code: %d.\n", __func__, + char_driver->driver.name, retval); + return retval; + } + + entry = kzalloc(sizeof(struct rmi_character_driver_list), GFP_KERNEL); + if (!entry) + return -ENOMEM; + entry->cd = char_driver; + + mutex_lock(&rmi_bus_mutex); + list_add_tail(&entry->list, &rmi_character_drivers.list); + mutex_unlock(&rmi_bus_mutex); + + /* notify devices of the removal of the function handler */ + bus_for_each_dev(&rmi_bus_type, NULL, char_driver, + rmi_register_character_device); + + return 0; +} +EXPORT_SYMBOL(rmi_register_character_driver); + + +int rmi_unregister_character_driver(struct rmi_char_driver *char_driver) +{ + struct rmi_character_driver_list *entry, *n; + struct rmi_char_device *char_dev, *m; + pr_debug("%s: Unregistering character driver %s.\n", __func__, + char_driver->driver.name); + + mutex_lock(&rmi_bus_mutex); + list_for_each_entry_safe(char_dev, m, &char_driver->devices, + list) { + list_del(&char_dev->list); + char_dev->driver->remove(char_dev); + } + list_for_each_entry_safe(entry, n, &rmi_character_drivers.list, + list) { + if (entry->cd == char_driver) { + list_del(&entry->list); + kfree(entry); + } + } + mutex_unlock(&rmi_bus_mutex); + + driver_unregister(&char_driver->driver); + + return 0; +} +EXPORT_SYMBOL(rmi_unregister_character_driver); + +static int __init rmi_bus_init(void) +{ + int error; + + mutex_init(&rmi_bus_mutex); + INIT_LIST_HEAD(&rmi_supported_functions.list); + INIT_LIST_HEAD(&rmi_character_drivers.list); + +#ifdef CONFIG_RMI4_DEBUG + rmi_debugfs_root = debugfs_create_dir(rmi_bus_type.name, NULL); + if (!rmi_debugfs_root) + pr_err("%s: Failed to create debugfs root.\n", __func__); + else if (IS_ERR(rmi_debugfs_root)) { + pr_err("%s: Kernel may not contain debugfs support, code=%ld\n", + __func__, PTR_ERR(rmi_debugfs_root)); + rmi_debugfs_root = NULL; + } +#endif + + error = bus_register(&rmi_bus_type); + if (error < 0) { + pr_err("%s: error registering the RMI bus: %d\n", __func__, + error); + return error; + } + pr_debug("%s: successfully registered RMI bus.\n", __func__); + + return 0; +} + +static void __exit rmi_bus_exit(void) +{ + /* We should only ever get here if all drivers are unloaded, so + * all we have to do at this point is unregister ourselves. + */ +#ifdef CONFIG_RMI4_DEBUG + if (rmi_debugfs_root) + debugfs_remove(rmi_debugfs_root); +#endif + bus_unregister(&rmi_bus_type); +} + +module_init(rmi_bus_init); +module_exit(rmi_bus_exit); + +MODULE_AUTHOR("Christopher Heiny +#include +#include +#include +#include +#include +#include + +#include +#include "rmi_driver.h" + +#define CHAR_DEVICE_NAME "rmi" +#define DEVICE_CLASS_NAME "rmidev" + +#define RMI_CHAR_DEV_TMPBUF_SZ 128 +#define RMI_REG_ADDR_PAGE_SELECT 0xFF +#define REG_ADDR_LIMIT 0xFFFF + +struct rmidev_data { + /* mutex for file operation*/ + struct mutex file_mutex; + /* main char dev structure */ + struct cdev main_dev; + + /* pointer to the corresponding RMI4 device. We use this to do */ + /* read, write, etc. */ + struct rmi_device *rmi_dev; + /* reference count */ + int ref_count; + + struct class *device_class; +}; + +/*store dynamically allocated major number of char device*/ +static int rmidev_major_num; + + +static struct class *rmidev_device_class; + + +/* file operations for RMI char device */ + +/* + * rmidev_llseek: - use to setup register address + * + * @filp: file structure for seek + * @off: offset + * if whence == SEEK_SET, + * high 16 bits: page address + * low 16 bits: register address + * + * if whence == SEEK_CUR, + * offset from current position + * + * if whence == SEEK_END, + * offset from END(0xFFFF) + * + * @whence: SEEK_SET , SEEK_CUR or SEEK_END + */ +static loff_t rmidev_llseek(struct file *filp, loff_t off, int whence) +{ + loff_t newpos; + struct rmidev_data *data = filp->private_data; + + if (IS_ERR(data)) { + pr_err("%s: pointer of char device is invalid", __func__); + return -EBADF; + } + + mutex_lock(&(data->file_mutex)); + + switch (whence) { + case SEEK_SET: + newpos = off; + break; + + case SEEK_CUR: + newpos = filp->f_pos + off; + break; + + case SEEK_END: + newpos = REG_ADDR_LIMIT + off; + break; + + default: /* can't happen */ + newpos = -EINVAL; + goto clean_up; + } + + if (newpos < 0 || newpos > REG_ADDR_LIMIT) { + dev_err(&data->rmi_dev->dev, "newpos 0x%04x is invalid.\n", + (unsigned int)newpos); + newpos = -EINVAL; + goto clean_up; + } + + filp->f_pos = newpos; + +clean_up: + mutex_unlock(&(data->file_mutex)); + return newpos; +} + +/* + * rmidev_read: - use to read data from RMI stream + * + * @filp: file structure for read + * @buf: user-level buffer pointer + * + * @count: number of byte read + * @f_pos: offset (starting register address) + * + * @return number of bytes read into user buffer (buf) if succeeds + * negative number if error occurs. + */ +static ssize_t rmidev_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + struct rmidev_data *data = filp->private_data; + ssize_t retval = 0; + unsigned char tmpbuf[count+1]; + + /* limit offset to REG_ADDR_LIMIT-1 */ + if (count > (REG_ADDR_LIMIT - *f_pos)) + count = REG_ADDR_LIMIT - *f_pos; + + if (count == 0) + return 0; + + if (IS_ERR(data)) { + pr_err("%s: pointer of char device is invalid", __func__); + return -EBADF; + } + + mutex_lock(&(data->file_mutex)); + + retval = rmi_read_block(data->rmi_dev, *f_pos, tmpbuf, count); + + if (retval < 0) + goto clean_up; + + if (copy_to_user(buf, tmpbuf, count)) + retval = -EFAULT; + else + *f_pos += retval; + +clean_up: + + mutex_unlock(&(data->file_mutex)); + + return retval; +} + +/* + * rmidev_write: - use to write data into RMI stream + * + * @filep : file structure for write + * @buf: user-level buffer pointer contains data to be written + * @count: number of byte be be written + * @f_pos: offset (starting register address) + * + * @return number of bytes written from user buffer (buf) if succeeds + * negative number if error occurs. + */ +static ssize_t rmidev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) +{ + struct rmidev_data *data = filp->private_data; + ssize_t retval = 0; + unsigned char tmpbuf[count+1]; + + /* limit offset to REG_ADDR_LIMIT-1 */ + if (count > (REG_ADDR_LIMIT - *f_pos)) + count = REG_ADDR_LIMIT - *f_pos; + + if (count == 0) + return 0; + + if (IS_ERR(data)) { + pr_err("%s: pointer of char device is invalid", __func__); + return -EBADF; + } + + if (copy_from_user(tmpbuf, buf, count)) + return -EFAULT; + + mutex_lock(&(data->file_mutex)); + + retval = rmi_write_block(data->rmi_dev, *f_pos, tmpbuf, count); + + if (retval >= 0) + *f_pos += count; + + mutex_unlock(&(data->file_mutex)); + + return retval; +} + +/* + * rmidev_open: - get a new handle for from RMI stream + * @inp : inode struture + * @filp: file structure for read/write + * + * @return 0 if succeeds + */ +static int rmidev_open(struct inode *inp, struct file *filp) +{ + struct rmidev_data *data = container_of(inp->i_cdev, + struct rmidev_data, main_dev); + int retval = 0; + + filp->private_data = data; + + if (!data->rmi_dev) + return -EACCES; + + mutex_lock(&(data->file_mutex)); + if (data->ref_count < 1) + data->ref_count++; + else + retval = -EACCES; + + mutex_unlock(&(data->file_mutex)); + + return retval; +} + +/* + * rmidev_release: - release an existing handle + * @inp: inode structure + * @filp: file structure for read/write + * + * @return 0 if succeeds + */ +static int rmidev_release(struct inode *inp, struct file *filp) +{ + struct rmidev_data *data = container_of(inp->i_cdev, + struct rmidev_data, main_dev); + + if (!data->rmi_dev) + return -EACCES; + + mutex_lock(&(data->file_mutex)); + + data->ref_count--; + if (data->ref_count < 0) + data->ref_count = 0; + + mutex_unlock(&(data->file_mutex)); + + return 0; +} + +static const struct file_operations rmidev_fops = { + .owner = THIS_MODULE, + .llseek = rmidev_llseek, + .read = rmidev_read, + .write = rmidev_write, + .open = rmidev_open, + .release = rmidev_release, +}; + +/* + * rmidev_device_cleanup - release memory or unregister driver + * @rmidev_data: instance data for a particular device. + * + */ +static void rmidev_device_cleanup(struct rmidev_data *data) +{ + dev_t devno; + + /* Get rid of our char dev entries */ + if (data) { + devno = data->main_dev.dev; + + if (data->device_class) + device_destroy(data->device_class, devno); + + cdev_del(&data->main_dev); + kfree(data); + + /* cleanup_module is never called if registering failed */ + unregister_chrdev_region(devno, 1); + pr_debug("%s: rmidev device is removed\n", __func__); + } +} + +/* + * rmi_char_devnode - return device permission + * + * @dev: char device structure + * @mode: file permission + * + */ +static char *rmi_char_devnode(struct device *dev, mode_t *mode) +{ + if (!mode) + return NULL; + /**mode = 0666*/ + *mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + + return kasprintf(GFP_KERNEL, "rmi/%s", dev_name(dev)); +} + +static int rmidev_init_device(struct rmi_char_device *cd) +{ + struct rmi_device *rmi_dev = cd->rmi_dev; + struct rmidev_data *data; + dev_t dev_no; + int retval; + struct device *device_ptr; + + if (rmidev_major_num) { + dev_no = MKDEV(rmidev_major_num, cd->rmi_dev->number); + retval = register_chrdev_region(dev_no, 1, CHAR_DEVICE_NAME); + } else { + retval = alloc_chrdev_region(&dev_no, 0, 1, CHAR_DEVICE_NAME); + /* let kernel allocate a major for us */ + rmidev_major_num = MAJOR(dev_no); + dev_info(&rmi_dev->dev, "Major number of rmidev: %d\n", + rmidev_major_num); + } + if (retval < 0) { + dev_err(&rmi_dev->dev, + "Failed to get minor dev number %d, code %d.\n", + cd->rmi_dev->number, retval); + return retval; + } else + dev_info(&rmi_dev->dev, "Allocated rmidev %d %d.\n", + MAJOR(dev_no), MINOR(dev_no)); + + data = kzalloc(sizeof(struct rmidev_data), GFP_KERNEL); + if (!data) { + dev_err(&rmi_dev->dev, "Failed to allocate rmidev_data.\n"); + /* unregister the char device region */ + __unregister_chrdev(rmidev_major_num, MINOR(dev_no), 1, + CHAR_DEVICE_NAME); + return -ENOMEM; + } + + mutex_init(&data->file_mutex); + + data->rmi_dev = cd->rmi_dev; + cd->data = data; + + cdev_init(&data->main_dev, &rmidev_fops); + + retval = cdev_add(&data->main_dev, dev_no, 1); + if (retval) { + dev_err(&cd->rmi_dev->dev, "Error %d adding rmi_char_dev.\n", + retval); + rmidev_device_cleanup(data); + return retval; + } + + dev_set_name(&cd->dev, "rmidev%d", MINOR(dev_no)); + data->device_class = rmidev_device_class; + device_ptr = device_create( + data->device_class, + NULL, dev_no, NULL, + CHAR_DEVICE_NAME"%d", + MINOR(dev_no)); + + if (IS_ERR(device_ptr)) { + dev_err(&cd->rmi_dev->dev, "Failed to create rmi device.\n"); + rmidev_device_cleanup(data); + return -ENODEV; + } + + return 0; +} + +static void rmidev_remove_device(struct rmi_char_device *cd) +{ + struct rmidev_data *data; + + dev_dbg(&cd->dev, "%s: removing an rmidev device.\n", __func__); + if (!cd) + return; + + data = cd->data; + if (data) + rmidev_device_cleanup(data); +} + +static struct rmi_char_driver rmidev_driver = { + .driver = { + .name = "rmidev", + .owner = THIS_MODULE, + }, + + .init = rmidev_init_device, + .remove = rmidev_remove_device, +}; + +static int __init rmidev_init(void) +{ + int error = 0; + pr_debug("%s: rmi_dev initialization.\n", __func__); + + /* create device node */ + rmidev_device_class = class_create(THIS_MODULE, DEVICE_CLASS_NAME); + + if (IS_ERR(rmidev_device_class)) { + pr_err("%s: ERROR - Failed to create /dev/%s.\n", __func__, + CHAR_DEVICE_NAME); + return -ENODEV; + } + /* setup permission */ + rmidev_device_class->devnode = rmi_char_devnode; + + error = rmi_register_character_driver(&rmidev_driver); + if (error) + class_destroy(rmidev_device_class); + return error; +} + +static void __exit rmidev_exit(void) +{ + pr_debug("%s: exiting.\n", __func__); + rmi_unregister_character_driver(&rmidev_driver); + class_destroy(rmidev_device_class); +} + +module_init(rmidev_init); +module_exit(rmidev_exit); + +MODULE_AUTHOR("Christopher Heiny "); +MODULE_DESCRIPTION("RMI4 Char Device"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/rmi4/rmi_driver.c b/drivers/input/touchscreen/rmi4/rmi_driver.c new file mode 100755 index 000000000000..67f84a8eed92 --- /dev/null +++ b/drivers/input/touchscreen/rmi4/rmi_driver.c @@ -0,0 +1,1616 @@ +/* + * Copyright (c) 2011 Synaptics Incorporated + * Copyright (c) 2011 Unixphere + * + * This driver adds support for generic RMI4 devices from Synpatics. It + * implements the mandatory f01 RMI register and depends on the presence of + * other required RMI functions. + * + * The RMI4 specification can be found here (URL split after files/ for + * style reasons): + * http://www.synaptics.com/sites/default/files/ + * 511-000136-01-Rev-E-RMI4%20Intrfacing%20Guide.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rmi_driver.h" +#ifdef CONFIG_RMI4_DEBUG +#include +#include +#include +#endif + +#define REGISTER_DEBUG 0 + +#define PDT_END_SCAN_LOCATION 0x0005 +#define PDT_PROPERTIES_LOCATION 0x00EF +#define BSR_LOCATION 0x00FE +#define HAS_BSR_MASK 0x20 +#define HAS_NONSTANDARD_PDT_MASK 0x40 +#define RMI4_END_OF_PDT(id) ((id) == 0x00 || (id) == 0xff) +#define RMI4_MAX_PAGE 0xff +#define RMI4_PAGE_SIZE 0x100 + +#define RMI_DEVICE_RESET_CMD 0x01 +#define DEFAULT_RESET_DELAY_MS 20 + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void rmi_driver_early_suspend(struct early_suspend *h); +static void rmi_driver_late_resume(struct early_suspend *h); +#endif + +/* sysfs files for attributes for driver values. */ +static ssize_t rmi_driver_bsr_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t rmi_driver_bsr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t rmi_driver_enabled_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_driver_enabled_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +#if REGISTER_DEBUG +static ssize_t rmi_driver_reg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +#endif + +#ifdef CONFIG_RMI4_DEBUG + +struct driver_debugfs_data { + bool done; + struct rmi_device *rmi_dev; +}; + +static int debug_open(struct inode *inodep, struct file *filp) { + struct driver_debugfs_data *data; + + data = kzalloc(sizeof(struct driver_debugfs_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->rmi_dev = inodep->i_private; + filp->private_data = data; + return 0; +} + +static int debug_release(struct inode *inodep, struct file *filp) { + kfree(filp->private_data); + return 0; +} + +#ifdef CONFIG_RMI4_SPI +#define DELAY_NAME "delay" + +static ssize_t delay_read(struct file *filp, char __user *buffer, size_t size, + loff_t *offset) { + struct driver_debugfs_data *data = filp->private_data; + struct rmi_device_platform_data *pdata = + data->rmi_dev->phys->dev->platform_data; + int retval; + char local_buf[size]; + + if (data->done) + return 0; + + data->done = 1; + + retval = snprintf(local_buf, size, "%d %d %d %d %d\n", + pdata->spi_data.read_delay_us, pdata->spi_data.write_delay_us, + pdata->spi_data.block_delay_us, + pdata->spi_data.pre_delay_us, pdata->spi_data.post_delay_us); + + if (retval <= 0 || copy_to_user(buffer, local_buf, retval)) + return -EFAULT; + + return retval; +} + +static ssize_t delay_write(struct file *filp, const char __user *buffer, + size_t size, loff_t *offset) { + struct driver_debugfs_data *data = filp->private_data; + struct rmi_device_platform_data *pdata = + data->rmi_dev->phys->dev->platform_data; + int retval; + char local_buf[size]; + unsigned int new_read_delay; + unsigned int new_write_delay; + unsigned int new_block_delay; + unsigned int new_pre_delay; + unsigned int new_post_delay; + + retval = copy_from_user(local_buf, buffer, size); + if (retval) + return -EFAULT; + + retval = sscanf(local_buf, "%u %u %u %u %u", &new_read_delay, + &new_write_delay, &new_block_delay, + &new_pre_delay, &new_post_delay); + if (retval != 5) { + dev_err(&data->rmi_dev->dev, + "Incorrect number of values provided for delay."); + return -EINVAL; + } + if (new_read_delay < 0) { + dev_err(&data->rmi_dev->dev, + "Byte delay must be positive microseconds.\n"); + return -EINVAL; + } + if (new_write_delay < 0) { + dev_err(&data->rmi_dev->dev, + "Write delay must be positive microseconds.\n"); + return -EINVAL; + } + if (new_block_delay < 0) { + dev_err(&data->rmi_dev->dev, + "Block delay must be positive microseconds.\n"); + return -EINVAL; + } + if (new_pre_delay < 0) { + dev_err(&data->rmi_dev->dev, + "Pre-transfer delay must be positive microseconds.\n"); + return -EINVAL; + } + if (new_post_delay < 0) { + dev_err(&data->rmi_dev->dev, + "Post-transfer delay must be positive microseconds.\n"); + return -EINVAL; + } + + dev_dbg(&data->rmi_dev->dev, + "Setting delays to %u %u %u %u %u.\n", new_read_delay, + new_write_delay, new_block_delay, new_pre_delay, + new_post_delay); + pdata->spi_data.read_delay_us = new_read_delay; + pdata->spi_data.write_delay_us = new_write_delay; + pdata->spi_data.block_delay_us = new_block_delay; + pdata->spi_data.pre_delay_us = new_pre_delay; + pdata->spi_data.post_delay_us = new_post_delay; + + return size; +} + +static struct file_operations delay_fops = { + .owner = THIS_MODULE, + .open = debug_open, + .release = debug_release, + .read = delay_read, + .write = delay_write, +}; +#endif /* CONFIG_RMI4_SPI */ + +#define PHYS_NAME "phys" + +static ssize_t phys_read(struct file *filp, char __user *buffer, size_t size, + loff_t *offset) { + struct driver_debugfs_data *data = filp->private_data; + struct rmi_phys_info *info = &data->rmi_dev->phys->info; + int retval; + char local_buf[size]; + + if (data->done) + return 0; + + data->done = 1; + + retval = snprintf(local_buf, PAGE_SIZE, + "%-5s %ld %ld %ld %ld %ld %ld %ld\n", + info->proto ? info->proto : "unk", + info->tx_count, info->tx_bytes, info->tx_errs, + info->rx_count, info->rx_bytes, info->rx_errs, + info->attn_count); + if (retval <= 0 || copy_to_user(buffer, local_buf, retval)) + return -EFAULT; + + return retval; +} + +static struct file_operations phys_fops = { + .owner = THIS_MODULE, + .open = debug_open, + .release = debug_release, + .read = phys_read, +}; + +static int setup_debugfs(struct rmi_device *rmi_dev) { + struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev); +#ifdef CONFIG_RMI4_SPI + struct rmi_phys_info *info = &rmi_dev->phys->info; +#endif + int retval = 0; + + if (!rmi_dev->debugfs_root) + return -ENODEV; + +#ifdef CONFIG_RMI4_SPI + if (!strncmp("spi", info->proto, 3)) { + data->debugfs_delay = debugfs_create_file(DELAY_NAME, RMI_RW_ATTR, + rmi_dev->debugfs_root, rmi_dev, &delay_fops); + if (!data->debugfs_delay || IS_ERR(data->debugfs_delay)) { + dev_warn(&rmi_dev->dev, "Failed to create debugfs delay.\n"); + data->debugfs_delay = NULL; + } + } +#endif + + data->debugfs_phys = debugfs_create_file(PHYS_NAME, RMI_RO_ATTR, + rmi_dev->debugfs_root, rmi_dev, &phys_fops); + if (!data->debugfs_phys || IS_ERR(data->debugfs_phys)) { + dev_warn(&rmi_dev->dev, "Failed to create debugfs phys.\n"); + data->debugfs_phys = NULL; + } + + return retval; +} + +static void teardown_debugfs(struct rmi_device *rmi_dev) { + struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev); + +#ifdef CONFIG_RMI4_SPI + if (!data->debugfs_delay) + debugfs_remove(data->debugfs_delay); +#endif + if (!data->debugfs_phys) + debugfs_remove(data->debugfs_phys); +} +#endif + +static int rmi_driver_process_reset_requests(struct rmi_device *rmi_dev); + +static int rmi_driver_process_config_requests(struct rmi_device *rmi_dev); + +static int rmi_driver_irq_restore(struct rmi_device *rmi_dev); + +static struct device_attribute attrs[] = { + __ATTR(enabled, RMI_RW_ATTR, + rmi_driver_enabled_show, rmi_driver_enabled_store), +#if REGISTER_DEBUG + __ATTR(reg, RMI_WO_ATTR, + rmi_show_error, rmi_driver_reg_store), +#endif +}; + +static struct device_attribute bsr_attribute = __ATTR(bsr, RMI_RW_ATTR, + rmi_driver_bsr_show, rmi_driver_bsr_store); + +/* Useful helper functions for u8* */ + +void u8_set_bit(u8 *target, int pos) +{ + target[pos/8] |= 1<pdt_props & HAS_BSR_MASK) != 0; +} + +/* Utility routine to set bits in a register. */ +int rmi_set_bits(struct rmi_device *rmi_dev, unsigned short address, + unsigned char bits) +{ + unsigned char reg_contents; + int retval; + + retval = rmi_read_block(rmi_dev, address, ®_contents, 1); + if (retval) + return retval; + reg_contents = reg_contents | bits; + retval = rmi_write_block(rmi_dev, address, ®_contents, 1); + if (retval == 1) + return 0; + else if (retval == 0) + return -EIO; + return retval; +} +EXPORT_SYMBOL(rmi_set_bits); + +/* Utility routine to clear bits in a register. */ +int rmi_clear_bits(struct rmi_device *rmi_dev, unsigned short address, + unsigned char bits) +{ + unsigned char reg_contents; + int retval; + + retval = rmi_read_block(rmi_dev, address, ®_contents, 1); + if (retval) + return retval; + reg_contents = reg_contents & ~bits; + retval = rmi_write_block(rmi_dev, address, ®_contents, 1); + if (retval == 1) + return 0; + else if (retval == 0) + return -EIO; + return retval; +} +EXPORT_SYMBOL(rmi_clear_bits); + +static void rmi_free_function_list(struct rmi_device *rmi_dev) +{ + struct rmi_function_container *entry, *n; + struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev); + + if (!data) { + dev_err(&rmi_dev->dev, "WTF: No driver data in %s\n", __func__); + return; + } + + if (data->f01_container) { + if (data->f01_container->fh && data->f01_container->fh->remove) { + data->f01_container->fh->remove(data->f01_container); + } + device_unregister(&data->f01_container->dev); + kfree(data->f01_container->irq_mask); + kfree(data->f01_container); + data->f01_container = NULL; + } + + if (list_empty(&data->rmi_functions.list)) + return; + + list_for_each_entry_safe(entry, n, &data->rmi_functions.list, list) { + if (entry->fh) { + if (entry->fh->remove) + entry->fh->remove(entry); + device_unregister(&entry->dev); + } + kfree(entry->irq_mask); + list_del(&entry->list); + kfree(entry); + } +} + +static void no_op(struct device *dev) +{ + dev_dbg(dev, "REMOVING KOBJ!"); + kobject_put(&dev->kobj); +} + +static int init_one_function(struct rmi_device *rmi_dev, + struct rmi_function_container *fc) +{ + int retval; + + if (!fc->fh) { + struct rmi_function_handler *fh = + rmi_get_function_handler(fc->fd.function_number); + if (!fh) { + dev_dbg(&rmi_dev->dev, "No handler for F%02X.\n", + fc->fd.function_number); + return 0; + } + fc->fh = fh; + } + + if (!fc->fh->init) + return 0; + /* This memset might not be what we want to do... */ + memset(&(fc->dev), 0, sizeof(struct device)); + dev_set_name(&(fc->dev), "fn%02x", fc->fd.function_number); + fc->dev.release = no_op; + + fc->dev.parent = &rmi_dev->dev; + dev_dbg(&rmi_dev->dev, "%s: Register F%02X.\n", __func__, + fc->fd.function_number); + retval = device_register(&fc->dev); + if (retval) { + dev_err(&rmi_dev->dev, "Failed device_register for F%02X.\n", + fc->fd.function_number); + return retval; + } + + retval = fc->fh->init(fc); + if (retval < 0) { + dev_err(&rmi_dev->dev, "Failed to initialize function F%02x\n", + fc->fd.function_number); + goto error_exit; + } + + return 0; + +error_exit: + device_unregister(&fc->dev); + return retval; +} + +static void rmi_driver_fh_add(struct rmi_device *rmi_dev, + struct rmi_function_handler *fh) +{ + struct rmi_function_container *entry; + struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev); + + if (!data) + return; + if (fh->func == 0x01) { + if (data->f01_container) + data->f01_container->fh = fh; + } else if (!list_empty(&data->rmi_functions.list)) { + mutex_lock(&data->pdt_mutex); + list_for_each_entry(entry, &data->rmi_functions.list, list) + if (entry->fd.function_number == fh->func) { + entry->fh = fh; + if (init_one_function(rmi_dev, entry) < 0) + entry->fh = NULL; + } + mutex_unlock(&data->pdt_mutex); + } + +} + +static void rmi_driver_fh_remove(struct rmi_device *rmi_dev, + struct rmi_function_handler *fh) +{ + struct rmi_function_container *entry, *temp; + struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev); + + if (fh->func == 0x01) { + /* don't call remove here since + * rmi_f01_initialize just get call one time */ + if (data->f01_container) + data->f01_container->fh = NULL; + return; + } + + list_for_each_entry_safe(entry, temp, &data->rmi_functions.list, + list) { + if (entry->fh && entry->fd.function_number == fh->func) { + if (fh->remove) + fh->remove(entry); + + entry->fh = NULL; + device_unregister(&entry->dev); + } + } +} + +static int rmi_driver_process_reset_requests(struct rmi_device *rmi_dev) +{ + struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev); + struct device *dev = &rmi_dev->dev; + struct rmi_function_container *entry; + int retval; + + /* Device control (F01) is handled before anything else. */ + + if (data->f01_container && data->f01_container->fh && + data->f01_container->fh->reset) { + retval = data->f01_container->fh->reset(data->f01_container); + if (retval < 0) { + dev_err(dev, "F%02x reset handler failed: %d.\n", + data->f01_container->fh->func, retval); + return retval; + } + } + + if (list_empty(&data->rmi_functions.list)) + return 0; + + list_for_each_entry(entry, &data->rmi_functions.list, list) { + if (entry->fh && entry->fh->reset) { + retval = entry->fh->reset(entry); + if (retval < 0) { + dev_err(dev, "F%02x reset handler failed: %d\n", + entry->fh->func, retval); + return retval; + } + } + } + + return 0; +} + +static int rmi_driver_process_config_requests(struct rmi_device *rmi_dev) +{ + struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev); + struct device *dev = &rmi_dev->dev; + struct rmi_function_container *entry; + int retval; + + /* Device control (F01) is handled before anything else. */ + + if (data->f01_container && data->f01_container->fh && + data->f01_container->fh->config) { + retval = data->f01_container->fh->config(data->f01_container); + if (retval < 0) { + dev_err(dev, "F%02x config handler failed: %d.\n", + data->f01_container->fh->func, retval); + return retval; + } + } + + if (list_empty(&data->rmi_functions.list)) + return 0; + + list_for_each_entry(entry, &data->rmi_functions.list, list) { + if (entry->fh && entry->fh->config) { + retval = entry->fh->config(entry); + if (retval < 0) { + dev_err(dev, "F%02x config handler failed: %d.\n", + entry->fh->func, retval); + return retval; + } + } + } + + return 0; +} + +static void construct_mask(u8 *mask, int num, int pos) +{ + int i; + + for (i = 0; i < num; i++) + u8_set_bit(mask, pos+i); +} + +static int process_interrupt_requests(struct rmi_device *rmi_dev) +{ + struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev); + struct device *dev = &rmi_dev->dev; + struct rmi_function_container *entry; + u8 irq_status[data->num_of_irq_regs]; + u8 irq_bits[data->num_of_irq_regs]; + int error; + + error = rmi_read_block(rmi_dev, + data->f01_container->fd.data_base_addr + 1, + irq_status, data->num_of_irq_regs); + if (error < 0) { + dev_err(dev, "%s: failed to read irqs.", __func__); + return error; + } + /* Device control (F01) is handled before anything else. */ + if (data->f01_container->irq_mask && data->f01_container->fh->attention) { + u8_and(irq_bits, irq_status, data->f01_container->irq_mask, + data->num_of_irq_regs); + if (u8_is_any_set(irq_bits, data->num_of_irq_regs)) + data->f01_container->fh->attention( + data->f01_container, irq_bits); + } + + u8_and(irq_status, irq_status, data->current_irq_mask, + data->num_of_irq_regs); + /* At this point, irq_status has all bits that are set in the + * interrupt status register and are enabled. + */ + + list_for_each_entry(entry, &data->rmi_functions.list, list) + if (entry->irq_mask && entry->fh && entry->fh->attention) { + u8_and(irq_bits, irq_status, entry->irq_mask, + data->num_of_irq_regs); + if (u8_is_any_set(irq_bits, data->num_of_irq_regs)) { + error = entry->fh->attention(entry, irq_bits); + if (error < 0) + dev_err(dev, "%s: f%.2x" + " attention handler failed:" + " %d\n", __func__, + entry->fh->func, error); + } + } + + return 0; +} + +static int rmi_driver_irq_handler(struct rmi_device *rmi_dev, int irq) +{ + struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev); + + /* Can get called before the driver is fully ready to deal with + * interrupts. + */ + if (!data || !data->f01_container || !data->f01_container->fh) { + dev_warn(&rmi_dev->dev, + "Not ready to handle interrupts yet!\n"); + return 0; + } + return process_interrupt_requests(rmi_dev); +} + +static int rmi_driver_reset_handler(struct rmi_device *rmi_dev) +{ + struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev); + int error; + + /* Can get called before the driver is fully ready to deal with + * interrupts. + */ + if (!data || !data->f01_container || !data->f01_container->fh) { + dev_warn(&rmi_dev->dev, + "Not ready to handle reset yet!\n"); + return 0; + } + + error = rmi_driver_process_reset_requests(rmi_dev); + if (error < 0) + return error; + + + error = rmi_driver_process_config_requests(rmi_dev); + if (error < 0) + return error; + + if (data->irq_stored) { + error = rmi_driver_irq_restore(rmi_dev); + if (error < 0) + return error; + } + + return 0; +} + + + +/* + * Construct a function's IRQ mask. This should + * be called once and stored. + */ +static u8 *rmi_driver_irq_get_mask(struct rmi_device *rmi_dev, + struct rmi_function_container *fc) { + struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev); + + u8 *irq_mask = kzalloc(sizeof(u8) * data->num_of_irq_regs, GFP_KERNEL); + if (irq_mask) + construct_mask(irq_mask, fc->num_of_irqs, fc->irq_pos); + + return irq_mask; +} + +/* + * This pair of functions allows functions like function 54 to request to have + * other interupts disabled until the restore function is called. Only one store + * happens at a time. + */ +static int rmi_driver_irq_save(struct rmi_device *rmi_dev, u8 * new_ints) +{ + int retval = 0; + struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev); + struct device *dev = &rmi_dev->dev; + + mutex_lock(&data->irq_mutex); + if (!data->irq_stored) { + /* Save current enabled interupts */ + retval = rmi_read_block(rmi_dev, + data->f01_container->fd.control_base_addr+1, + data->irq_mask_store, data->num_of_irq_regs); + if (retval < 0) { + dev_err(dev, "%s: Failed to read enabled interrupts!", + __func__); + goto error_unlock; + } + /* + * Disable every interupt except for function 54 + * TODO:Will also want to not disable function 1-like functions. + * No need to take care of this now, since there's no good way + * to identify them. + */ + retval = rmi_write_block(rmi_dev, + data->f01_container->fd.control_base_addr+1, + new_ints, data->num_of_irq_regs); + if (retval < 0) { + dev_err(dev, "%s: Failed to change enabled interrupts!", + __func__); + goto error_unlock; + } + memcpy(data->current_irq_mask, new_ints, + data->num_of_irq_regs * sizeof(u8)); + data->irq_stored = true; + } else { + retval = -ENOSPC; /* No space to store IRQs.*/ + dev_err(dev, "%s: Attempted to save values when" + " already stored!", __func__); + } + +error_unlock: + mutex_unlock(&data->irq_mutex); + return retval; +} + +static int rmi_driver_irq_restore(struct rmi_device *rmi_dev) +{ + int retval = 0; + struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev); + struct device *dev = &rmi_dev->dev; + mutex_lock(&data->irq_mutex); + + if (data->irq_stored) { + retval = rmi_write_block(rmi_dev, + data->f01_container->fd.control_base_addr+1, + data->irq_mask_store, data->num_of_irq_regs); + if (retval < 0) { + dev_err(dev, "%s: Failed to write enabled interupts!", + __func__); + goto error_unlock; + } + memcpy(data->current_irq_mask, data->irq_mask_store, + data->num_of_irq_regs * sizeof(u8)); + data->irq_stored = false; + } else { + retval = -EINVAL; + dev_err(dev, "%s: Attempted to restore values when not stored!", + __func__); + } + +error_unlock: + mutex_unlock(&data->irq_mutex); + return retval; +} + +static int rmi_driver_fn_generic(struct rmi_device *rmi_dev, + struct pdt_entry *pdt_ptr, + int *current_irq_count, + u16 page_start) +{ + struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev); + struct rmi_function_container *fc = NULL; + int retval = 0; + struct device *dev = &rmi_dev->dev; + struct rmi_device_platform_data *pdata; + + pdata = to_rmi_platform_data(rmi_dev); + + dev_dbg(dev, "Initializing F%02X for %s.\n", pdt_ptr->function_number, + pdata->sensor_name); + + fc = kzalloc(sizeof(struct rmi_function_container), + GFP_KERNEL); + if (!fc) { + dev_err(dev, "Failed to allocate container for F%02X.\n", + pdt_ptr->function_number); + retval = -ENOMEM; + goto error_free_data; + } + + copy_pdt_entry_to_fd(pdt_ptr, &fc->fd, page_start); + + fc->rmi_dev = rmi_dev; + fc->num_of_irqs = pdt_ptr->interrupt_source_count; + fc->irq_pos = *current_irq_count; + *current_irq_count += fc->num_of_irqs; + + retval = init_one_function(rmi_dev, fc); + if (retval < 0) { + dev_err(dev, "Failed to initialize F%.2x\n", + pdt_ptr->function_number); + goto error_free_data; + } + + INIT_LIST_HEAD(&fc->list); + list_add_tail(&fc->list, &data->rmi_functions.list); + return 0; + +error_free_data: + kfree(fc); + return retval; +} + +/* + * F01 was once handled very differently from all other functions. It is + * now only slightly special, and as the driver is refined we expect this + * function to go away. + */ +static int rmi_driver_fn_01_specific(struct rmi_device *rmi_dev, + struct pdt_entry *pdt_ptr, + int *current_irq_count, + u16 page_start) +{ + struct rmi_driver_data *data = NULL; + struct rmi_function_container *fc = NULL; + union f01_device_status device_status; + int retval = 0; + struct device *dev = &rmi_dev->dev; + struct rmi_function_handler *fh = + rmi_get_function_handler(0x01); + struct rmi_device_platform_data *pdata; + + pdata = to_rmi_platform_data(rmi_dev); + data = rmi_get_driverdata(rmi_dev); + + retval = rmi_read(rmi_dev, pdt_ptr->data_base_addr, &device_status.reg); + if (retval) { + dev_err(dev, "Failed to read device status.\n"); + return retval; + } + + dev_dbg(dev, "Initializing F01 for %s.\n", pdata->sensor_name); + + if (!fh) + dev_dbg(dev, "%s: No function handler for F01?!", __func__); + + fc = kzalloc(sizeof(struct rmi_function_container), GFP_KERNEL); + if (!fc) { + retval = -ENOMEM; + return retval; + } + + copy_pdt_entry_to_fd(pdt_ptr, &fc->fd, page_start); + fc->num_of_irqs = pdt_ptr->interrupt_source_count; + fc->irq_pos = *current_irq_count; + *current_irq_count += fc->num_of_irqs; + + fc->rmi_dev = rmi_dev; + fc->dev.parent = &fc->rmi_dev->dev; + fc->fh = fh; + + dev_set_name(&(fc->dev), "fn%02x", fc->fd.function_number); + fc->dev.release = no_op; + + dev_dbg(dev, "%s: Register F01.\n", __func__); + retval = device_register(&fc->dev); + if (retval) { + dev_err(dev, "%s: Failed device_register for F01.\n", __func__); + goto error_free_data; + } + + data->f01_container = fc; + data->f01_bootloader_mode = device_status.flash_prog; + if (device_status.flash_prog) + dev_warn(dev, "WARNING: RMI4 device is in bootloader mode!\n"); + + INIT_LIST_HEAD(&fc->list); + + return retval; + +error_free_data: + kfree(fc); + return retval; +} + +/* + * Scan the PDT for F01 so we can force a reset before anything else + * is done. This forces the sensor into a known state, and also + * forces application of any pending updates from reflashing the + * firmware or configuration. We have to do this before actually + * building the PDT because the reflash might cause various registers + * to move around. + */ +static int do_initial_reset(struct rmi_device *rmi_dev) +{ + struct pdt_entry pdt_entry; + int page; + struct device *dev = &rmi_dev->dev; + bool done = false; + int i; + int retval; + struct rmi_device_platform_data *pdata; + + dev_dbg(dev, "Initial reset.\n"); + pdata = to_rmi_platform_data(rmi_dev); + for (page = 0; (page <= RMI4_MAX_PAGE) && !done; page++) { + u16 page_start = RMI4_PAGE_SIZE * page; + u16 pdt_start = page_start + PDT_START_SCAN_LOCATION; + u16 pdt_end = page_start + PDT_END_SCAN_LOCATION; + + done = true; + for (i = pdt_start; i >= pdt_end; i -= sizeof(pdt_entry)) { + retval = rmi_read_block(rmi_dev, i, (u8 *)&pdt_entry, + sizeof(pdt_entry)); + if (retval != sizeof(pdt_entry)) { + dev_err(dev, "Read PDT entry at 0x%04x" + "failed, code = %d.\n", i, retval); + return retval; + } + + if (RMI4_END_OF_PDT(pdt_entry.function_number)) + break; + done = false; + + if (pdt_entry.function_number == 0x01) { + u16 cmd_addr = page_start + + pdt_entry.command_base_addr; + u8 cmd_buf = RMI_DEVICE_RESET_CMD; + retval = rmi_write_block(rmi_dev, cmd_addr, + &cmd_buf, 1); + if (retval < 0) { + dev_err(dev, "Initial reset failed. " + "Code = %d.\n", retval); + return retval; + } + mdelay(pdata->reset_delay_ms); + return 0; + } + } + } + + dev_warn(dev, "WARNING: Failed to find F01 for initial reset.\n"); + return -ENODEV; +} + +static int rmi_scan_pdt(struct rmi_device *rmi_dev) +{ + struct rmi_driver_data *data; + struct pdt_entry pdt_entry; + int page; + struct device *dev = &rmi_dev->dev; + int irq_count = 0; + bool done = false; + int i; + int retval; +#ifdef CONFIG_RMI4_DEBUG + dev_info(dev, "Scanning PDT...\n"); +#endif + data = rmi_get_driverdata(rmi_dev); + mutex_lock(&data->pdt_mutex); + + for (page = 0; (page <= RMI4_MAX_PAGE) && !done; page++) { + u16 page_start = RMI4_PAGE_SIZE * page; + u16 pdt_start = page_start + PDT_START_SCAN_LOCATION; + u16 pdt_end = page_start + PDT_END_SCAN_LOCATION; + + done = true; + for (i = pdt_start; i >= pdt_end; i -= sizeof(pdt_entry)) { + retval = rmi_read_block(rmi_dev, i, (u8 *)&pdt_entry, + sizeof(pdt_entry)); + if (retval != sizeof(pdt_entry)) { + dev_err(dev, "Read PDT entry at 0x%04x " + "failed.\n", i); + goto error_exit; + } + + if (RMI4_END_OF_PDT(pdt_entry.function_number)) + break; +#ifdef CONFIG_RMI4_DEBUG + dev_info(dev, "%s: Found F%.2X on page 0x%02X\n", + __func__, pdt_entry.function_number, page); +#endif + done = false; + + if (pdt_entry.function_number == 0x01) + retval = rmi_driver_fn_01_specific(rmi_dev, + &pdt_entry, &irq_count, + page_start); + else + retval = rmi_driver_fn_generic(rmi_dev, + &pdt_entry, &irq_count, + page_start); + + if (retval) + goto error_exit; +#ifdef CONFIG_RMI4_DEBUG + printk("command_base_addr:%x, control_base_addr:%x, data_base_addr:%x\n", pdt_entry.command_base_addr, + pdt_entry.control_base_addr, pdt_entry.data_base_addr); +#else + msleep(1); //in this for(), enough delay is needed, or may cause system die +#endif + } + done = done || data->f01_bootloader_mode; + } + data->irq_count = irq_count; + data->num_of_irq_regs = (irq_count + 7) / 8; + dev_dbg(dev, "%s: Done with PDT scan.\n", __func__); + retval = 0; + +error_exit: + mutex_unlock(&data->pdt_mutex); + return retval; +} + +static int rmi_driver_probe(struct rmi_device *rmi_dev) +{ + struct rmi_driver_data *data = NULL; + struct rmi_function_container *fc; + struct rmi_device_platform_data *pdata; + int retval = 0; + struct device *dev = &rmi_dev->dev; + int attr_count = 0; + + dev_dbg(dev, "%s: Starting probe.\n", __func__); + + pdata = to_rmi_platform_data(rmi_dev); + + data = kzalloc(sizeof(struct rmi_driver_data), GFP_KERNEL); + if (!data) { + dev_err(dev, "%s: Failed to allocate driver data.\n", __func__); + return -ENOMEM; + } + INIT_LIST_HEAD(&data->rmi_functions.list); + rmi_set_driverdata(rmi_dev, data); + mutex_init(&data->pdt_mutex); + + if (!pdata->reset_delay_ms) + pdata->reset_delay_ms = DEFAULT_RESET_DELAY_MS; + retval = do_initial_reset(rmi_dev); + if (retval) + dev_warn(dev, "RMI initial reset failed! Soldiering on.\n"); + + + retval = rmi_scan_pdt(rmi_dev); + if (retval) { + dev_err(dev, "PDT scan for %s failed with code %d.\n", + pdata->sensor_name, retval); + goto err_free_data; + } + + if (!data->f01_container) { + dev_err(dev, "missing F01 container!\n"); + retval = -EINVAL; + goto err_free_data; + } + + data->f01_container->irq_mask = kzalloc( + sizeof(u8) * data->num_of_irq_regs, GFP_KERNEL); + if (!data->f01_container->irq_mask) { + dev_err(dev, "Failed to allocate F01 IRQ mask.\n"); + retval = -ENOMEM; + goto err_free_data; + } + construct_mask(data->f01_container->irq_mask, + data->f01_container->num_of_irqs, + data->f01_container->irq_pos); + list_for_each_entry(fc, &data->rmi_functions.list, list) + fc->irq_mask = rmi_driver_irq_get_mask(rmi_dev, fc); + + retval = rmi_driver_f01_init(rmi_dev); + if (retval < 0) { + dev_err(dev, "Failed to initialize F01.\n"); + goto err_free_data; + } + + retval = rmi_read(rmi_dev, PDT_PROPERTIES_LOCATION, + (char *) &data->pdt_props); + if (retval < 0) { + /* we'll print out a warning and continue since + * failure to get the PDT properties is not a cause to fail + */ + dev_warn(dev, "Could not read PDT properties from 0x%04x. " + "Assuming 0x00.\n", PDT_PROPERTIES_LOCATION); + } + + dev_dbg(dev, "%s: Creating sysfs files.", __func__); + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { + retval = device_create_file(dev, &attrs[attr_count]); + if (retval < 0) { + dev_err(dev, "%s: Failed to create sysfs file %s.\n", + __func__, attrs[attr_count].attr.name); + goto err_free_data; + } + } + if (has_bsr(data)) { + retval = device_create_file(dev, &bsr_attribute); + if (retval < 0) { + dev_err(dev, "%s: Failed to create sysfs file bsr.\n", + __func__); + goto err_free_data; + } + } + + mutex_init(&data->irq_mutex); + data->current_irq_mask = kzalloc(sizeof(u8) * data->num_of_irq_regs, + GFP_KERNEL); + if (!data->current_irq_mask) { + dev_err(dev, "Failed to allocate current_irq_mask.\n"); + retval = -ENOMEM; + goto err_free_data; + } + retval = rmi_read_block(rmi_dev, + data->f01_container->fd.control_base_addr+1, + data->current_irq_mask, data->num_of_irq_regs); + if (retval < 0) { + dev_err(dev, "%s: Failed to read current IRQ mask.\n", + __func__); + goto err_free_data; + } + data->irq_mask_store = kzalloc(sizeof(u8) * data->num_of_irq_regs, + GFP_KERNEL); + if (!data->irq_mask_store) { + dev_err(dev, "Failed to allocate mask store.\n"); + retval = -ENOMEM; + goto err_free_data; + } + +#ifdef CONFIG_PM + data->pm_data = pdata->pm_data; + data->pre_suspend = pdata->pre_suspend; + data->post_resume = pdata->post_resume; + + mutex_init(&data->suspend_mutex); + +#ifdef CONFIG_HAS_EARLYSUSPEND + rmi_dev->early_suspend_handler.level = + EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + rmi_dev->early_suspend_handler.suspend = rmi_driver_early_suspend; + rmi_dev->early_suspend_handler.resume = rmi_driver_late_resume; + register_early_suspend(&rmi_dev->early_suspend_handler); +#endif /* CONFIG_HAS_EARLYSUSPEND */ +#endif /* CONFIG_PM */ + data->enabled = true; + +#ifdef CONFIG_RMI4_DEBUG + retval = setup_debugfs(rmi_dev); + if (retval < 0) + dev_warn(&fc->dev, "Failed to setup debugfs. Code: %d.\n", + retval); +#endif + + return 0; + + err_free_data: + rmi_free_function_list(rmi_dev); + for (attr_count--; attr_count >= 0; attr_count--) + device_remove_file(dev, &attrs[attr_count]); + if (has_bsr(data)) + device_remove_file(dev, &bsr_attribute); + if (data->f01_container) + kfree(data->f01_container->irq_mask); + kfree(data->irq_mask_store); + kfree(data->current_irq_mask); + kfree(data); + rmi_set_driverdata(rmi_dev, NULL); + return retval; +} + +#ifdef CONFIG_PM +static int rmi_driver_suspend(struct device *dev) +{ + struct rmi_device *rmi_dev; + struct rmi_driver_data *data; + struct rmi_function_container *entry; + int retval = 0; + + rmi_dev = to_rmi_device(dev); + data = rmi_get_driverdata(rmi_dev); + + mutex_lock(&data->suspend_mutex); + if (data->suspended) + goto exit; + +#ifndef CONFIG_HAS_EARLYSUSPEND + if (data->pre_suspend) { + retval = data->pre_suspend(data->pm_data); + if (retval) + goto exit; + } +#endif /* !CONFIG_HAS_EARLYSUSPEND */ + + list_for_each_entry(entry, &data->rmi_functions.list, list) + if (entry->fh && entry->fh->suspend) { + retval = entry->fh->suspend(entry); + if (retval < 0) + goto exit; + } + + if (data->f01_container && data->f01_container->fh + && data->f01_container->fh->suspend) { + retval = data->f01_container->fh->suspend(data->f01_container); + if (retval < 0) + goto exit; + } + data->suspended = true; + +exit: + mutex_unlock(&data->suspend_mutex); + return retval; +} + +static int rmi_driver_resume(struct device *dev) +{ + struct rmi_device *rmi_dev; + struct rmi_driver_data *data; + struct rmi_function_container *entry; + int retval = 0; + + rmi_dev = to_rmi_device(dev); + data = rmi_get_driverdata(rmi_dev); + + mutex_lock(&data->suspend_mutex); + if (!data->suspended) + goto exit; + + if (data->f01_container && data->f01_container->fh + && data->f01_container->fh->resume) { + retval = data->f01_container->fh->resume(data->f01_container); + if (retval < 0) + goto exit; + } + + list_for_each_entry(entry, &data->rmi_functions.list, list) + if (entry->fh && entry->fh->resume) { + retval = entry->fh->resume(entry); + if (retval < 0) + goto exit; + } + +#ifndef CONFIG_HAS_EARLYSUSPEND + if (data->post_resume) { + retval = data->post_resume(data->pm_data); + if (retval) + goto exit; + } +#endif /* !CONFIG_HAS_EARLYSUSPEND */ + + data->suspended = false; + +exit: + mutex_unlock(&data->suspend_mutex); + return retval; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void rmi_driver_early_suspend(struct early_suspend *h) +{ + struct rmi_device *rmi_dev = + container_of(h, struct rmi_device, early_suspend_handler); + struct rmi_driver_data *data; + struct rmi_function_container *entry; + int retval = 0; + + data = rmi_get_driverdata(rmi_dev); + dev_dbg(&rmi_dev->dev, "Early suspend.\n"); + + mutex_lock(&data->suspend_mutex); + if (data->suspended) + goto exit; + + if (data->pre_suspend) { + retval = data->pre_suspend(data->pm_data); + if (retval) + goto exit; + } + + list_for_each_entry(entry, &data->rmi_functions.list, list) + if (entry->fh && entry->fh->early_suspend) { + retval = entry->fh->early_suspend(entry); + if (retval < 0) + goto exit; + } + + if (data->f01_container && data->f01_container->fh + && data->f01_container->fh->early_suspend) { + retval = data->f01_container->fh->early_suspend( + data->f01_container); + if (retval < 0) + goto exit; + } + data->suspended = true; + +exit: + mutex_unlock(&data->suspend_mutex); +} + +static void rmi_driver_late_resume(struct early_suspend *h) +{ + struct rmi_device *rmi_dev = + container_of(h, struct rmi_device, early_suspend_handler); + struct rmi_driver_data *data; + struct rmi_function_container *entry; + int retval = 0; + + data = rmi_get_driverdata(rmi_dev); + dev_dbg(&rmi_dev->dev, "Late resume.\n"); + + mutex_lock(&data->suspend_mutex); + if (!data->suspended) + goto exit; + + if (data->f01_container && data->f01_container->fh + && data->f01_container->fh->late_resume) { + retval = data->f01_container->fh->late_resume( + data->f01_container); + if (retval < 0) + goto exit; + } + + list_for_each_entry(entry, &data->rmi_functions.list, list) + if (entry->fh && entry->fh->late_resume) { + retval = entry->fh->late_resume(entry); + if (retval < 0) + goto exit; + } + + if (data->post_resume) { + retval = data->post_resume(data->pm_data); + if (retval) + goto exit; + } + + data->suspended = false; + +exit: + mutex_unlock(&data->suspend_mutex); +} +#endif /* CONFIG_HAS_EARLYSUSPEND */ +#endif /* CONFIG_PM */ + +static int __devexit rmi_driver_remove(struct rmi_device *rmi_dev) +{ + struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev); + struct rmi_function_container *entry; + int i; + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&rmi_dev->early_suspend_handler); +#endif /* CONFIG_HAS_EARLYSUSPEND */ +#ifdef CONFIG_RMI4_DEBUG + teardown_debugfs(rmi_dev); +#endif + + list_for_each_entry(entry, &data->rmi_functions.list, list) + if (entry->fh && entry->fh->remove) + entry->fh->remove(entry); + + rmi_free_function_list(rmi_dev); + for (i = 0; i < ARRAY_SIZE(attrs); i++) + device_remove_file(&rmi_dev->dev, &attrs[i]); + if (has_bsr(data)) + device_remove_file(&rmi_dev->dev, &bsr_attribute); + kfree(data->f01_container->irq_mask); + kfree(data->irq_mask_store); + kfree(data->current_irq_mask); + kfree(data); + + return 0; +} + +#ifdef UNIVERSAL_DEV_PM_OPS +static UNIVERSAL_DEV_PM_OPS(rmi_driver_pm, rmi_driver_suspend, + rmi_driver_resume, NULL); +#endif + +static struct rmi_driver sensor_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "rmi_generic", +#ifdef UNIVERSAL_DEV_PM_OPS + .pm = &rmi_driver_pm, +#endif + }, + .probe = rmi_driver_probe, + .irq_handler = rmi_driver_irq_handler, + .reset_handler = rmi_driver_reset_handler, + .fh_add = rmi_driver_fh_add, + .fh_remove = rmi_driver_fh_remove, + .get_func_irq_mask = rmi_driver_irq_get_mask, + .store_irq_mask = rmi_driver_irq_save, + .restore_irq_mask = rmi_driver_irq_restore, + .remove = __devexit_p(rmi_driver_remove) +}; + +/* sysfs show and store fns for driver attributes */ + +static ssize_t rmi_driver_bsr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rmi_device *rmi_dev; + struct rmi_driver_data *data; + rmi_dev = to_rmi_device(dev); + data = rmi_get_driverdata(rmi_dev); + + return snprintf(buf, PAGE_SIZE, "%u\n", data->bsr); +} + +static ssize_t rmi_driver_bsr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int retval; + unsigned long val; + struct rmi_device *rmi_dev; + struct rmi_driver_data *data; + + rmi_dev = to_rmi_device(dev); + data = rmi_get_driverdata(rmi_dev); + + /* need to convert the string data to an actual value */ + retval = strict_strtoul(buf, 10, &val); + if (retval < 0) { + dev_err(dev, "Invalid value '%s' written to BSR.\n", buf); + return -EINVAL; + } + + retval = rmi_write(rmi_dev, BSR_LOCATION, (unsigned char)val); + if (retval) { + dev_err(dev, "%s : failed to write bsr %u to 0x%x\n", + __func__, (unsigned int)val, BSR_LOCATION); + return retval; + } + + data->bsr = val; + + return count; +} + +static void disable_sensor(struct rmi_device *rmi_dev) +{ + struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev); + + rmi_dev->phys->disable_device(rmi_dev->phys); + + data->enabled = false; +} + +static int enable_sensor(struct rmi_device *rmi_dev) +{ + struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev); + int retval = 0; + + retval = rmi_dev->phys->enable_device(rmi_dev->phys); + /* non-zero means error occurred */ + if (retval) + return retval; + + data->enabled = true; + + return 0; +} + +static ssize_t rmi_driver_enabled_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rmi_device *rmi_dev; + struct rmi_driver_data *data; + + rmi_dev = to_rmi_device(dev); + data = rmi_get_driverdata(rmi_dev); + + return snprintf(buf, PAGE_SIZE, "%u\n", data->enabled); +} + +static ssize_t rmi_driver_enabled_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int retval; + int new_value; + struct rmi_device *rmi_dev; + struct rmi_driver_data *data; + + rmi_dev = to_rmi_device(dev); + data = rmi_get_driverdata(rmi_dev); + + if (sysfs_streq(buf, "0")) + new_value = false; + else if (sysfs_streq(buf, "1")) + new_value = true; + else + return -EINVAL; + + if (new_value) { + retval = enable_sensor(rmi_dev); + if (retval) { + dev_err(dev, "Failed to enable sensor, code=%d.\n", + retval); + return -EIO; + } + } else { + disable_sensor(rmi_dev); + } + + return count; +} + +#if REGISTER_DEBUG +static ssize_t rmi_driver_reg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int retval; + unsigned int address; + unsigned int bytes; + struct rmi_device *rmi_dev; + struct rmi_driver_data *data; + u8 readbuf[128]; + unsigned char outbuf[512]; + unsigned char *bufptr = outbuf; + int i; + + rmi_dev = to_rmi_device(dev); + data = rmi_get_driverdata(rmi_dev); + + retval = sscanf(buf, "%x %u", &address, &bytes); + if (retval != 2) { + dev_err(dev, "Invalid input (code %d) for reg store: %s", + retval, buf); + return -EINVAL; + } + if (address < 0 || address > 0xFFFF) { + dev_err(dev, "Invalid address for reg store '%#06x'.\n", + address); + return -EINVAL; + } + if (bytes < 0 || bytes >= sizeof(readbuf) || address+bytes > 65535) { + dev_err(dev, "Invalid byte count for reg store '%d'.\n", + bytes); + return -EINVAL; + } + + retval = rmi_read_block(rmi_dev, address, readbuf, bytes); + if (retval != bytes) { + dev_err(dev, "Failed to read %d registers at %#06x, code %d.\n", + bytes, address, retval); + return retval; + } + + dev_info(dev, "Reading %d bytes from %#06x.\n", bytes, address); + for (i = 0; i < bytes; i++) { + retval = snprintf(bufptr, 4, "%02X ", readbuf[i]); + if (retval < 0) { + dev_err(dev, "Failed to format string. Code: %d", + retval); + return retval; + } + bufptr += retval; + } + dev_info(dev, "%s\n", outbuf); + + return count; +} +#endif + +static int __init rmi_driver_init(void) +{ + return rmi_register_driver(&sensor_driver); +} + +static void __exit rmi_driver_exit(void) +{ + rmi_unregister_driver(&sensor_driver); +} + +module_init(rmi_driver_init); +module_exit(rmi_driver_exit); + +MODULE_AUTHOR("Christopher Heiny +/* Sysfs related macros */ + +/* You must define FUNCTION_DATA and FNUM to use these functions. */ +#define RMI4_SYSFS_DEBUG defined(CONFIG_RMI4_DEBUG) || defined(CONFIG_ANDROID)) + +#if defined(FNUM) && defined(FUNCTION_DATA) + +#define tricat(x,y,z) tricat_(x,y,z) + +#define tricat_(x,y,z) x##y##z + +#define show_union_struct_prototype(propname)\ +static ssize_t tricat(rmi_fn_,FNUM,_##propname##_show)(\ + struct device *dev,\ + struct device_attribute *attr,\ + char *buf);\ +\ +DEVICE_ATTR(propname, RMI_RO_ATTR,\ + tricat(rmi_fn_,FNUM,_##propname##_show),\ + rmi_store_error); + +#define store_union_struct_prototype(propname)\ +static ssize_t tricat(rmi_fn_,FNUM,_##propname##_store)(\ + struct device *dev,\ + struct device_attribute *attr,\ + const char *buf, size_t count);\ +\ +DEVICE_ATTR(propname, RMI_WO_ATTR,\ + rmi_show_error,\ + tricat(rmi_fn_, FNUM, _##propname##_store)); + + +#define show_store_union_struct_prototype(propname)\ +static ssize_t tricat(rmi_fn_, FNUM, _##propname##_show)(\ + struct device *dev,\ + struct device_attribute *attr,\ + char *buf);\ +\ +static ssize_t tricat(rmi_fn_, FNUM, _##propname##_store)(\ + struct device *dev,\ + struct device_attribute *attr,\ + const char *buf, size_t count);\ +\ +DEVICE_ATTR(propname, RMI_RW_ATTR,\ + tricat(rmi_fn_, FNUM, _##propname##_show),\ + tricat(rmi_fn_, FNUM, _##propname##_store)); + +#define simple_show_union_struct(regtype, propname, fmt)\ +static ssize_t tricat(rmi_fn_, FNUM, _##propname##_show)(struct device *dev,\ + struct device_attribute *attr, char *buf) {\ + struct rmi_function_container *fc;\ + struct FUNCTION_DATA *data;\ +\ + fc = to_rmi_function_container(dev);\ + data = fc->data;\ +\ + return snprintf(buf, PAGE_SIZE, fmt,\ + data->regtype.propname);\ +} + +#define show_union_struct(regtype, reg_group, propname, fmt)\ +static ssize_t tricat(rmi_fn_, FNUM, _##propname##_show)(\ + struct device *dev,\ + struct device_attribute *attr,\ + char *buf) {\ + struct rmi_function_container *fc;\ + struct FUNCTION_DATA *data;\ + int result;\ +\ + fc = to_rmi_function_container(dev);\ + data = fc->data;\ +\ + mutex_lock(&data->regtype##_mutex);\ + /* Read current regtype values */\ + result = rmi_read_block(fc->rmi_dev, data->regtype.reg_group->address,\ + (u8 *)data->regtype.reg_group,\ + sizeof(data->regtype.reg_group->regs));\ + mutex_unlock(&data->regtype##_mutex);\ + if (result < 0) {\ + dev_dbg(dev, "%s : Could not read regtype at 0x%x\\n",\ + __func__, data->regtype.reg_group->address);\ + return result;\ + }\ + return snprintf(buf, PAGE_SIZE, fmt,\ + data->regtype.reg_group->propname);\ +}\ + +#define show_store_union_struct(regtype, reg_group, propname, fmt)\ +show_union_struct(regtype, reg_group, propname, fmt)\ +\ +static ssize_t tricat(rmi_fn_, FNUM, _##propname##_store)(\ + struct device *dev,\ + struct device_attribute *attr,\ + const char *buf, size_t count) {\ + int result;\ + unsigned long val;\ + unsigned long old_val;\ + struct rmi_function_container *fc;\ + struct FUNCTION_DATA *data;\ +\ + fc = to_rmi_function_container(dev);\ + data = fc->data;\ +\ + /* need to convert the string data to an actual value */\ + result = strict_strtoul(buf, 10, &val);\ +\ + /* if an error occured, return it */\ + if (result)\ + return result;\ + /* Check value maybe */\ +\ + /* Read current regtype values */\ + mutex_lock(&data->regtype##_mutex);\ + result =\ + rmi_read_block(fc->rmi_dev, data->regtype.reg_group->address,\ + (u8 *)data->regtype.reg_group,\ + sizeof(data->regtype.reg_group->regs));\ +\ + if (result < 0) {\ + mutex_unlock(&data->regtype##_mutex);\ + dev_dbg(dev, "%s : Could not read regtype at 0x%x\\n",\ + __func__,\ + data->regtype.reg_group->address);\ + return result;\ + }\ + /* if the current regtype registers are already set as we want them,\ + * do nothing to them */\ + if (data->regtype.reg_group->propname == val) {\ + mutex_unlock(&data->regtype##_mutex);\ + return count;\ + }\ + /* Write the regtype back to the regtype register */\ + old_val = data->regtype.reg_group->propname;\ + data->regtype.reg_group->propname = val;\ + result =\ + rmi_write_block(fc->rmi_dev, data->regtype.reg_group->address,\ + (u8 *)data->regtype.reg_group,\ + sizeof(data->regtype.reg_group->regs));\ + if (result < 0) {\ + dev_dbg(dev, "%s : Could not write regtype to 0x%x\\n",\ + __func__,\ + data->regtype.reg_group->address);\ + /* revert change to local value if value not written */\ + data->regtype.reg_group->propname = old_val;\ + mutex_unlock(&data->regtype##_mutex);\ + return result;\ + }\ + mutex_unlock(&data->regtype##_mutex);\ + return count;\ +} + + +#define show_repeated_union_struct(regtype, reg_group, propname, fmt)\ +static ssize_t tricat(rmi_fn_, FNUM, _##propname##_show)(struct device *dev,\ + struct device_attribute *attr,\ + char *buf) {\ + struct rmi_function_container *fc;\ + struct FUNCTION_DATA *data;\ + int reg_length;\ + int result, size = 0;\ + char *temp;\ + int i;\ +\ + fc = to_rmi_function_container(dev);\ + data = fc->data;\ + mutex_lock(&data->regtype##_mutex);\ +\ + /* Read current regtype values */\ + reg_length = data->regtype.reg_group->length;\ + result = rmi_read_block(fc->rmi_dev, data->regtype.reg_group->address,\ + (u8*) data->regtype.reg_group->regs,\ + reg_length * sizeof(u8));\ + mutex_unlock(&data->regtype##_mutex);\ + if (result < 0) {\ + dev_dbg(dev, "%s : Could not read regtype at 0x%x\n"\ + "Data may be outdated.", __func__,\ + data->regtype.reg_group->address);\ + }\ + temp = buf;\ + for (i = 0; i < reg_length; i++) {\ + result = snprintf(temp, PAGE_SIZE - size, fmt " ",\ + data->regtype.reg_group->regs[i].propname);\ + if (result < 0) {\ + dev_err(dev, "%s : Could not write output.", __func__);\ + return result;\ + }\ + size += result;\ + temp += result;\ + }\ + result = snprintf(temp, PAGE_SIZE - size, "\n");\ + if (result < 0) {\ + dev_err(dev, "%s : Could not write output.", __func__);\ + return result;\ + }\ + return size + result;\ +} + +#define show_store_repeated_union_struct(regtype, reg_group, propname, fmt)\ +show_repeated_union_struct(regtype, reg_group, propname, fmt)\ +\ +static ssize_t tricat(rmi_fn_, FNUM, _##propname##_store)(struct device *dev,\ + struct device_attribute *attr,\ + const char *buf, size_t count) {\ + struct rmi_function_container *fc;\ + struct FUNCTION_DATA *data;\ + int reg_length;\ + int result;\ + const char *temp;\ + int i;\ + unsigned int newval;\ +\ + fc = to_rmi_function_container(dev);\ + data = fc->data;\ + mutex_lock(&data->regtype##_mutex);\ +\ + /* Read current regtype values */\ +\ + reg_length = data->regtype.reg_group->length;\ + result = rmi_read_block(fc->rmi_dev, data->regtype.reg_group->address,\ + (u8*) data->regtype.reg_group->regs,\ + reg_length * sizeof(u8));\ +\ + if (result < 0) {\ + dev_dbg(dev, "%s : Could not read regtype at 0x%x\n"\ + "Data may be outdated.", __func__,\ + data->regtype.reg_group->address);\ + }\ + /* parse input */\ + \ + temp = buf;\ + for (i = 0; i < reg_length; i++) {\ + if(sscanf(temp, fmt, &newval) == 1) {\ + data->regtype.reg_group->regs[i].propname = newval;\ + } else {\ + /* If we don't read a value for each position, abort, restore + * previous values locally by rereading */\ + result = rmi_read_block(fc->rmi_dev, data->regtype.reg_group->address,\ + (u8*) data->regtype.reg_group->regs,\ + reg_length * sizeof(u8));\ +\ + if (result < 0) {\ + dev_dbg(dev, "%s : Could not read regtype at 0x%x\n"\ + "Local data may be innacurrate.", __func__,\ + data->regtype.reg_group->address);\ + }\ + return -EINVAL;\ + }\ + /* move to next number */\ + while (*temp != 0) {\ + temp++;\ + if (isspace(*(temp - 1)) && !isspace(*temp))\ + break;\ + }\ + }\ + result = rmi_write_block(fc->rmi_dev, data->regtype.reg_group->address,\ + (u8*) data->regtype.reg_group->regs,\ + reg_length * sizeof(u8));\ + mutex_unlock(&data->regtype##_mutex);\ + if (result < 0) {\ + dev_dbg(dev, "%s : Could not write new values"\ + " to 0x%x\n", __func__, data->regtype.reg_group->address);\ + return result;\ + }\ + return count;\ +} + +/* Create templates for given types */ +#define simple_show_union_struct_unsigned(regtype, propname)\ +simple_show_union_struct(regtype, propname, "%u\n") + +#define show_union_struct_unsigned(regtype, reg_group, propname)\ +show_union_struct(regtype, reg_group, propname, "%u\n") + +#define show_store_union_struct_unsigned(regtype, reg_group, propname)\ +show_store_union_struct(regtype, reg_group, propname, "%u\n") + +#define show_repeated_union_struct_unsigned(regtype, reg_group, propname)\ +show_repeated_union_struct(regtype, reg_group, propname, "%u") + +#define show_store_repeated_union_struct_unsigned(regtype, reg_group, propname)\ +show_store_repeated_union_struct(regtype, reg_group, propname, "%u") + +/* Remove access to raw format string versions */ +/*#undef simple_show_union_struct +#undef show_union_struct_unsigned +#undef show_store_union_struct +#undef show_repeated_union_struct +#undef show_store_repeated_union_struct*/ + +#endif + +#define GROUP(_attrs) { \ + .attrs = _attrs, \ +} + +#define attrify(nm) &dev_attr_##nm.attr + +union f01_device_status { + struct { + u8 status_code:4; + u8 reserved:2; + u8 flash_prog:1; + u8 unconfigured:1; + }; + u8 reg; +}; + +struct rmi_driver_data { + struct rmi_function_container rmi_functions; + + struct rmi_function_container *f01_container; + bool f01_bootloader_mode; + + int num_of_irq_regs; + int irq_count; + u8 *current_irq_mask; + u8 *irq_mask_store; + bool irq_stored; + struct mutex irq_mutex; + struct mutex pdt_mutex; + + unsigned char pdt_props; + unsigned char bsr; + bool enabled; + +#ifdef CONFIG_PM + bool suspended; + struct mutex suspend_mutex; + + void *pm_data; + int (*pre_suspend) (const void *pm_data); + int (*post_resume) (const void *pm_data); +#endif + +#ifdef CONFIG_RMI4_DEBUG +#ifdef CONFIG_RMI4_SPI + struct dentry *debugfs_delay; +#endif + struct dentry *debugfs_phys; + struct dentry *debugfs_reg_ctl; + struct dentry *debugfs_reg; + u16 reg_debug_addr; + u8 reg_debug_size; +#endif + + void *data; +}; + +struct pdt_entry { + u8 query_base_addr:8; + u8 command_base_addr:8; + u8 control_base_addr:8; + u8 data_base_addr:8; + u8 interrupt_source_count:3; + u8 bits3and4:2; + u8 function_version:2; + u8 bit7:1; + u8 function_number:8; +}; + +int rmi_driver_f01_init(struct rmi_device *rmi_dev); + +static inline void copy_pdt_entry_to_fd(struct pdt_entry *pdt, + struct rmi_function_descriptor *fd, + u16 page_start) +{ + fd->query_base_addr = pdt->query_base_addr + page_start; + fd->command_base_addr = pdt->command_base_addr + page_start; + fd->control_base_addr = pdt->control_base_addr + page_start; + fd->data_base_addr = pdt->data_base_addr + page_start; + fd->function_number = pdt->function_number; + fd->interrupt_source_count = pdt->interrupt_source_count; + fd->function_version = pdt->function_version; +} + +#endif + diff --git a/drivers/input/touchscreen/rmi4/rmi_f01.c b/drivers/input/touchscreen/rmi4/rmi_f01.c new file mode 100755 index 000000000000..1516ab74a4c2 --- /dev/null +++ b/drivers/input/touchscreen/rmi4/rmi_f01.c @@ -0,0 +1,1389 @@ +/* + * Copyright (c) 2011-2012 Synaptics Incorporated + * Copyright (c) 2011 Unixphere + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include "rmi_driver.h" + +/* control register bits */ +#define RMI_SLEEP_MODE_NORMAL (0x00) +#define RMI_SLEEP_MODE_SENSOR_SLEEP (0x01) +#define RMI_SLEEP_MODE_RESERVED0 (0x02) +#define RMI_SLEEP_MODE_RESERVED1 (0x03) + +#define RMI_IS_VALID_SLEEPMODE(mode) \ + (mode >= RMI_SLEEP_MODE_NORMAL && mode <= RMI_SLEEP_MODE_RESERVED1) + +union f01_device_commands { + struct { + u8 reset:1; + u8 reserved:1; + }; + u8 reg; +}; + +struct f01_device_control_0 { + union { + struct { + u8 sleep_mode:2; + u8 nosleep:1; + u8 reserved:2; + u8 charger_input:1; + u8 report_rate:1; + u8 configured:1; + }; + u8 reg; + }; +}; + +struct f01_device_control { + struct f01_device_control_0 ctrl0; + u8 *interrupt_enable; + u8 doze_interval; + u8 wakeup_threshold; + u8 doze_holdoff; +}; + +union f01_basic_queries { + struct { + u8 manufacturer_id:8; + + u8 custom_map:1; + u8 non_compliant:1; + u8 has_lts:1; + u8 has_sensor_id:1; + u8 has_charger_input:1; + u8 has_adjustable_doze:1; + u8 has_adjustable_doze_holdoff:1; + u8 has_product_properties_2:1; + + u8 productinfo_1:7; + u8 q2_bit_7:1; + u8 productinfo_2:7; + u8 q3_bit_7:1; + + u8 year:5; + u8 month:4; + u8 day:5; + u8 cp1:1; + u8 cp2:1; + u8 wafer_id1_lsb:8; + u8 wafer_id1_msb:8; + u8 wafer_id2_lsb:8; + u8 wafer_id2_msb:8; + u8 wafer_id3_lsb:8; + }; + u8 regs[11]; +}; + +union f01_query_42 { + struct { + u8 has_ds4_queries:1; + u8 has_multi_phy:1; + u8 has_guest:1; + u8 reserved:5; + }; + u8 regs[1]; +}; + +union f01_ds4_queries { + struct { + u8 length:4; + u8 reserved_1:4; + + u8 has_package_id_query:1; + u8 has_packrat_query:1; + u8 has_reset_query:1; + u8 has_maskrev_query:1; + u8 reserved_2:4; + + u8 has_i2c_control:1; + u8 has_spi_control:1; + u8 has_attn_control:1; + u8 reserved_3:5; + + u8 reset_enabled:1; + u8 reset_polarity:1; + u8 pullup_enabled:1; + u8 reserved_4:1; + u8 reset_pin_number:4; + }; + u8 regs[4]; +}; + +struct f01_data { + struct f01_device_control device_control; + union f01_basic_queries basic_queries; + union f01_device_status device_status; + u8 product_id[RMI_PRODUCT_ID_LENGTH+1]; + + u8 interrupt_enable_addr; + u8 doze_interval_addr; + u8 wakeup_threshold_addr; + u8 doze_holdoff_addr; + + int irq_count; + int num_of_irq_regs; + +#ifdef CONFIG_PM + bool suspended; + bool old_nosleep; +#endif +}; + + +static ssize_t rmi_fn_01_productinfo_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_01_productid_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_01_manufacturer_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_01_datecode_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_01_reportrate_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_01_reportrate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t rmi_fn_01_interrupt_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_01_interrupt_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t rmi_fn_01_doze_interval_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_01_doze_interval_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t rmi_fn_01_wakeup_threshold_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_01_wakeup_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t rmi_fn_01_doze_holdoff_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_01_doze_holdoff_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t rmi_fn_01_reset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t rmi_fn_01_sleepmode_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_01_sleepmode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t rmi_fn_01_nosleep_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_01_nosleep_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t rmi_fn_01_chargerinput_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_01_chargerinput_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t rmi_fn_01_configured_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_01_unconfigured_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_01_flashprog_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_01_statuscode_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static int rmi_f01_alloc_memory(struct rmi_function_container *fc, + int num_of_irq_regs); + +static void rmi_f01_free_memory(struct rmi_function_container *fc); + +static int rmi_f01_initialize(struct rmi_function_container *fc); + +static int rmi_f01_create_sysfs(struct rmi_function_container *fc); + +static int rmi_f01_config(struct rmi_function_container *fc); + +static int rmi_f01_reset(struct rmi_function_container *fc); + + +static struct device_attribute fn_01_attrs[] = { + __ATTR(productinfo, RMI_RO_ATTR, + rmi_fn_01_productinfo_show, rmi_store_error), + __ATTR(productid, RMI_RO_ATTR, + rmi_fn_01_productid_show, rmi_store_error), + __ATTR(manufacturer, RMI_RO_ATTR, + rmi_fn_01_manufacturer_show, rmi_store_error), + __ATTR(datecode, RMI_RO_ATTR, + rmi_fn_01_datecode_show, rmi_store_error), + + /* control register access */ + __ATTR(sleepmode, RMI_RW_ATTR, + rmi_fn_01_sleepmode_show, rmi_fn_01_sleepmode_store), + __ATTR(nosleep, RMI_RW_ATTR, + rmi_fn_01_nosleep_show, rmi_fn_01_nosleep_store), + __ATTR(chargerinput, RMI_RW_ATTR, + rmi_fn_01_chargerinput_show, rmi_fn_01_chargerinput_store), + __ATTR(reportrate, RMI_RW_ATTR, + rmi_fn_01_reportrate_show, rmi_fn_01_reportrate_store), + __ATTR(interrupt_enable, RMI_RW_ATTR, + rmi_fn_01_interrupt_enable_show, + rmi_fn_01_interrupt_enable_store), + __ATTR(doze_interval, RMI_RW_ATTR, + rmi_fn_01_doze_interval_show, + rmi_fn_01_doze_interval_store), + __ATTR(wakeup_threshold, RMI_RW_ATTR, + rmi_fn_01_wakeup_threshold_show, + rmi_fn_01_wakeup_threshold_store), + __ATTR(doze_holdoff, RMI_RW_ATTR, + rmi_fn_01_doze_holdoff_show, + rmi_fn_01_doze_holdoff_store), + + /* We make report rate RO, since the driver uses that to look for + * resets. We don't want someone faking us out by changing that + * bit. + */ + __ATTR(configured, RMI_RO_ATTR, + rmi_fn_01_configured_show, rmi_store_error), + + /* Command register access. */ + __ATTR(reset, RMI_WO_ATTR, + rmi_show_error, rmi_fn_01_reset_store), + + /* STatus register access. */ + __ATTR(unconfigured, RMI_RO_ATTR, + rmi_fn_01_unconfigured_show, rmi_store_error), + __ATTR(flashprog, RMI_RO_ATTR, + rmi_fn_01_flashprog_show, rmi_store_error), + __ATTR(statuscode, RMI_RO_ATTR, + rmi_fn_01_statuscode_show, rmi_store_error), +}; + +/* Utility routine to set the value of a bit field in a register. */ +int rmi_set_bit_field(struct rmi_device *rmi_dev, + unsigned short address, + unsigned char field_mask, + unsigned char bits) +{ + unsigned char reg_contents; + int retval; + + retval = rmi_read(rmi_dev, address, ®_contents); + if (retval) + return retval; + reg_contents = (reg_contents & ~field_mask) | bits; + retval = rmi_write(rmi_dev, address, reg_contents); + if (retval == 1) + return 0; + else if (retval == 0) + return -EIO; + return retval; +} + +static ssize_t rmi_fn_01_productinfo_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct f01_data *data = NULL; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "0x%02x 0x%02x\n", + data->basic_queries.productinfo_1, + data->basic_queries.productinfo_2); +} + +static ssize_t rmi_fn_01_productid_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct f01_data *data = NULL; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%s\n", data->product_id); +} + +static ssize_t rmi_fn_01_manufacturer_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct f01_data *data = NULL; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "0x%02x\n", + data->basic_queries.manufacturer_id); +} + +static ssize_t rmi_fn_01_datecode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct f01_data *data = NULL; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "20%02u-%02u-%02u\n", + data->basic_queries.year, + data->basic_queries.month, + data->basic_queries.day); +} + +static ssize_t rmi_fn_01_reset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc = NULL; + unsigned int reset; + int retval = 0; + /* Command register always reads as 0, so we can just use a local. */ + union f01_device_commands commands = {}; + + fc = to_rmi_function_container(dev); + + if (sscanf(buf, "%u", &reset) != 1) + return -EINVAL; + if (reset < 0 || reset > 1) + return -EINVAL; + + /* Per spec, 0 has no effect, so we skip it entirely. */ + if (reset) { + commands.reset = 1; + retval = rmi_write_block(fc->rmi_dev, fc->fd.command_base_addr, + &commands.reg, sizeof(commands.reg)); + if (retval < 0) { + dev_err(dev, "%s: failed to issue reset command, " + "error = %d.", __func__, retval); + return retval; + } + } + + return count; +} + +static ssize_t rmi_fn_01_sleepmode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct f01_data *data = NULL; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + return snprintf(buf, PAGE_SIZE, + "%d\n", data->device_control.ctrl0.sleep_mode); +} + +static ssize_t rmi_fn_01_sleepmode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct f01_data *data = NULL; + unsigned long new_value; + int retval; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + retval = strict_strtoul(buf, 10, &new_value); + if (retval < 0 || !RMI_IS_VALID_SLEEPMODE(new_value)) { + dev_err(dev, "%s: Invalid sleep mode %s.", __func__, buf); + return -EINVAL; + } + + dev_dbg(dev, "Setting sleep mode to %ld.", new_value); + data->device_control.ctrl0.sleep_mode = new_value; + retval = rmi_write_block(fc->rmi_dev, fc->fd.control_base_addr, + &data->device_control.ctrl0.reg, + sizeof(data->device_control.ctrl0.reg)); + if (retval >= 0) + retval = count; + else + dev_err(dev, "Failed to write sleep mode, code %d.\n", retval); + return retval; +} + +static ssize_t rmi_fn_01_nosleep_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct f01_data *data = NULL; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%d\n", + data->device_control.ctrl0.nosleep); +} + +static ssize_t rmi_fn_01_nosleep_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct f01_data *data = NULL; + unsigned long new_value; + int retval; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + retval = strict_strtoul(buf, 10, &new_value); + if (retval < 0 || new_value < 0 || new_value > 1) { + dev_err(dev, "%s: Invalid nosleep bit %s.", __func__, buf); + return -EINVAL; + } + + data->device_control.ctrl0.nosleep = new_value; + retval = rmi_write_block(fc->rmi_dev, fc->fd.control_base_addr, + &data->device_control.ctrl0.reg, + sizeof(data->device_control.ctrl0.reg)); + if (retval >= 0) + retval = count; + else + dev_err(dev, "Failed to write nosleep bit.\n"); + return retval; +} + +static ssize_t rmi_fn_01_chargerinput_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct f01_data *data = NULL; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%d\n", + data->device_control.ctrl0.charger_input); +} + +static ssize_t rmi_fn_01_chargerinput_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct f01_data *data = NULL; + unsigned long new_value; + int retval; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + retval = strict_strtoul(buf, 10, &new_value); + if (retval < 0 || new_value < 0 || new_value > 1) { + dev_err(dev, "%s: Invalid chargerinput bit %s.", __func__, buf); + return -EINVAL; + } + + data->device_control.ctrl0.charger_input = new_value; + retval = rmi_write_block(fc->rmi_dev, fc->fd.control_base_addr, + &data->device_control.ctrl0.reg, + sizeof(data->device_control.ctrl0.reg)); + if (retval >= 0) + retval = count; + else + dev_err(dev, "Failed to write chargerinput bit.\n"); + return retval; +} + +static ssize_t rmi_fn_01_reportrate_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct f01_data *data = NULL; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%d\n", + data->device_control.ctrl0.report_rate); +} + +static ssize_t rmi_fn_01_reportrate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct f01_data *data = NULL; + unsigned long new_value; + int retval; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + retval = strict_strtoul(buf, 10, &new_value); + if (retval < 0 || new_value < 0 || new_value > 1) { + dev_err(dev, "%s: Invalid reportrate bit %s.", __func__, buf); + return -EINVAL; + } + + data->device_control.ctrl0.report_rate = new_value; + retval = rmi_write_block(fc->rmi_dev, fc->fd.control_base_addr, + &data->device_control.ctrl0.reg, + sizeof(data->device_control.ctrl0.reg)); + if (retval >= 0) + retval = count; + else + dev_err(dev, "Failed to write reportrate bit.\n"); + return retval; +} + +static ssize_t rmi_fn_01_interrupt_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f01_data *data; + int i, len, total_len = 0; + char *current_buf = buf; + + fc = to_rmi_function_container(dev); + data = fc->data; + /* loop through each irq value and copy its + * string representation into buf */ + for (i = 0; i < data->irq_count; i++) { + int irq_reg; + int irq_shift; + int interrupt_enable; + + irq_reg = i / 8; + irq_shift = i % 8; + interrupt_enable = + ((data->device_control.interrupt_enable[irq_reg] + >> irq_shift) & 0x01); + + /* get next irq value and write it to buf */ + len = snprintf(current_buf, PAGE_SIZE - total_len, + "%u ", interrupt_enable); + /* bump up ptr to next location in buf if the + * snprintf was valid. Otherwise issue an error + * and return. */ + if (len > 0) { + current_buf += len; + total_len += len; + } else { + dev_err(dev, "%s: Failed to build interrupt_enable" + " buffer, code = %d.\n", __func__, len); + return snprintf(buf, PAGE_SIZE, "unknown\n"); + } + } + len = snprintf(current_buf, PAGE_SIZE - total_len, "\n"); + if (len > 0) + total_len += len; + else + dev_warn(dev, "%s: Failed to append carriage return.\n", + __func__); + return total_len; + +} + +static ssize_t rmi_fn_01_interrupt_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct f01_data *data; + int i; + int irq_count = 0; + int retval = count; + int irq_reg = 0; + + fc = to_rmi_function_container(dev); + data = fc->data; + for (i = 0; i < data->irq_count && *buf != 0; + i++, buf += 2) { + int irq_shift; + int interrupt_enable; + int result; + + irq_reg = i / 8; + irq_shift = i % 8; + + /* get next interrupt mapping value and store and bump up to + * point to next item in buf */ + result = sscanf(buf, "%u", &interrupt_enable); + if ((result != 1) || + (interrupt_enable != 0 && interrupt_enable != 1)) { + dev_err(dev, + "%s: Error - interrupt enable[%d]" + " is not a valid value 0x%x.\n", + __func__, i, interrupt_enable); + return -EINVAL; + } + if (interrupt_enable == 0) { + data->device_control.interrupt_enable[irq_reg] &= + (1 << irq_shift) ^ 0xFF; + } else + data->device_control.interrupt_enable[irq_reg] |= + (1 << irq_shift); + irq_count++; + } + + /* Make sure the irq count matches */ + if (irq_count != data->irq_count) { + dev_err(dev, + "%s: Error - interrupt enable count of %d" + " doesn't match device count of %d.\n", + __func__, irq_count, data->irq_count); + return -EINVAL; + } + + /* write back to the control register */ + retval = rmi_write_block(fc->rmi_dev, data->interrupt_enable_addr, + data->device_control.interrupt_enable, + sizeof(u8)*(data->num_of_irq_regs)); + if (retval < 0) { + dev_err(dev, "%s : Could not write interrupt_enable_store" + " to 0x%x\n", __func__, data->interrupt_enable_addr); + return retval; + } + + return count; + +} + +static ssize_t rmi_fn_01_doze_interval_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct f01_data *data = NULL; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%d\n", + data->device_control.doze_interval); + +} + +static ssize_t rmi_fn_01_doze_interval_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct f01_data *data = NULL; + unsigned long new_value; + int retval; + int ctrl_base_addr; + + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + retval = strict_strtoul(buf, 10, &new_value); + if (retval < 0 || new_value < 0 || new_value > 255) { + dev_err(dev, "%s: Invalid doze interval %s.", __func__, buf); + return -EINVAL; + } + + data->device_control.doze_interval = new_value; + ctrl_base_addr = fc->fd.control_base_addr + sizeof(u8) + + (sizeof(u8)*(data->num_of_irq_regs)); + dev_info(dev, "doze_interval store address %x, value %d", + ctrl_base_addr, data->device_control.doze_interval); + + retval = rmi_write_block(fc->rmi_dev, data->doze_interval_addr, + &data->device_control.doze_interval, + sizeof(u8)); + if (retval >= 0) + retval = count; + else + dev_err(dev, "Failed to write doze interval.\n"); + return retval; + +} + +static ssize_t rmi_fn_01_wakeup_threshold_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct f01_data *data = NULL; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%d\n", + data->device_control.wakeup_threshold); +} + +static ssize_t rmi_fn_01_wakeup_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct f01_data *data = NULL; + unsigned long new_value; + int retval; + + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + retval = strict_strtoul(buf, 10, &new_value); + if (retval < 0 || new_value < 0 || new_value > 255) { + dev_err(dev, "%s: Invalid wakeup threshold %s.", __func__, buf); + return -EINVAL; + } + + data->device_control.doze_interval = new_value; + retval = rmi_write_block(fc->rmi_dev, data->wakeup_threshold_addr, + &data->device_control.wakeup_threshold, + sizeof(u8)); + if (retval >= 0) + retval = count; + else + dev_err(dev, "Failed to write wakeup threshold.\n"); + return retval; + +} + +static ssize_t rmi_fn_01_doze_holdoff_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct f01_data *data = NULL; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%d\n", + data->device_control.doze_holdoff); + +} + + +static ssize_t rmi_fn_01_doze_holdoff_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct f01_data *data = NULL; + unsigned long new_value; + int retval; + + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + retval = strict_strtoul(buf, 10, &new_value); + if (retval < 0 || new_value < 0 || new_value > 255) { + dev_err(dev, "%s: Invalid doze holdoff %s.", __func__, buf); + return -EINVAL; + } + + data->device_control.doze_interval = new_value; + retval = rmi_write_block(fc->rmi_dev, data->doze_holdoff_addr, + &data->device_control.doze_holdoff, + sizeof(u8)); + if (retval >= 0) + retval = count; + else + dev_err(dev, "Failed to write doze holdoff.\n"); + return retval; + +} + +static ssize_t rmi_fn_01_configured_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct f01_data *data = NULL; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%d\n", + data->device_control.ctrl0.configured); +} + +static ssize_t rmi_fn_01_unconfigured_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct f01_data *data = NULL; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%d\n", + data->device_status.unconfigured); +} + +static ssize_t rmi_fn_01_flashprog_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct f01_data *data = NULL; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%d\n", + data->device_status.flash_prog); +} + +static ssize_t rmi_fn_01_statuscode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct f01_data *data = NULL; + struct rmi_function_container *fc = to_rmi_function_container(dev); + + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "0x%02x\n", + data->device_status.status_code); +} + +/* why is this not done in init? */ +int rmi_driver_f01_init(struct rmi_device *rmi_dev) +{ + struct rmi_driver_data *driver_data = rmi_get_driverdata(rmi_dev); + struct rmi_function_container *fc = driver_data->f01_container; + int error; + + error = rmi_f01_alloc_memory(fc, driver_data->num_of_irq_regs); + if (error < 0) + goto error_exit; + + error = rmi_f01_initialize(fc); + if (error < 0) + goto error_exit; + + error = rmi_f01_create_sysfs(fc); + if (error < 0) + goto error_exit; + + return 0; + + error_exit: + rmi_f01_free_memory(fc); + + return error; +} + +static int rmi_f01_alloc_memory(struct rmi_function_container *fc, + int num_of_irq_regs) +{ + struct f01_data *f01; + + f01 = kzalloc(sizeof(struct f01_data), GFP_KERNEL); + if (!f01) { + dev_err(&fc->dev, "Failed to allocate fn_01_data.\n"); + return -ENOMEM; + } + + f01->device_control.interrupt_enable = + kzalloc(sizeof(u8)*(num_of_irq_regs), GFP_KERNEL); + if (!f01->device_control.interrupt_enable) { + kfree(f01); + return -ENOMEM; + } + fc->data = f01; + + return 0; +} + +static void rmi_f01_free_memory(struct rmi_function_container *fc) +{ + struct f01_data *f01 = fc->data; + kfree(f01->device_control.interrupt_enable); + kfree(fc->data); + fc->data = NULL; +} + +static int rmi_f01_initialize(struct rmi_function_container *fc) +{ + u8 temp; + int retval; + int ctrl_base_addr; + struct rmi_device *rmi_dev = fc->rmi_dev; + struct rmi_driver_data *driver_data = rmi_get_driverdata(rmi_dev); + struct f01_data *data = fc->data; + struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev); + + /* Set the configured bit and (optionally) other important stuff + * in the device control register. */ + ctrl_base_addr = fc->fd.control_base_addr; + retval = rmi_read_block(rmi_dev, fc->fd.control_base_addr, + &data->device_control.ctrl0.reg, + sizeof(data->device_control.ctrl0.reg)); + if (retval < 0) { + dev_err(&fc->dev, "Failed to read F01 control.\n"); + return retval; + } + switch (pdata->power_management.nosleep) { + case RMI_F01_NOSLEEP_DEFAULT: + break; + case RMI_F01_NOSLEEP_OFF: + data->device_control.ctrl0.nosleep = 0; + break; + case RMI_F01_NOSLEEP_ON: + data->device_control.ctrl0.nosleep = 1; + break; + } + /* Sleep mode might be set as a hangover from a system crash or + * reboot without power cycle. If so, clear it so the sensor + * is certain to function. + */ + if (data->device_control.ctrl0.sleep_mode != RMI_SLEEP_MODE_NORMAL) { + dev_warn(&fc->dev, + "WARNING: Non-zero sleep mode found. Clearing...\n"); + data->device_control.ctrl0.sleep_mode = RMI_SLEEP_MODE_NORMAL; + } + + data->device_control.ctrl0.configured = 1; + retval = rmi_write_block(rmi_dev, fc->fd.control_base_addr, + &data->device_control.ctrl0.reg, + sizeof(data->device_control.ctrl0.reg)); + if (retval < 0) { + dev_err(&fc->dev, "Failed to write F01 control.\n"); + return retval; + } + + data->irq_count = driver_data->irq_count; + data->num_of_irq_regs = driver_data->num_of_irq_regs; + ctrl_base_addr += sizeof(struct f01_device_control_0); + + data->interrupt_enable_addr = ctrl_base_addr; + retval = rmi_read_block(rmi_dev, ctrl_base_addr, + data->device_control.interrupt_enable, + sizeof(u8) * (driver_data->num_of_irq_regs)); + if (retval < 0) { + dev_err(&fc->dev, "Failed to read F01 control interrupt enable register.\n"); + goto error_exit; + } + ctrl_base_addr += (sizeof(u8) * (driver_data->num_of_irq_regs)); + + /* dummy read in order to clear irqs */ + retval = rmi_read(rmi_dev, fc->fd.data_base_addr + 1, &temp); + if (retval < 0) { + dev_err(&fc->dev, "Failed to read Interrupt Status.\n"); + return retval; + } + + retval = rmi_read_block(rmi_dev, fc->fd.query_base_addr, + data->basic_queries.regs, + sizeof(data->basic_queries.regs)); + + if (retval < 0) { + dev_err(&fc->dev, "Failed to read device query registers.\n"); + return retval; + } + + retval = rmi_read_block(rmi_dev, + fc->fd.query_base_addr + sizeof(data->basic_queries.regs), + data->product_id, RMI_PRODUCT_ID_LENGTH); + if (retval < 0) { + dev_err(&fc->dev, "Failed to read product ID.\n"); + return retval; + } + data->product_id[RMI_PRODUCT_ID_LENGTH] = '\0'; + dev_info(&fc->dev, "found RMI device, manufacturer: %s, product: %s\n", + data->basic_queries.manufacturer_id == 1 ? + "synaptics" : "unknown", + data->product_id); + + /* read control register */ + if (data->basic_queries.has_adjustable_doze) { + data->doze_interval_addr = ctrl_base_addr; + ctrl_base_addr++; + + if (pdata->power_management.doze_interval) { + data->device_control.doze_interval = + pdata->power_management.doze_interval; + retval = rmi_write(rmi_dev, data->doze_interval_addr, + data->device_control.doze_interval); + if (retval < 0) { + dev_err(&fc->dev, "Failed to configure F01 doze interval register.\n"); + goto error_exit; + } + } else { + retval = rmi_read(rmi_dev, data->doze_interval_addr, + &data->device_control.doze_interval); + if (retval < 0) { + dev_err(&fc->dev, "Failed to read F01 doze interval register.\n"); + goto error_exit; + } + } + + data->wakeup_threshold_addr = ctrl_base_addr; + ctrl_base_addr++; + + if (pdata->power_management.wakeup_threshold) { + data->device_control.wakeup_threshold = + pdata->power_management.wakeup_threshold; + retval = rmi_write(rmi_dev, data->wakeup_threshold_addr, + data->device_control.wakeup_threshold); + if (retval < 0) { + dev_err(&fc->dev, "Failed to configure F01 wakeup threshold register.\n"); + goto error_exit; + } + } else { + retval = rmi_read(rmi_dev, data->wakeup_threshold_addr, + &data->device_control.wakeup_threshold); + if (retval < 0) { + dev_err(&fc->dev, "Failed to read F01 wakeup threshold register.\n"); + goto error_exit; + } + } + } + + if (data->basic_queries.has_adjustable_doze_holdoff) { + data->doze_holdoff_addr = ctrl_base_addr; + ctrl_base_addr++; + + if (pdata->power_management.doze_holdoff) { + data->device_control.doze_holdoff = + pdata->power_management.doze_holdoff; + retval = rmi_write(rmi_dev, data->doze_holdoff_addr, + data->device_control.doze_holdoff); + if (retval < 0) { + dev_err(&fc->dev, "Failed to configure F01 " + "doze holdoff register.\n"); + goto error_exit; + } + } else { + retval = rmi_read(rmi_dev, data->doze_holdoff_addr, + &data->device_control.doze_holdoff); + if (retval < 0) { + dev_err(&fc->dev, "Failed to read F01 doze" + " holdoff register.\n"); + goto error_exit; + } + } + } + + retval = rmi_read_block(rmi_dev, fc->fd.data_base_addr, + &data->device_status.reg, + sizeof(data->device_status.reg)); + if (retval < 0) { + dev_err(&fc->dev, "Failed to read device status.\n"); + goto error_exit; + } + + if (data->device_status.unconfigured) { + dev_err(&fc->dev, + "Device reset during configuration process, status: " + "%#02x!\n", data->device_status.status_code); + retval = -EINVAL; + goto error_exit; + } + + return retval; + + error_exit: + kfree(data); + return retval; +} + +static int rmi_f01_create_sysfs(struct rmi_function_container *fc) +{ + int attr_count = 0; + int retval = 0; + struct f01_data *data = fc->data; + + dev_dbg(&fc->dev, "Creating sysfs files."); + for (attr_count = 0; attr_count < ARRAY_SIZE(fn_01_attrs); + attr_count++) { + if (!strcmp("doze_interval", fn_01_attrs[attr_count].attr.name) + && !data->basic_queries.has_lts) { + continue; + } + if (!strcmp("wakeup_threshold", + fn_01_attrs[attr_count].attr.name) + && !data->basic_queries.has_adjustable_doze) { + continue; + } + if (!strcmp("doze_holdoff", fn_01_attrs[attr_count].attr.name) + && !data->basic_queries.has_adjustable_doze_holdoff) { + continue; + } + retval = sysfs_create_file(&fc->dev.kobj, + &fn_01_attrs[attr_count].attr); + if (retval < 0) { + dev_err(&fc->dev, "Failed to create sysfs file for %s.", + fn_01_attrs[attr_count].attr.name); + goto err_remove_sysfs; + } + } + + return 0; + +err_remove_sysfs: + for (attr_count--; attr_count >= 0; attr_count--) + sysfs_remove_file(&fc->dev.kobj, + &fn_01_attrs[attr_count].attr); + + return retval; +} + +static int rmi_f01_config(struct rmi_function_container *fc) +{ + struct f01_data *data = fc->data; + int retval; + + retval = rmi_write_block(fc->rmi_dev, fc->fd.control_base_addr, + (u8 *)&data->device_control.ctrl0, + sizeof(struct f01_device_control_0)); + if (retval < 0) { + dev_err(&fc->dev, "Failed to write device_control.reg.\n"); + return retval; + } + + retval = rmi_write_block(fc->rmi_dev, data->interrupt_enable_addr, + data->device_control.interrupt_enable, + sizeof(u8)*(data->num_of_irq_regs)); + + if (retval < 0) { + dev_err(&fc->dev, "Failed to write interrupt enable.\n"); + return retval; + } + if (data->basic_queries.has_lts) { + retval = rmi_write_block(fc->rmi_dev, data->doze_interval_addr, + &data->device_control.doze_interval, + sizeof(u8)); + if (retval < 0) { + dev_err(&fc->dev, "Failed to write doze interval.\n"); + return retval; + } + } + + if (data->basic_queries.has_adjustable_doze) { + retval = rmi_write_block( + fc->rmi_dev, data->wakeup_threshold_addr, + &data->device_control.wakeup_threshold, + sizeof(u8)); + if (retval < 0) { + dev_err(&fc->dev, "Failed to write wakeup threshold.\n"); + return retval; + } + } + + if (data->basic_queries.has_adjustable_doze_holdoff) { + retval = rmi_write_block(fc->rmi_dev, data->doze_holdoff_addr, + &data->device_control.doze_holdoff, + sizeof(u8)); + if (retval < 0) { + dev_err(&fc->dev, "Failed to write doze holdoff.\n"); + return retval; + } + } + return 0; +} + +static int rmi_f01_reset(struct rmi_function_container *fc) +{ + /*do nothing here */ + return 0; +} + + +#ifdef CONFIG_PM +static int rmi_f01_suspend(struct rmi_function_container *fc) +{ + struct rmi_device *rmi_dev = fc->rmi_dev; + struct rmi_driver_data *driver_data = rmi_get_driverdata(rmi_dev); + struct f01_data *data = driver_data->f01_container->data; + int retval = 0; + + dev_info(&fc->dev, "Suspending...\n"); + if (data->suspended) + return 0; + + data->old_nosleep = data->device_control.ctrl0.nosleep; + data->device_control.ctrl0.nosleep = 0; + data->device_control.ctrl0.sleep_mode = RMI_SLEEP_MODE_SENSOR_SLEEP; + printk("++sleep_mode:%x\n", data->device_control.ctrl0.reg); + retval = rmi_write_block(rmi_dev, + driver_data->f01_container->fd.control_base_addr, + (u8 *)&data->device_control.ctrl0, + sizeof(struct f01_device_control_0)); + if (retval < 0) { + dev_err(&fc->dev, "Failed to write sleep mode. Code: %d.\n", + retval); + data->device_control.ctrl0.nosleep = data->old_nosleep; + data->device_control.ctrl0.sleep_mode = RMI_SLEEP_MODE_NORMAL; + } else { + data->suspended = true; + retval = 0; + } + + return retval; +} + +static int rmi_f01_resume(struct rmi_function_container *fc) +{ + struct rmi_device *rmi_dev = fc->rmi_dev; + struct rmi_driver_data *driver_data = rmi_get_driverdata(rmi_dev); + struct f01_data *data = driver_data->f01_container->data; + int retval = 0; + + dev_info(&fc->dev, "Resuming...\n"); + if (!data->suspended) + return 0; + + data->device_control.ctrl0.nosleep = data->old_nosleep; + data->device_control.ctrl0.sleep_mode = RMI_SLEEP_MODE_NORMAL; + printk("++sleep_mode:%x\n", data->device_control.ctrl0.reg); + retval = rmi_write_block(rmi_dev, + driver_data->f01_container->fd.control_base_addr, + (u8 *)&data->device_control.ctrl0, + sizeof(struct f01_device_control_0)); + if (retval < 0) + dev_err(&fc->dev, + "Failed to restore normal operation. Code: %d.\n", + retval); + else { + data->suspended = false; + retval = 0; + } + + return retval; +} +#endif /* CONFIG_PM */ + +static int rmi_f01_init(struct rmi_function_container *fc) +{ + return 0; +} + +static void rmi_f01_remove(struct rmi_function_container *fc) +{ + int attr_count; + + for (attr_count = 0; attr_count < ARRAY_SIZE(fn_01_attrs); + attr_count++) { + sysfs_remove_file(&fc->dev.kobj, &fn_01_attrs[attr_count].attr); + } + + rmi_f01_free_memory(fc); +} + +static int rmi_f01_attention(struct rmi_function_container *fc, u8 *irq_bits) +{ + struct rmi_device *rmi_dev = fc->rmi_dev; + struct f01_data *data = fc->data; + int retval; + + retval = rmi_read_block(rmi_dev, fc->fd.data_base_addr, + &data->device_status.reg, + sizeof(data->device_status.reg)); + if (retval < 0) { + dev_err(&fc->dev, "Failed to read device status, code: %d.\n", + retval); + return retval; + } + if (data->device_status.unconfigured) { + dev_warn(&fc->dev, "Device reset detected.\n"); + retval = rmi_dev->driver->reset_handler(rmi_dev); + if (retval < 0) + return retval; + } + return 0; +} + +static struct rmi_function_handler function_handler = { + .func = 0x01, + .init = rmi_f01_init, + .config = rmi_f01_config, + .reset = rmi_f01_reset, + .attention = rmi_f01_attention, +#ifdef CONFIG_PM + +#ifdef CONFIG_HAS_EARLYSUSPEND + .early_suspend = rmi_f01_suspend, + .late_resume = rmi_f01_resume, +#else + .suspend = rmi_f01_suspend, + .resume = rmi_f01_resume, +#endif /* CONFIG_HAS_EARLYSUSPEND */ +#endif /* CONFIG_PM */ + .remove = rmi_f01_remove, +}; + +static int __init rmi_f01_module_init(void) +{ + int error; + + error = rmi_register_function_driver(&function_handler); + if (error < 0) { + pr_err("%s: register failed!\n", __func__); + return error; + } + + return 0; +} + +static void __exit rmi_f01_module_exit(void) +{ + rmi_unregister_function_driver(&function_handler); +} + +module_init(rmi_f01_module_init); +module_exit(rmi_f01_module_exit); + +MODULE_AUTHOR("Christopher Heiny "); +MODULE_DESCRIPTION("RMI F01 module"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(RMI_DRIVER_VERSION); diff --git a/drivers/input/touchscreen/rmi4/rmi_f09.c b/drivers/input/touchscreen/rmi4/rmi_f09.c new file mode 100755 index 000000000000..e71f4720b568 --- /dev/null +++ b/drivers/input/touchscreen/rmi4/rmi_f09.c @@ -0,0 +1,771 @@ +/* + * Copyright (c) 2011 Synaptics Incorporated + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include "rmi_driver.h" +#define QUERY_BASE_INDEX 1 + +/* data specific to fn $09 that needs to be kept around */ +struct f09_query { + u8 limit_register_count; + union { + struct { + u8 result_register_count:3; + u8 reserved:3; + u8 internal_limits:1; + u8 host_test_enable:1; + }; + u8 f09_bist_query1; + }; +}; + +struct f09_control { + union { + struct { + u8 test1_limit_low:8; + u8 test1_limit_high:8; + u8 test1_limit_diff:8; + }; + u8 f09_control_test1[3]; + }; + union { + struct { + u8 test2_limit_low:8; + u8 test2_limit_high:8; + u8 test2_limit_diff:8; + }; + u8 f09_control_test2[3]; + }; +}; + +struct f09_data { + u8 test_number_control; + u8 overall_bist_result; + u8 test_result1; + u8 test_result2; + u8 transmitter_number; + + union { + struct { + u8 receiver_number:6; + u8 limit_failure_code:2; + }; + u8 f09_bist_data2; + }; +}; + +struct f09_cmd { + union { + struct { + u8 run_bist:1; + }; + u8 f09_bist_cmd0; + }; +}; + +struct rmi_fn_09_data { + struct f09_query query; + struct f09_data data; + struct f09_cmd cmd; + struct f09_control control; + signed char status; +}; + + +static ssize_t rmi_f09_status_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t rmi_f09_status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t rmi_f09_limit_register_count_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t rmi_f09_host_test_enable_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t rmi_f09_host_test_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t rmi_f09_internal_limits_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t rmi_f09_result_register_count_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t rmi_f09_overall_bist_result_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t rmi_f09_test_number_control_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t rmi_f09_test_number_control_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t rmi_f09_run_bist_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t rmi_f09_run_bist_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t rmi_f09_test_result1_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t rmi_f09_test_result2_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t rmi_f09_control_test1_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t rmi_f09_control_test1_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t rmi_f09_control_test2_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t rmi_f09_control_test2_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static int rmi_f09_alloc_memory(struct rmi_function_container *fc); + +static void rmi_f09_free_memory(struct rmi_function_container *fc); + +static int rmi_f09_initialize(struct rmi_function_container *fc); + +static int rmi_f09_config(struct rmi_function_container *fc); + +static int rmi_f09_reset(struct rmi_function_container *fc); + +static int rmi_f09_create_sysfs(struct rmi_function_container *fc); + + +static struct device_attribute attrs[] = { + __ATTR(status, RMI_RW_ATTR, + rmi_f09_status_show, rmi_f09_status_store), + __ATTR(limitRegisterCount, RMI_RO_ATTR, + rmi_f09_limit_register_count_show, rmi_store_error), + __ATTR(hostTestEnable, RMI_RW_ATTR, + rmi_f09_host_test_enable_show, rmi_f09_host_test_enable_store), + __ATTR(internalLimits, RMI_RO_ATTR, + rmi_f09_internal_limits_show, rmi_store_error), + __ATTR(resultRegisterCount, RMI_RO_ATTR, + rmi_f09_result_register_count_show, rmi_store_error), + __ATTR(overall_bist_result, RMI_RO_ATTR, + rmi_f09_overall_bist_result_show, rmi_store_error), + __ATTR(test_number_control, RMI_RW_ATTR, + rmi_f09_test_number_control_show, + rmi_f09_test_number_control_store), + __ATTR(test_result1, RMI_RO_ATTR, + rmi_f09_test_result1_show, rmi_store_error), + __ATTR(test_result2, RMI_RO_ATTR, + rmi_f09_test_result2_show, rmi_store_error), + __ATTR(run_bist, RMI_RW_ATTR, + rmi_f09_run_bist_show, rmi_f09_run_bist_store), + __ATTR(f09_control_test1, RMI_RW_ATTR, + rmi_f09_control_test1_show, rmi_f09_control_test1_store), + __ATTR(f09_control_test2, RMI_RW_ATTR, + rmi_f09_control_test2_show, rmi_f09_control_test2_store), +}; + +static int rmi_f09_init(struct rmi_function_container *fc) +{ + int rc; + + dev_info(&fc->dev, "Intializing F09 values."); + + rc = rmi_f09_alloc_memory(fc); + if (rc < 0) + goto error_exit; + + rc = rmi_f09_initialize(fc); + if (rc < 0) + goto error_exit; + + rc = rmi_f09_create_sysfs(fc); + if (rc < 0) + goto error_exit; + + return 0; + +error_exit: + rmi_f09_free_memory(fc); + + return rc; +} + +static int rmi_f09_alloc_memory(struct rmi_function_container *fc) +{ + struct rmi_fn_09_data *f09; + + f09 = kzalloc(sizeof(struct rmi_fn_09_data), GFP_KERNEL); + if (!f09) { + dev_err(&fc->dev, "Failed to allocate rmi_fn_09_data.\n"); + return -ENOMEM; + } + fc->data = f09; + + return 0; +} + +static void rmi_f09_free_memory(struct rmi_function_container *fc) +{ + kfree(fc->data); + fc->data = NULL; +} + +static int rmi_f09_initialize(struct rmi_function_container *fc) +{ + struct rmi_device *rmi_dev = fc->rmi_dev; + struct rmi_device_platform_data *pdata; + struct rmi_fn_09_data *f09 = fc->data; + u8 query_base_addr; + int rc; + + + pdata = to_rmi_platform_data(rmi_dev); + query_base_addr = fc->fd.query_base_addr; + + /* initial all default values for f09 query here */ + rc = rmi_read_block(rmi_dev, query_base_addr, + (u8 *)&f09->query, sizeof(f09->query)); + if (rc < 0) { + dev_err(&fc->dev, "Failed to read query register." + " from 0x%04x\n", query_base_addr); + return rc; + } + + return 0; +} + +static int rmi_f09_create_sysfs(struct rmi_function_container *fc) +{ + int attr_count = 0; + int rc; + + dev_dbg(&fc->dev, "Creating sysfs files."); + /* Set up sysfs device attributes. */ + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { + if (sysfs_create_file + (&fc->dev.kobj, &attrs[attr_count].attr) < 0) { + dev_err(&fc->dev, "Failed to create sysfs file for %s.", + attrs[attr_count].attr.name); + rc = -ENODEV; + goto err_remove_sysfs; + } + } + + return 0; + +err_remove_sysfs: + for (attr_count--; attr_count >= 0; attr_count--) + sysfs_remove_file(&fc->dev.kobj, + &attrs[attr_count].attr); + + return rc; +} + +static int rmi_f09_config(struct rmi_function_container *fc) +{ + /*we do nothing here. instead reset should notify the user.*/ + return 0; +} + +static int rmi_f09_reset(struct rmi_function_container *fc) +{ + struct rmi_fn_09_data *instance_data = fc->data; + + instance_data->status = -ECONNRESET; + + return 0; +} + +static void rmi_f09_remove(struct rmi_function_container *fc) +{ + int attr_count; + + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) + sysfs_remove_file(&fc->dev.kobj, + &attrs[attr_count].attr); + + rmi_f09_free_memory(fc); +} + +static int rmi_f09_attention(struct rmi_function_container *fc, u8 *irq_bits) +{ + struct rmi_device *rmi_dev = fc->rmi_dev; + struct rmi_fn_09_data *data = fc->data; + int error; + error = rmi_read_block(rmi_dev, fc->fd.command_base_addr, + (u8 *)&data->cmd, sizeof(data->cmd)); + + if (error < 0) { + dev_err(&fc->dev, "Failed to read command register.\n"); + return error; + } + /* If the command register is cleared, meaning the value is 0 */ + if (data->status == ECONNRESET) { + dev_warn(&rmi_dev->dev, "RESET occured: %#04x.\n", + data->status); + } else if (data->cmd.run_bist) { + dev_warn(&rmi_dev->dev, + "Command register not cleared: %#04x.\n", + data->cmd.run_bist); + } + return 0; +} + +static struct rmi_function_handler function_handler = { + .func = 0x09, + .init = rmi_f09_init, + .attention = rmi_f09_attention, + .config = rmi_f09_config, + .reset = rmi_f09_reset, + .remove = rmi_f09_remove +}; + +static int __init rmi_f09_module_init(void) +{ + int error; + + error = rmi_register_function_driver(&function_handler); + if (error < 0) { + pr_err("%s: register failed!\n", __func__); + return error; + } + + return 0; +} + +static void rmi_f09_module_exit(void) +{ + rmi_unregister_function_driver(&function_handler); +} + +static ssize_t rmi_f09_status_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_09_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%d\n", instance_data->status); +} + +static ssize_t rmi_f09_status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct rmi_fn_09_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + /* any write to status resets 1 */ + instance_data->status = 0; + + return 0; +} + +static ssize_t rmi_f09_limit_register_count_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_09_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->query.limit_register_count); +} + +static ssize_t rmi_f09_host_test_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_09_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->query.host_test_enable); +} + +static ssize_t rmi_f09_host_test_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct rmi_fn_09_data *data; + unsigned int new_value; + int result; + + fc = to_rmi_function_container(dev); + data = fc->data; + if (sscanf(buf, "%u", &new_value) != 1) { + dev_err(dev, + "%s: Error - hostTestEnable has an invalid length.\n", + __func__); + return -EINVAL; + } + + if (new_value < 0 || new_value > 1) { + dev_err(dev, "%s: Invalid hostTestEnable bit %s.", + __func__, buf); + return -EINVAL; + } + data->query.host_test_enable = new_value; + result = rmi_write(fc->rmi_dev, fc->fd.query_base_addr, + data->query.host_test_enable); + if (result < 0) { + dev_err(dev, "%s: Could not write hostTestEnable to 0x%x\n", + __func__, fc->fd.query_base_addr); + return result; + } + + return count; + +} + +static ssize_t rmi_f09_internal_limits_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_09_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->query.internal_limits); +} + +static ssize_t rmi_f09_result_register_count_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_09_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->query.result_register_count); +} + +static ssize_t rmi_f09_overall_bist_result_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_09_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->data.overall_bist_result); +} + +static ssize_t rmi_f09_test_result1_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_09_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->data.test_result1); +} + +static ssize_t rmi_f09_test_result2_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_09_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->data.test_result2); +} + +static ssize_t rmi_f09_run_bist_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_09_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->cmd.run_bist); +} + +static ssize_t rmi_f09_run_bist_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct rmi_fn_09_data *data; + unsigned int new_value; + int result; + + fc = to_rmi_function_container(dev); + data = fc->data; + if (sscanf(buf, "%u", &new_value) != 1) { + dev_err(dev, + "%s: Error - run_bist_store has an " + "invalid len.\n", + __func__); + return -EINVAL; + } + + if (new_value < 0 || new_value > 1) { + dev_err(dev, "%s: Invalid run_bist bit %s.", __func__, buf); + return -EINVAL; + } + data->cmd.run_bist = new_value; + result = rmi_write(fc->rmi_dev, fc->fd.command_base_addr, + data->cmd.run_bist); + if (result < 0) { + dev_err(dev, "%s : Could not write run_bist_store to 0x%x\n", + __func__, fc->fd.command_base_addr); + return result; + } + + return count; + +} + +static ssize_t rmi_f09_control_test1_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_09_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u %u %u\n", + data->control.test1_limit_low, + data->control.test1_limit_high, + data->control.test1_limit_diff); +} + +static ssize_t rmi_f09_control_test1_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct rmi_fn_09_data *data; + unsigned int new_low, new_high, new_diff; + int result; + + fc = to_rmi_function_container(dev); + data = fc->data; + if (sscanf(buf, "%u %u %u", &new_low, &new_high, &new_diff) != 3) { + dev_err(dev, + "%s: Error - f09_control_test1_store has an " + "invalid len.\n", + __func__); + return -EINVAL; + } + + if (new_low < 0 || new_low > 1 || new_high < 0 || new_high + || new_diff < 0 || new_diff) { + dev_err(dev, "%s: Invalid f09_control_test1_diff bit %s.", + __func__, buf); + return -EINVAL; + } + data->control.test1_limit_low = new_low; + data->control.test1_limit_high = new_high; + data->control.test1_limit_diff = new_diff; + result = rmi_write(fc->rmi_dev, fc->fd.control_base_addr, + data->control.test1_limit_low); + if (result < 0) { + dev_err(dev, "%s : Could not write f09_control_test1_limit_low to 0x%x\n", + __func__, fc->fd.control_base_addr); + return result; + } + + result = rmi_write(fc->rmi_dev, fc->fd.control_base_addr, + data->control.test1_limit_high); + if (result < 0) { + dev_err(dev, "%s : Could not write f09_control_test1_limit_high to 0x%x\n", + __func__, fc->fd.control_base_addr); + return result; + } + + result = rmi_write(fc->rmi_dev, fc->fd.control_base_addr, + data->control.test1_limit_diff); + if (result < 0) { + dev_err(dev, "%s : Could not write f09_control_test1_limit_diff to 0x%x\n", + __func__, fc->fd.control_base_addr); + return result; + } + + return count; + +} + +static ssize_t rmi_f09_control_test2_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_09_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u %u %u\n", + data->control.test2_limit_low, + data->control.test2_limit_high, + data->control.test2_limit_diff); +} + +static ssize_t rmi_f09_control_test2_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct rmi_fn_09_data *data; + unsigned int new_low, new_high, new_diff; + int result; + + fc = to_rmi_function_container(dev); + data = fc->data; + if (sscanf(buf, "%u %u %u", &new_low, &new_high, &new_diff) != 3) { + dev_err(dev, + "%s: Error - f09_control_test1_store has an " + "invalid len.\n", + __func__); + return -EINVAL; + } + + if (new_low < 0 || new_low > 1 || new_high < 0 || new_high > 1 || + new_diff < 0 || new_diff > 1) { + dev_err(dev, "%s: Invalid f09_control_test2_diff bit %s.", + __func__, buf); + return -EINVAL; + } + data->control.test2_limit_low = new_low; + data->control.test2_limit_high = new_high; + data->control.test2_limit_diff = new_diff; + result = rmi_write(fc->rmi_dev, fc->fd.control_base_addr, + data->control.test2_limit_low); + if (result < 0) { + dev_err(dev, "%s : Could not write f09_control_test2_limit_low to 0x%x\n", + __func__, fc->fd.control_base_addr); + return result; + } + + result = rmi_write(fc->rmi_dev, fc->fd.control_base_addr, + data->control.test2_limit_high); + if (result < 0) { + dev_err(dev, "%s : Could not write f09_control_test2_limit_high to 0x%x\n", + __func__, fc->fd.control_base_addr); + return result; + } + + result = rmi_write(fc->rmi_dev, fc->fd.control_base_addr, + data->control.test2_limit_diff); + if (result < 0) { + dev_err(dev, "%s : Could not write f09_control_test2_limit_diff to 0x%x\n", + __func__, fc->fd.control_base_addr); + return result; + } + + return count; + +} + + +static ssize_t rmi_f09_test_number_control_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_09_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->data.test_number_control); +} + +static ssize_t rmi_f09_test_number_control_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct rmi_fn_09_data *data; + unsigned int new_value; + int result; + + fc = to_rmi_function_container(dev); + data = fc->data; + if (sscanf(buf, "%u", &new_value) != 1) { + dev_err(dev, + "%s: Error - test_number_control_store has an " + "invalid len.\n", + __func__); + return -EINVAL; + } + + if (new_value < 0 || new_value > 1) { + dev_err(dev, "%s: Invalid test_number_control bit %s.", + __func__, buf); + return -EINVAL; + } + data->data.test_number_control = new_value; + result = rmi_write(fc->rmi_dev, fc->fd.control_base_addr, + data->data.test_number_control); + if (result < 0) { + dev_err(dev, "%s : Could not write " + "test_number_control_store to 0x%x\n", + __func__, fc->fd.data_base_addr); + return result; + } + + return count; +} + +module_init(rmi_f09_module_init); +module_exit(rmi_f09_module_exit); + +MODULE_AUTHOR("Allie Xiong "); +MODULE_DESCRIPTION("RMI F09 module"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(RMI_DRIVER_VERSION); diff --git a/drivers/input/touchscreen/rmi4/rmi_f11.c b/drivers/input/touchscreen/rmi4/rmi_f11.c new file mode 100755 index 000000000000..e94b570a1cba --- /dev/null +++ b/drivers/input/touchscreen/rmi4/rmi_f11.c @@ -0,0 +1,1947 @@ +/* + * Copyright (c) 2011 Synaptics Incorporated + * Copyright (c) 2011 Unixphere + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include "rmi_driver.h" +#define RESUME_REZERO (1 && defined(CONFIG_PM)) +#if RESUME_REZERO +#include +#define DEFAULT_REZERO_WAIT_MS 40 +#endif + +#ifndef MT_TOOL_MAX +#define MT_TOOL_MAX MT_TOOL_PEN +#endif + +#define F11_MAX_NUM_OF_SENSORS 8 +#define F11_MAX_NUM_OF_FINGERS 10 +#define F11_MAX_NUM_OF_TOUCH_SHAPES 16 + +#define F11_REL_POS_MIN -128 +#define F11_REL_POS_MAX 127 + +#define FINGER_STATE_MASK 0x03 +#define GET_FINGER_STATE(f_states, i) \ + ((f_states[i / 4] >> (2 * (i % 4))) & FINGER_STATE_MASK) + +#define F11_CTRL_SENSOR_MAX_X_POS_OFFSET 6 +#define F11_CTRL_SENSOR_MAX_Y_POS_OFFSET 8 + +#define F11_CEIL(x, y) (((x) + ((y)-1)) / (y)) +#define INBOX(x, y, box) (x >= box.x && x < (box.x + box.width) \ + && y >= box.y && y < (box.y + box.height)) + +#define DEFAULT_XY_MAX 9999 +#define DEFAULT_MAX_ABS_MT_PRESSURE 255 +#define DEFAULT_MAX_ABS_MT_TOUCH 15 +#define DEFAULT_MAX_ABS_MT_ORIENTATION 1 +#define DEFAULT_MIN_ABS_MT_TRACKING_ID 1 +#define DEFAULT_MAX_ABS_MT_TRACKING_ID 10 +#define MAX_NAME_LENGTH 256 + +#define SYNAPTICS_MAX_POINTS (10) +static ssize_t f11_flip_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t f11_flip_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t f11_clip_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t f11_clip_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t f11_offset_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t f11_offset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t f11_swap_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t f11_swap_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t f11_relreport_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t f11_relreport_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t f11_maxPos_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t f11_rezero_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +#if RESUME_REZERO +static ssize_t f11_rezeroOnResume_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t f11_rezeroOnResume_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t f11_rezeroWait_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t f11_rezeroWait_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +#endif + + +static void rmi_f11_free_memory(struct rmi_function_container *fc); + +static int rmi_f11_initialize(struct rmi_function_container *fc); + +static int rmi_f11_create_sysfs(struct rmi_function_container *fc); + +static int rmi_f11_config(struct rmi_function_container *fc); + +static int rmi_f11_reset(struct rmi_function_container *fc); + +static int rmi_f11_register_devices(struct rmi_function_container *fc); + +static void rmi_f11_free_devices(struct rmi_function_container *fc); + + +static struct device_attribute attrs[] = { + __ATTR(flip, RMI_RW_ATTR, f11_flip_show, f11_flip_store), + __ATTR(clip, RMI_RW_ATTR, f11_clip_show, f11_clip_store), + __ATTR(offset, RMI_RW_ATTR, f11_offset_show, f11_offset_store), + __ATTR(swap, RMI_RW_ATTR, f11_swap_show, f11_swap_store), + __ATTR(relreport, RMI_RW_ATTR, f11_relreport_show, f11_relreport_store), + __ATTR(maxPos, RMI_RO_ATTR, f11_maxPos_show, rmi_store_error), +#if RESUME_REZERO + __ATTR(rezeroOnResume, RMI_RW_ATTR, f11_rezeroOnResume_show, + f11_rezeroOnResume_store), + __ATTR(rezeroWait, RMI_RW_ATTR, f11_rezeroWait_show, + f11_rezeroWait_store), +#endif + __ATTR(rezero, RMI_WO_ATTR, rmi_show_error, f11_rezero_store) +}; + + +union f11_2d_commands { + struct { + u8 rezero:1; + }; + u8 reg; +}; + +struct f11_2d_device_query { + union { + struct { + u8 nbr_of_sensors:3; + u8 has_query9:1; + u8 has_query11:1; + }; + u8 f11_2d_query0; + }; + + union { + struct { + u8 has_z_tuning:1; + u8 has_pos_interpolation_tuning:1; + u8 has_w_tuning:1; + u8 has_pitch_info:1; + u8 has_default_finger_width:1; + u8 has_segmentation_aggressiveness:1; + u8 has_tx_rw_clip:1; + u8 has_drumming_correction:1; + }; + u8 f11_2d_query11; + }; +}; + +union f11_2d_query9 { + struct { + u8 has_pen:1; + u8 has_proximity:1; + u8 has_palm_det_sensitivity:1; + u8 has_suppress_on_palm_detect:1; + u8 has_two_pen_thresholds:1; + u8 has_contact_geometry:1; + }; + u8 reg; +}; + +struct f11_2d_sensor_query { + union { + struct { + /* query1 */ + u8 number_of_fingers:3; + u8 has_rel:1; + u8 has_abs:1; + u8 has_gestures:1; + u8 has_sensitivity_adjust:1; + u8 configurable:1; + /* query2 */ + u8 num_of_x_electrodes:7; + /* query3 */ + u8 num_of_y_electrodes:7; + /* query4 */ + u8 max_electrodes:7; + }; + u8 f11_2d_query1__4[4]; + }; + + union { + struct { + u8 abs_data_size:3; + u8 has_anchored_finger:1; + u8 has_adj_hyst:1; + u8 has_dribble:1; + }; + u8 f11_2d_query5; + }; + + u8 f11_2d_query6; + + union { + struct { + u8 has_single_tap:1; + u8 has_tap_n_hold:1; + u8 has_double_tap:1; + u8 has_early_tap:1; + u8 has_flick:1; + u8 has_press:1; + u8 has_pinch:1; + u8 padding:1; + + u8 has_palm_det:1; + u8 has_rotate:1; + u8 has_touch_shapes:1; + u8 has_scroll_zones:1; + u8 has_individual_scroll_zones:1; + u8 has_multi_finger_scroll:1; + }; + u8 f11_2d_query7__8[2]; + }; + + union f11_2d_query9 query9; + + union { + struct { + u8 nbr_touch_shapes:5; + }; + u8 f11_2d_query10; + }; +}; + +union f11_2d_ctrl10 { + struct { + u8 single_tap_int_enable:1; + u8 tap_n_hold_int_enable:1; + u8 double_tap_int_enable:1; + u8 early_tap_int_enable:1; + u8 flick_int_enable:1; + u8 press_int_enable:1; + u8 pinch_int_enable:1; + }; + u8 reg; +}; + +union f11_2d_ctrl11 { + struct { + u8 palm_detect_int_enable:1; + u8 rotate_int_enable:1; + u8 touch_shape_int_enable:1; + u8 scroll_zone_int_enable:1; + u8 multi_finger_scroll_int_enable:1; + }; + u8 reg; +}; + +union f11_2d_ctrl12 { + struct { + u8 sensor_map:7; + u8 xy_sel:1; + }; + u8 reg; +}; + +union f11_2d_ctrl14 { + struct { + u8 sens_adjustment:5; + u8 hyst_adjustment:3; + }; + u8 reg; +}; + +union f11_2d_ctrl15 { + struct { + u8 max_tap_time:8; + }; + u8 reg; +}; + +union f11_2d_ctrl16 { + struct { + u8 min_press_time:8; + }; + u8 reg; +}; + +union f11_2d_ctrl17 { + struct { + u8 max_tap_distance:8; + }; + u8 reg; +}; + +union f11_2d_ctrl18_19 { + struct { + u8 min_flick_distance:8; + u8 min_flick_speed:8; + }; + u8 reg[2]; +}; + +union f11_2d_ctrl20_21 { + struct { + u8 pen_detect_enable:1; + u8 pen_jitter_filter_enable:1; + u8 ctrl20_reserved:6; + u8 pen_z_threshold:8; + }; + u8 reg[2]; +}; + +struct f11_2d_ctrl { + + union { + struct { + /* F11_2D_Ctrl0 */ + u8 reporting_mode:3; + u8 abs_pos_filt:1; + u8 rel_pos_filt:1; + u8 rel_ballistics:1; + u8 dribble:1; + u8 report_beyond_clip:1; + /* F11_2D_Ctrl1 */ + u8 palm_detect_thres:4; + u8 motion_sensitivity:2; + u8 man_track_en:1; + u8 man_tracked_finger:1; + /* F11_2D_Ctrl2 and 3 */ + u8 delta_x_threshold:8; + u8 delta_y_threshold:8; + /* F11_2D_Ctrl4 and 5 */ + u8 velocity:8; + u8 acceleration:8; + /* F11_2D_Ctrl6 thru 9 */ + u16 sensor_max_x_pos:12; + u8 ctrl7_reserved:4; + u16 sensor_max_y_pos:12; + u8 ctrl9_reserved:4; + }; + u8 ctrl0_9[10]; + }; + + union f11_2d_ctrl10 *ctrl10; + union f11_2d_ctrl11 *ctrl11; + union f11_2d_ctrl12 *ctrl12; + u8 ctrl12_size; + union f11_2d_ctrl14 *ctrl14; + union f11_2d_ctrl15 *ctrl15; + union f11_2d_ctrl16 *ctrl16; + union f11_2d_ctrl17 *ctrl17; + union f11_2d_ctrl18_19 *ctrl18_19; + union f11_2d_ctrl20_21 *ctrl20_21; +}; + +struct f11_2d_data_1_5 { + u8 x_msb; + u8 y_msb; + u8 x_lsb:4; + u8 y_lsb:4; + u8 w_y:4; + u8 w_x:4; + u8 z; +}; + +struct f11_2d_data_6_7 { + s8 delta_x; + s8 delta_y; +}; + +struct f11_2d_data_8 { + u8 single_tap:1; + u8 tap_and_hold:1; + u8 double_tap:1; + u8 early_tap:1; + u8 flick:1; + u8 press:1; + u8 pinch:1; +}; + +struct f11_2d_data_9 { + u8 palm_detect:1; + u8 rotate:1; + u8 shape:1; + u8 scrollzone:1; + u8 finger_count:3; +}; + +struct f11_2d_data_10 { + u8 pinch_motion; +}; + +struct f11_2d_data_10_12 { + u8 x_flick_dist; + u8 y_flick_dist; + u8 flick_time; +}; + +struct f11_2d_data_11_12 { + u8 motion; + u8 finger_separation; +}; + +struct f11_2d_data_13 { + u8 shape_n; +}; + +struct f11_2d_data_14_15 { + u8 horizontal; + u8 vertical; +}; + +struct f11_2d_data_14_17 { + u8 x_low; + u8 y_right; + u8 x_upper; + u8 y_left; +}; + +struct f11_2d_data { + u8 *f_state; + const struct f11_2d_data_1_5 *abs_pos; + const struct f11_2d_data_6_7 *rel_pos; + const struct f11_2d_data_8 *gest_1; + const struct f11_2d_data_9 *gest_2; + const struct f11_2d_data_10 *pinch; + const struct f11_2d_data_10_12 *flick; + const struct f11_2d_data_11_12 *rotate; + const struct f11_2d_data_13 *shapes; + const struct f11_2d_data_14_15 *multi_scroll; + const struct f11_2d_data_14_17 *scroll_zones; +}; + +struct f11_2d_sensor { + struct rmi_f11_2d_axis_alignment axis_align; + struct f11_2d_sensor_query sens_query; + struct f11_2d_data data; + u16 max_x; + u16 max_y; + u8 nbr_fingers; + u8 finger_tracker[F11_MAX_NUM_OF_FINGERS]; + u8 *data_pkt; + int pkt_size; + u8 sensor_index; + struct rmi_f11_virtualbutton_map virtualbutton_map; + char input_name[MAX_NAME_LENGTH]; + char input_phys[MAX_NAME_LENGTH]; + struct input_dev *input; + struct input_dev *mouse_input; +}; + +struct f11_data { + struct f11_2d_device_query dev_query; + struct f11_2d_ctrl dev_controls; +#if RESUME_REZERO + u16 rezero_wait_ms; + bool rezero_on_resume; +#endif + struct f11_2d_sensor sensors[F11_MAX_NUM_OF_SENSORS]; +}; + +enum finger_state_values { + F11_NO_FINGER = 0x00, + F11_PRESENT = 0x01, + F11_INACCURATE = 0x02, + F11_RESERVED = 0x03 +}; + +/** F11_INACCURATE state is overloaded to indicate pen present. */ +#define F11_PEN F11_INACCURATE + +static int get_tool_type(struct f11_2d_sensor *sensor, u8 finger_state) { + if (sensor->sens_query.query9.has_pen && finger_state == F11_PEN) + return MT_TOOL_PEN; + return MT_TOOL_FINGER; +} + +static void rmi_f11_rel_pos_report(struct f11_2d_sensor *sensor, u8 n_finger) +{ + struct f11_2d_data *data = &sensor->data; + struct rmi_f11_2d_axis_alignment *axis_align = &sensor->axis_align; + s8 x, y; + s8 temp; + + x = data->rel_pos[n_finger].delta_x; + y = data->rel_pos[n_finger].delta_y; + + x = min(F11_REL_POS_MAX, max(F11_REL_POS_MIN, (int)x)); + y = min(F11_REL_POS_MAX, max(F11_REL_POS_MIN, (int)y)); + + if (axis_align->swap_axes) { + temp = x; + x = y; + y = temp; + } + if (axis_align->flip_x) + x = min(F11_REL_POS_MAX, -x); + if (axis_align->flip_y) + y = min(F11_REL_POS_MAX, -y); + + if (x || y) { + input_report_rel(sensor->input, REL_X, x); + input_report_rel(sensor->input, REL_Y, y); + input_report_rel(sensor->mouse_input, REL_X, x); + input_report_rel(sensor->mouse_input, REL_Y, y); + } + input_sync(sensor->mouse_input); +} + +static void rmi_f11_abs_pos_report(struct f11_2d_sensor *sensor, + u8 finger_state, u8 n_finger) +{ + struct f11_2d_data *data = &sensor->data; + struct rmi_f11_2d_axis_alignment *axis_align = &sensor->axis_align; + int prev_state = sensor->finger_tracker[n_finger]; + int x, y, z; + int w_x, w_y, w_max, w_min, orient; + int temp; + + if (prev_state && !finger_state) { + /* this is a release */ + x = y = z = w_max = w_min = orient = 0; + input_mt_slot(sensor->input, n_finger); + input_mt_report_slot_state(sensor->input, MT_TOOL_FINGER, false); + input_report_abs(sensor->input, ABS_MT_TRACKING_ID, -1); + } else if (!prev_state && !finger_state) { + /* nothing to report */ + return; + } else { + x = ((data->abs_pos[n_finger].x_msb << 4) | + data->abs_pos[n_finger].x_lsb); + y = ((data->abs_pos[n_finger].y_msb << 4) | + data->abs_pos[n_finger].y_lsb); + z = data->abs_pos[n_finger].z; + w_x = data->abs_pos[n_finger].w_x; + w_y = data->abs_pos[n_finger].w_y; + w_max = max(w_x, w_y); + w_min = min(w_x, w_y); + if (axis_align->swap_axes) { + temp = x; + x = y; + y = temp; + temp = w_x; + w_x = w_y; + w_y = temp; + } + + orient = w_x > w_y ? 1 : 0; + + if (axis_align->flip_x) + x = max(sensor->max_x - x, 0); + + if (axis_align->flip_y) + y = max(sensor->max_y - y, 0); + //printk("+x:%d, y:%d\n", x , y); + /* + ** here checking if X offset or y offset are specified is + ** redundant. We just add the offsets or, clip the values + ** + ** note: offsets need to be done before clipping occurs, + ** or we could get funny values that are outside + ** clipping boundaries. + */ + x += axis_align->offset_X; + y += axis_align->offset_Y; + x = max(axis_align->clip_X_low, x); + y = max(axis_align->clip_Y_low, y); + if (axis_align->clip_X_high) + x = min(axis_align->clip_X_high, x); + if (axis_align->clip_Y_high) + y = min(axis_align->clip_Y_high, y); + + pr_debug("%s: f_state[%d]:%d - x:%d y:%d z:%d w_max:%d w_min:%d\n", + __func__, n_finger, finger_state, x, y, z, w_max, w_min); +#ifndef CONFIG_RMI4_F11_PEN + /* Some UIs ignore W of zero, so we fudge it to 1 for pens. */ + if (sensor->sens_query.query9.has_pen && + get_tool_type(sensor, finger_state) == MT_TOOL_PEN) { + w_max = max(1, w_max); + w_min = max(1, w_min); + } +#endif + + input_mt_slot(sensor->input, n_finger); + input_mt_report_slot_state(sensor->input, MT_TOOL_FINGER, true); + input_report_abs(sensor->input, ABS_MT_TRACKING_ID, n_finger); + input_report_abs(sensor->input, ABS_MT_TOUCH_MAJOR, w_max); + input_report_abs(sensor->input, ABS_MT_PRESSURE, z); + input_report_abs(sensor->input, ABS_MT_TOUCH_MINOR, w_min); + input_report_abs(sensor->input, ABS_MT_ORIENTATION, orient); + input_report_abs(sensor->input, ABS_MT_POSITION_X, x); + input_report_abs(sensor->input, ABS_MT_POSITION_Y, y); + +#ifdef CONFIG_RMI4_F11_PEN + if (sensor->sens_query.query9.has_pen) { + input_report_abs(sensor->input, ABS_MT_TOOL_TYPE, + get_tool_type(sensor, finger_state)); + } +#endif + + } + sensor->finger_tracker[n_finger] = finger_state; +} + +#ifdef CONFIG_RMI4_VIRTUAL_BUTTON +static int rmi_f11_virtual_button_handler(struct f11_2d_sensor *sensor) +{ + int i; + int x; + int y; + struct rmi_f11_virtualbutton_map *virtualbutton_map; + if (sensor->sens_query.has_gestures && + sensor->data.gest_1->single_tap) { + virtualbutton_map = &sensor->virtualbutton_map; + x = ((sensor->data.abs_pos[0].x_msb << 4) | + sensor->data.abs_pos[0].x_lsb); + y = ((sensor->data.abs_pos[0].y_msb << 4) | + sensor->data.abs_pos[0].y_lsb); + for (i = 0; i < virtualbutton_map->buttons; i++) { + if (INBOX(x, y, virtualbutton_map->map[i])) { + input_report_key(sensor->input, + virtualbutton_map->map[i].code, 1); + input_report_key(sensor->input, + virtualbutton_map->map[i].code, 0); + input_sync(sensor->input); + return 0; + } + } + } + return 0; +} +#else +#define rmi_f11_virtual_button_handler(sensor) +#endif + +static void rmi_f11_finger_handler(struct f11_2d_sensor *sensor) +{ + const u8 *f_state = sensor->data.f_state; + u8 finger_state; + u8 finger_pressed_count; + u8 i; + + for (i = 0, finger_pressed_count = 0; i < sensor->nbr_fingers; i++) { + /* Possible of having 4 fingers per f_statet register */ + finger_state = GET_FINGER_STATE(f_state, i); + + if (finger_state == F11_RESERVED) { + pr_err("%s: Invalid finger state[%d]:0x%02x.", __func__, + i, finger_state); + continue; + } else if ((finger_state == F11_PRESENT) || + (finger_state == F11_INACCURATE)) { + finger_pressed_count++; + } + + if (sensor->data.abs_pos) + rmi_f11_abs_pos_report(sensor, finger_state, i); + + if (sensor->data.rel_pos) + rmi_f11_rel_pos_report(sensor, i); + } + input_report_key(sensor->input, BTN_TOUCH, finger_pressed_count); + input_sync(sensor->input); +} + +static int f11_2d_construct_data(struct f11_2d_sensor *sensor) +{ + struct f11_2d_sensor_query *query = &sensor->sens_query; + struct f11_2d_data *data = &sensor->data; + int i; + + sensor->nbr_fingers = (query->number_of_fingers == 5 ? 10 : + query->number_of_fingers + 1); + + sensor->pkt_size = F11_CEIL(sensor->nbr_fingers, 4); + + if (query->has_abs) + sensor->pkt_size += (sensor->nbr_fingers * 5); + + if (query->has_rel) + sensor->pkt_size += (sensor->nbr_fingers * 2); + + /* Check if F11_2D_Query7 is non-zero */ + if (query->f11_2d_query7__8[0]) + sensor->pkt_size += sizeof(u8); + + /* Check if F11_2D_Query7 or F11_2D_Query8 is non-zero */ + if (query->f11_2d_query7__8[0] || query->f11_2d_query7__8[1]) + sensor->pkt_size += sizeof(u8); + + if (query->has_pinch || query->has_flick || query->has_rotate) { + sensor->pkt_size += 3; + if (!query->has_flick) + sensor->pkt_size--; + if (!query->has_rotate) + sensor->pkt_size--; + } + + if (query->has_touch_shapes) + sensor->pkt_size += F11_CEIL(query->nbr_touch_shapes + 1, 8); + + sensor->data_pkt = kzalloc(sensor->pkt_size, GFP_KERNEL); + if (!sensor->data_pkt) + return -ENOMEM; + + data->f_state = sensor->data_pkt; + i = F11_CEIL(sensor->nbr_fingers, 4); + + if (query->has_abs) { + data->abs_pos = (struct f11_2d_data_1_5 *) + &sensor->data_pkt[i]; + i += (sensor->nbr_fingers * 5); + } + + if (query->has_rel) { + data->rel_pos = (struct f11_2d_data_6_7 *) + &sensor->data_pkt[i]; + i += (sensor->nbr_fingers * 2); + } + + if (query->f11_2d_query7__8[0]) { + data->gest_1 = (struct f11_2d_data_8 *)&sensor->data_pkt[i]; + i++; + } + + if (query->f11_2d_query7__8[0] || query->f11_2d_query7__8[1]) { + data->gest_2 = (struct f11_2d_data_9 *)&sensor->data_pkt[i]; + i++; + } + + if (query->has_pinch) { + data->pinch = (struct f11_2d_data_10 *)&sensor->data_pkt[i]; + i++; + } + + if (query->has_flick) { + if (query->has_pinch) { + data->flick = (struct f11_2d_data_10_12 *)data->pinch; + i += 2; + } else { + data->flick = (struct f11_2d_data_10_12 *) + &sensor->data_pkt[i]; + i += 3; + } + } + + if (query->has_rotate) { + if (query->has_flick) { + data->rotate = (struct f11_2d_data_11_12 *) + (data->flick + 1); + } else { + data->rotate = (struct f11_2d_data_11_12 *) + &sensor->data_pkt[i]; + i += 2; + } + } + + if (query->has_touch_shapes) + data->shapes = (struct f11_2d_data_13 *)&sensor->data_pkt[i]; + + return 0; +} + +static void f11_free_control_regs(struct f11_2d_ctrl *ctrl) +{ + kfree(ctrl->ctrl10); + kfree(ctrl->ctrl11); + kfree(ctrl->ctrl14); + kfree(ctrl->ctrl15); + kfree(ctrl->ctrl16); + kfree(ctrl->ctrl17); + kfree(ctrl->ctrl18_19); + kfree(ctrl->ctrl20_21); + ctrl->ctrl10 = NULL; + ctrl->ctrl11 = NULL; + ctrl->ctrl14 = NULL; + ctrl->ctrl15 = NULL; + ctrl->ctrl16 = NULL; + ctrl->ctrl17 = NULL; + ctrl->ctrl18_19 = NULL; + ctrl->ctrl20_21 = NULL; +} + +static int f11_read_control_regs(struct rmi_device *rmi_dev, + struct f11_2d_ctrl *ctrl, + int ctrl_base_addr) { + int read_address = ctrl_base_addr; + int error = 0; + + error = rmi_read_block(rmi_dev, read_address, ctrl->ctrl0_9, + sizeof(ctrl->ctrl0_9)); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read F11 ctrl0, code: %d.\n", error); + return error; + } + read_address = read_address + sizeof(ctrl->ctrl0_9); + + if (ctrl->ctrl10) { + error = rmi_read_block(rmi_dev, read_address, + &ctrl->ctrl10->reg, sizeof(union f11_2d_ctrl10)); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read F11 ctrl10, code: %d.\n", + error); + return error; + } + read_address = read_address + sizeof(union f11_2d_ctrl10); + } + + if (ctrl->ctrl11) { + error = rmi_read_block(rmi_dev, read_address, + &ctrl->ctrl11->reg, sizeof(union f11_2d_ctrl11)); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read F11 ctrl11, code: %d.\n", + error); + return error; + } + read_address = read_address + sizeof(union f11_2d_ctrl11); + } + + if (ctrl->ctrl14) { + error = rmi_read_block(rmi_dev, read_address, + &ctrl->ctrl14->reg, sizeof(union f11_2d_ctrl14)); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read F11 ctrl14, code: %d.\n", + error); + return error; + } + read_address = read_address + sizeof(union f11_2d_ctrl14); + } + + if (ctrl->ctrl15) { + error = rmi_read_block(rmi_dev, read_address, + &ctrl->ctrl15->reg, sizeof(union f11_2d_ctrl15)); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read F11 ctrl15, code: %d.\n", + error); + return error; + } + read_address = read_address + sizeof(union f11_2d_ctrl15); + } + + if (ctrl->ctrl16) { + error = rmi_read_block(rmi_dev, read_address, + &ctrl->ctrl16->reg, sizeof(union f11_2d_ctrl16)); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read F11 ctrl16, code: %d.\n", + error); + return error; + } + read_address = read_address + sizeof(union f11_2d_ctrl16); + } + + if (ctrl->ctrl17) { + error = rmi_read_block(rmi_dev, read_address, + &ctrl->ctrl17->reg, sizeof(union f11_2d_ctrl17)); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read F11 ctrl17, code: %d.\n", + error); + return error; + } + read_address = read_address + sizeof(union f11_2d_ctrl17); + } + + if (ctrl->ctrl18_19) { + error = rmi_read_block(rmi_dev, read_address, + ctrl->ctrl18_19->reg, sizeof(union f11_2d_ctrl18_19)); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read F11 ctrl18_19, code: %d.\n", + error); + return error; + } + read_address = read_address + sizeof(union f11_2d_ctrl18_19); + } + + if (ctrl->ctrl20_21) { + error = rmi_read_block(rmi_dev, read_address, + ctrl->ctrl20_21->reg, sizeof(union f11_2d_ctrl20_21)); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read F11 ctrl20_21, code: %d.\n", + error); + return error; + } + read_address = read_address + sizeof(union f11_2d_ctrl20_21); + } + + return 0; +} + +static int f11_allocate_control_regs(struct rmi_device *rmi_dev, + struct f11_2d_device_query *device_query, + struct f11_2d_sensor_query *sensor_query, + struct f11_2d_ctrl *ctrl, + int ctrl_base_addr) { + int error = 0; + + if (sensor_query->f11_2d_query7__8[0]) { + ctrl->ctrl10 = kzalloc(sizeof(union f11_2d_ctrl10), + GFP_KERNEL); + if (!ctrl->ctrl10) { + error = -ENOMEM; + goto error_exit; + } + } + + if (sensor_query->f11_2d_query7__8[1]) { + ctrl->ctrl11 = kzalloc(sizeof(union f11_2d_ctrl11), + GFP_KERNEL); + if (!ctrl->ctrl11) { + error = -ENOMEM; + goto error_exit; + } + } + + if (device_query->has_query9 && sensor_query->query9.has_pen) { + ctrl->ctrl20_21 = kzalloc(sizeof(union f11_2d_ctrl20_21), + GFP_KERNEL); + if (!ctrl->ctrl20_21) { + error = -ENOMEM; + goto error_exit; + } + } + + return f11_read_control_regs(rmi_dev, ctrl, ctrl_base_addr); + +error_exit: + f11_free_control_regs(ctrl); + return error; +} + +static int f11_write_control_regs(struct rmi_device *rmi_dev, + struct f11_2d_sensor_query *query, + struct f11_2d_ctrl *ctrl, + int ctrl_base_addr) +{ + int write_address = ctrl_base_addr; + int error; + + error = rmi_write_block(rmi_dev, write_address, + ctrl->ctrl0_9, sizeof(ctrl->ctrl0_9)); + if (error < 0) + return error; + write_address += sizeof(ctrl->ctrl0_9); + + if (ctrl->ctrl10) { + error = rmi_write_block(rmi_dev, write_address, + &ctrl->ctrl10->reg, 1); + if (error < 0) + return error; + write_address++; + } + + if (ctrl->ctrl11) { + error = rmi_write_block(rmi_dev, write_address, + &ctrl->ctrl11->reg, 1); + if (error < 0) + return error; + write_address++; + } + + if (ctrl->ctrl12 && ctrl->ctrl12_size && query->configurable) { + if (ctrl->ctrl12_size > query->max_electrodes) { + dev_err(&rmi_dev->dev, + "%s: invalid cfg size:%d, should be < %d.\n", + __func__, ctrl->ctrl12_size, + query->max_electrodes); + return -EINVAL; + } + error = rmi_write_block(rmi_dev, write_address, + &ctrl->ctrl12->reg, + ctrl->ctrl12_size); + if (error < 0) + return error; + write_address += ctrl->ctrl12_size; + } + + if (ctrl->ctrl14) { + error = rmi_write_block(rmi_dev, write_address, + &ctrl->ctrl14->reg, 1); + if (error < 0) + return error; + write_address++; + } + + if (ctrl->ctrl15) { + error = rmi_write_block(rmi_dev, write_address, + &ctrl->ctrl15->reg, 1); + if (error < 0) + return error; + write_address++; + } + + if (ctrl->ctrl16) { + error = rmi_write_block(rmi_dev, write_address, + &ctrl->ctrl16->reg, 1); + if (error < 0) + return error; + write_address++; + } + + if (ctrl->ctrl17) { + error = rmi_write_block(rmi_dev, write_address, + &ctrl->ctrl17->reg, 1); + if (error < 0) + return error; + write_address++; + } + + if (ctrl->ctrl18_19) { + error = rmi_write_block(rmi_dev, write_address, + ctrl->ctrl18_19->reg, sizeof(union f11_2d_ctrl18_19)); + if (error < 0) + return error; + write_address += sizeof(union f11_2d_ctrl18_19); + } + + if (ctrl->ctrl20_21) { + error = rmi_write_block(rmi_dev, write_address, + ctrl->ctrl20_21->reg, + sizeof(union f11_2d_ctrl20_21)); + if (error < 0) + return error; + write_address += sizeof(union f11_2d_ctrl20_21); + } + + return 0; +} + +static int rmi_f11_get_query_parameters(struct rmi_device *rmi_dev, + struct f11_2d_sensor_query *query, u8 query_base_addr) +{ + int query_size; + int rc; + + rc = rmi_read_block(rmi_dev, query_base_addr, query->f11_2d_query1__4, + sizeof(query->f11_2d_query1__4)); + if (rc < 0) + return rc; + query_size = rc; + + if (query->has_abs) { + rc = rmi_read(rmi_dev, query_base_addr + query_size, + &query->f11_2d_query5); + if (rc < 0) + return rc; + query_size++; + } + + if (query->has_rel) { + rc = rmi_read(rmi_dev, query_base_addr + query_size, + &query->f11_2d_query6); + if (rc < 0) + return rc; + query_size++; + } + + if (query->has_gestures) { + rc = rmi_read_block(rmi_dev, query_base_addr + query_size, + query->f11_2d_query7__8, + sizeof(query->f11_2d_query7__8)); + if (rc < 0) + return rc; + query_size += sizeof(query->f11_2d_query7__8); + } + + if (query->has_touch_shapes) { + rc = rmi_read(rmi_dev, query_base_addr + query_size, + &query->f11_2d_query10); + if (rc < 0) + return rc; + query_size++; + } + + return query_size; +} + +/* This operation is done in a number of places, so we have a handy routine + * for it. + */ +static void f11_set_abs_params(struct rmi_function_container *fc, int index) +{ + struct f11_data *instance_data = fc->data; + struct f11_2d_sensor *sensor = &instance_data->sensors[index]; + struct input_dev *input = sensor->input; + int device_x_max = + instance_data->dev_controls.sensor_max_x_pos; + int device_y_max = + instance_data->dev_controls.sensor_max_y_pos; + int x_min, x_max, y_min, y_max; + + if (sensor->axis_align.swap_axes) { + int temp = device_x_max; + device_x_max = device_y_max; + device_y_max = temp; + } + + /* Use the max X and max Y read from the device, or the clip values, + * whichever is stricter. + */ + x_min = sensor->axis_align.clip_X_low; + if (sensor->axis_align.clip_X_high) + x_max = min((int) device_x_max, + sensor->axis_align.clip_X_high); + else + x_max = device_x_max; + + y_min = sensor->axis_align.clip_Y_low; + if (sensor->axis_align.clip_Y_high) + y_max = min((int) device_y_max, + sensor->axis_align.clip_Y_high); + else + y_max = device_y_max; + + dev_dbg(&fc->dev, "Set ranges X=[%d..%d] Y=[%d..%d].", + x_min, x_max, y_min, y_max); + + __set_bit(INPUT_PROP_DIRECT, input->propbit); + __set_bit(EV_ABS, input->evbit); + input_mt_init_slots(input, SYNAPTICS_MAX_POINTS); + input_set_abs_params(input, ABS_MT_PRESSURE, 0, DEFAULT_MAX_ABS_MT_PRESSURE, 0, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, DEFAULT_MAX_ABS_MT_TOUCH, 0, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, DEFAULT_MAX_ABS_MT_TOUCH, 0, 0); + input_set_abs_params(input, ABS_MT_ORIENTATION, 0, DEFAULT_MAX_ABS_MT_ORIENTATION, 0, 0); + input_set_abs_params(input, ABS_MT_TRACKING_ID, + DEFAULT_MIN_ABS_MT_TRACKING_ID, + DEFAULT_MAX_ABS_MT_TRACKING_ID, 0, 0); + /* TODO get max_x_pos (and y) from control registers. */ + input_set_abs_params(input, ABS_MT_POSITION_X, x_min, x_max, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); +#ifdef CONFIG_RMI4_F11_PEN + if (sensor->sens_query.query9.has_pen) + input_set_abs_params(input, ABS_MT_TOOL_TYPE, + 0, MT_TOOL_MAX, 0, 0); +#endif +} + +static int rmi_f11_init(struct rmi_function_container *fc) +{ + int rc; + + rc = rmi_f11_initialize(fc); + if (rc < 0) + goto err_free_data; + + rc = rmi_f11_register_devices(fc); + if (rc < 0) + goto err_free_data; + + rc = rmi_f11_create_sysfs(fc); + if (rc < 0) + goto err_free_data; + + return 0; + +err_free_data: + rmi_f11_free_memory(fc); + + return rc; +} + +static void rmi_f11_free_memory(struct rmi_function_container *fc) +{ + struct f11_data *f11 = fc->data; + int i; + + if (f11) { + f11_free_control_regs(&f11->dev_controls); + for (i = 0; i < f11->dev_query.nbr_of_sensors + 1; i++) + kfree(f11->sensors[i].virtualbutton_map.map); + kfree(f11); + fc->data = NULL; + } +} + + +static int rmi_f11_initialize(struct rmi_function_container *fc) +{ + struct rmi_device *rmi_dev = fc->rmi_dev; + struct f11_data *f11; + u8 query_offset; + u8 query_base_addr; + u8 control_base_addr; + u16 max_x_pos, max_y_pos, temp; + int rc; + int i; + struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev); + + dev_dbg(&fc->dev, "Initializing F11 values for %s.\n", + pdata->sensor_name); + + /* + ** init instance data, fill in values and create any sysfs files + */ + f11 = kzalloc(sizeof(struct f11_data), GFP_KERNEL); + if (!f11) + return -ENOMEM; + + fc->data = f11; +#if RESUME_REZERO + f11->rezero_on_resume = true; + f11->rezero_wait_ms = DEFAULT_REZERO_WAIT_MS; +#endif + + query_base_addr = fc->fd.query_base_addr; + control_base_addr = fc->fd.control_base_addr; + + rc = rmi_read(rmi_dev, query_base_addr, &f11->dev_query.f11_2d_query0); + if (rc < 0) + return rc; + + query_offset = (query_base_addr + 1); + /* Increase with one since number of sensors is zero based */ + for (i = 0; i < (f11->dev_query.nbr_of_sensors + 1); i++) { + f11->sensors[i].sensor_index = i; + + rc = rmi_f11_get_query_parameters(rmi_dev, + &f11->sensors[i].sens_query, + query_offset); + if (rc < 0) + return rc; + query_offset += rc; + + if (f11->dev_query.has_query9) { + rc = rmi_read(rmi_dev, query_offset, + &f11->sensors[i].sens_query.query9.reg); + if (rc < 0) { + dev_err(&fc->dev, "Failed to read query 9.\n"); + return rc; + } + query_offset += rc; + } + + rc = f11_allocate_control_regs(rmi_dev, + &f11->dev_query, &f11->sensors[i].sens_query, + &f11->dev_controls, control_base_addr); + if (rc < 0) { + dev_err(&fc->dev, + "Failed to initialize F11 control params.\n"); + return rc; + } + + f11->sensors[i].axis_align = pdata->axis_align; + + rc = rmi_read_block(rmi_dev, + control_base_addr + F11_CTRL_SENSOR_MAX_X_POS_OFFSET, + (u8 *)&max_x_pos, sizeof(max_x_pos)); + if (rc < 0) + return rc; + + rc = rmi_read_block(rmi_dev, + control_base_addr + F11_CTRL_SENSOR_MAX_Y_POS_OFFSET, + (u8 *)&max_y_pos, sizeof(max_y_pos)); + if (rc < 0) + return rc; + + if (pdata->axis_align.swap_axes) { + temp = max_x_pos; + max_x_pos = max_y_pos; + max_y_pos = temp; + } + f11->sensors[i].max_x = max_x_pos; + f11->sensors[i].max_y = max_y_pos; + + rc = f11_2d_construct_data(&f11->sensors[i]); + if (rc < 0) + return rc; + } + + return 0; +} + +static int rmi_f11_register_devices(struct rmi_function_container *fc) +{ + struct rmi_device *rmi_dev = fc->rmi_dev; + struct f11_data *f11 = fc->data; + struct input_dev *input_dev; + struct input_dev *input_dev_mouse; + int sensors_itertd = 0; + int i; + int rc; +#ifdef CONFIG_RMI4_VIRTUAL_BUTTON + struct rmi_f11_virtualbutton_map *vm_sensor; + struct rmi_f11_virtualbutton_map *vm_pdata; + struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev); +#endif + + for (i = 0; i < (f11->dev_query.nbr_of_sensors + 1); i++) { + sensors_itertd = i; + input_dev = input_allocate_device(); + if (!input_dev) { + rc = -ENOMEM; + goto error_unregister; + } + + f11->sensors[i].input = input_dev; + /* TODO how to modify the dev name and + * phys name for input device */ + sprintf(f11->sensors[i].input_name, "%sfn%02x", + dev_name(&rmi_dev->dev), fc->fd.function_number); + input_dev->name = f11->sensors[i].input_name; + sprintf(f11->sensors[i].input_phys, "%s/input0", + input_dev->name); + input_dev->phys = f11->sensors[i].input_phys; + input_dev->dev.parent = &rmi_dev->dev; + input_set_drvdata(input_dev, f11); + + set_bit(EV_SYN, input_dev->evbit); + set_bit(EV_KEY, input_dev->evbit); + set_bit(EV_ABS, input_dev->evbit); + + f11_set_abs_params(fc, i); + + dev_dbg(&fc->dev, "%s: Sensor %d hasRel %d.\n", + __func__, i, f11->sensors[i].sens_query.has_rel); + if (f11->sensors[i].sens_query.has_rel) { + set_bit(EV_REL, input_dev->evbit); + set_bit(REL_X, input_dev->relbit); + set_bit(REL_Y, input_dev->relbit); + } + rc = input_register_device(input_dev); + if (rc < 0) { + input_free_device(input_dev); + f11->sensors[i].input = NULL; + goto error_unregister; + } + + /* how to register the virtualbutton device */ +#ifdef CONFIG_RMI4_VIRTUAL_BUTTON + if (f11->sensors[i].sens_query.has_gestures) { + int j; + + vm_sensor = &f11->sensors[i].virtualbutton_map; + vm_pdata = pdata->virtualbutton_map; + if (!vm_pdata) { + dev_err(&fc->dev, "Failed to get the pdata virtualbutton map.\n"); + goto error_unregister; + } + vm_sensor->buttons = vm_pdata->buttons; + vm_sensor->map = kcalloc(vm_pdata->buttons, + sizeof(struct virtualbutton_map), + GFP_KERNEL); + if (!vm_sensor->map) { + dev_err(&fc->dev, "Failed to allocate the virtualbutton map.\n"); + rc = -ENOMEM; + goto error_unregister; + } + /* set bits for each button... */ + for (j = 0; j < vm_pdata->buttons; j++) { + memcpy(&vm_sensor->map[j], &vm_pdata->map[j], + sizeof(struct virtualbutton_map)); + set_bit(vm_sensor->map[j].code, + f11->sensors[i].input->keybit); + } + } + +#endif + + if (f11->sensors[i].sens_query.has_rel) { + /*create input device for mouse events */ + input_dev_mouse = input_allocate_device(); + if (!input_dev_mouse) { + rc = -ENOMEM; + goto error_unregister; + } + + f11->sensors[i].mouse_input = input_dev_mouse; + input_dev_mouse->name = "rmi_mouse"; + input_dev_mouse->phys = "rmi_f11/input0"; + + input_dev_mouse->id.vendor = 0x18d1; + input_dev_mouse->id.product = 0x0210; + input_dev_mouse->id.version = 0x0100; + + set_bit(EV_REL, input_dev_mouse->evbit); + set_bit(REL_X, input_dev_mouse->relbit); + set_bit(REL_Y, input_dev_mouse->relbit); + + set_bit(BTN_MOUSE, input_dev_mouse->evbit); + /* Register device's buttons and keys */ + set_bit(EV_KEY, input_dev_mouse->evbit); + set_bit(BTN_LEFT, input_dev_mouse->keybit); + set_bit(BTN_MIDDLE, input_dev_mouse->keybit); + set_bit(BTN_RIGHT, input_dev_mouse->keybit); + + rc = input_register_device(input_dev_mouse); + if (rc < 0) { + input_free_device(input_dev_mouse); + f11->sensors[i].mouse_input = NULL; + goto error_unregister; + } + + set_bit(BTN_RIGHT, input_dev_mouse->keybit); + } + + } + + return 0; + +error_unregister: + for (; sensors_itertd > 0; sensors_itertd--) { + if (f11->sensors[sensors_itertd].input) { + if (f11->sensors[sensors_itertd].mouse_input) { + input_unregister_device( + f11->sensors[sensors_itertd].mouse_input); + f11->sensors[sensors_itertd].mouse_input = NULL; + } + input_unregister_device(f11->sensors[i].input); + f11->sensors[i].input = NULL; + } + kfree(f11->sensors[i].virtualbutton_map.map); + } + + return rc; +} + +static void rmi_f11_free_devices(struct rmi_function_container *fc) +{ + struct f11_data *f11 = fc->data; + int i; + + for (i = 0; i < (f11->dev_query.nbr_of_sensors + 1); i++) { + if (f11->sensors[i].input) + input_unregister_device(f11->sensors[i].input); + if (f11->sensors[i].sens_query.has_rel && + f11->sensors[i].mouse_input) + input_unregister_device(f11->sensors[i].mouse_input); + } +} + +static int rmi_f11_create_sysfs(struct rmi_function_container *fc) +{ + int attr_count = 0; + int rc; + + dev_dbg(&fc->dev, "Creating sysfs files.\n"); + /* Set up sysfs device attributes. */ + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { + if (sysfs_create_file + (&fc->dev.kobj, &attrs[attr_count].attr) < 0) { + dev_err(&fc->dev, + "Failed to create sysfs file for %s.", + attrs[attr_count].attr.name); + rc = -ENODEV; + goto err_remove_sysfs; + } + } + + return 0; + +err_remove_sysfs: + for (attr_count--; attr_count >= 0; attr_count--) + sysfs_remove_file(&fc->dev.kobj, + &attrs[attr_count].attr); + return rc; +} + +static int rmi_f11_config(struct rmi_function_container *fc) +{ + struct f11_data *f11 = fc->data; + int i; + int rc; + + for (i = 0; i < (f11->dev_query.nbr_of_sensors + 1); i++) { + rc = f11_write_control_regs(fc->rmi_dev, + &f11->sensors[i].sens_query, + &f11->dev_controls, + fc->fd.query_base_addr); + if (rc < 0) + return rc; + } + + return 0; +} + +static int rmi_f11_reset(struct rmi_function_container *fc) +{ + /* we do nothing here */ + return 0; +} + +int rmi_f11_attention(struct rmi_function_container *fc, u8 *irq_bits) +{ + struct rmi_device *rmi_dev = fc->rmi_dev; + struct f11_data *f11 = fc->data; + u8 data_base_addr = fc->fd.data_base_addr; + int data_base_addr_offset = 0; + int error; + int i; + + for (i = 0; i < f11->dev_query.nbr_of_sensors + 1; i++) { + error = rmi_read_block(rmi_dev, + data_base_addr + data_base_addr_offset, + f11->sensors[i].data_pkt, + f11->sensors[i].pkt_size); + if (error < 0) + return error; + + rmi_f11_finger_handler(&f11->sensors[i]); + rmi_f11_virtual_button_handler(&f11->sensors[i]); + data_base_addr_offset += f11->sensors[i].pkt_size; + } + + return 0; +} + +#if RESUME_REZERO +static int rmi_f11_resume(struct rmi_function_container *fc) +{ + struct rmi_device *rmi_dev = fc->rmi_dev; + struct f11_data *data = fc->data; + /* Command register always reads as 0, so we can just use a local. */ + union f11_2d_commands commands = {}; + int retval = 0; + + dev_dbg(&fc->dev, "Resuming...\n"); + if (!data->rezero_on_resume) + return 0; + + if (data->rezero_wait_ms) + mdelay(data->rezero_wait_ms); + + commands.rezero = 1; + retval = rmi_write_block(rmi_dev, fc->fd.command_base_addr, + &commands.reg, sizeof(commands.reg)); + if (retval < 0) { + dev_err(&rmi_dev->dev, "%s: failed to issue rezero command, error = %d.", + __func__, retval); + return retval; + } + + return retval; +} +#endif /* RESUME_REZERO */ + +static void rmi_f11_remove(struct rmi_function_container *fc) +{ + int attr_count = 0; + + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { + sysfs_remove_file(&fc->dev.kobj, + &attrs[attr_count].attr); + } + + rmi_f11_free_devices(fc); + + rmi_f11_free_memory(fc); + +} + +static struct rmi_function_handler function_handler = { + .func = 0x11, + .init = rmi_f11_init, + .config = rmi_f11_config, + .reset = rmi_f11_reset, + .attention = rmi_f11_attention, + .remove = rmi_f11_remove +#if RESUME_REZERO +#ifdef CONFIG_HAS_EARLYSUSPEND + , + .late_resume = rmi_f11_resume +#else + .resume = rmi_f11_resume +#endif /* CONFIG_HAS_EARLYSUSPEND */ +#endif +}; + +static int __init rmi_f11_module_init(void) +{ + int error; + + error = rmi_register_function_driver(&function_handler); + if (error < 0) { + pr_err("%s: register failed!\n", __func__); + return error; + } + + return 0; +} + +static void __exit rmi_f11_module_exit(void) +{ + rmi_unregister_function_driver(&function_handler); +} + +static ssize_t f11_maxPos_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f11_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u %u\n", + data->sensors[0].max_x, data->sensors[0].max_y); +} + +static ssize_t f11_flip_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f11_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u %u\n", + data->sensors[0].axis_align.flip_x, + data->sensors[0].axis_align.flip_y); +} + +static ssize_t f11_flip_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct rmi_function_container *fc; + struct f11_data *instance_data; + unsigned int new_X, new_Y; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + + if (sscanf(buf, "%u %u", &new_X, &new_Y) != 2) + return -EINVAL; + if (new_X < 0 || new_X > 1 || new_Y < 0 || new_Y > 1) + return -EINVAL; + instance_data->sensors[0].axis_align.flip_x = new_X; + instance_data->sensors[0].axis_align.flip_y = new_Y; + + return count; +} + +static ssize_t f11_swap_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rmi_function_container *fc; + struct f11_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", + instance_data->sensors[0].axis_align.swap_axes); +} + +static ssize_t f11_swap_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct f11_data *instance_data; + unsigned int newSwap; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + + if (sscanf(buf, "%u", &newSwap) != 1) + return -EINVAL; + if (newSwap < 0 || newSwap > 1) + return -EINVAL; + instance_data->sensors[0].axis_align.swap_axes = newSwap; + + f11_set_abs_params(fc, 0); + + return count; +} + +static ssize_t f11_relreport_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f11_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", + instance_data-> + sensors[0].axis_align.rel_report_enabled); +} + +static ssize_t f11_relreport_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct rmi_function_container *fc; + struct f11_data *instance_data; + unsigned int new_value; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + + if (sscanf(buf, "%u", &new_value) != 1) + return -EINVAL; + if (new_value < 0 || new_value > 1) + return -EINVAL; + instance_data->sensors[0].axis_align.rel_report_enabled = new_value; + + return count; +} + +static ssize_t f11_offset_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f11_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%d %d\n", + instance_data->sensors[0].axis_align.offset_X, + instance_data->sensors[0].axis_align.offset_Y); +} + +static ssize_t f11_offset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct rmi_function_container *fc; + struct f11_data *instance_data; + int new_X, new_Y; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + + if (sscanf(buf, "%d %d", &new_X, &new_Y) != 2) + return -EINVAL; + instance_data->sensors[0].axis_align.offset_X = new_X; + instance_data->sensors[0].axis_align.offset_Y = new_Y; + + return count; +} + +static ssize_t f11_clip_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + + struct rmi_function_container *fc; + struct f11_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u %u %u %u\n", + instance_data->sensors[0].axis_align.clip_X_low, + instance_data->sensors[0].axis_align.clip_X_high, + instance_data->sensors[0].axis_align.clip_Y_low, + instance_data->sensors[0].axis_align.clip_Y_high); +} + +static ssize_t f11_clip_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct rmi_function_container *fc; + struct f11_data *instance_data; + unsigned int new_X_low, new_X_high, new_Y_low, new_Y_high; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + if (sscanf(buf, "%u %u %u %u", + &new_X_low, &new_X_high, &new_Y_low, &new_Y_high) != 4) + return -EINVAL; + if (new_X_low < 0 || new_X_low >= new_X_high || new_Y_low < 0 + || new_Y_low >= new_Y_high) + return -EINVAL; + instance_data->sensors[0].axis_align.clip_X_low = new_X_low; + instance_data->sensors[0].axis_align.clip_X_high = new_X_high; + instance_data->sensors[0].axis_align.clip_Y_low = new_Y_low; + instance_data->sensors[0].axis_align.clip_Y_high = new_Y_high; + + /* + ** for now, we assume this is sensor index 0 + */ + f11_set_abs_params(fc, 0); + + return count; +} + +static ssize_t f11_rezero_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc = NULL; + unsigned int rezero; + int retval = 0; + /* Command register always reads as 0, so we can just use a local. */ + union f11_2d_commands commands = {}; + + fc = to_rmi_function_container(dev); + + if (sscanf(buf, "%u", &rezero) != 1) + return -EINVAL; + if (rezero < 0 || rezero > 1) + return -EINVAL; + + /* Per spec, 0 has no effect, so we skip it entirely. */ + if (rezero) { + commands.rezero = 1; + retval = rmi_write_block(fc->rmi_dev, fc->fd.command_base_addr, + &commands.reg, sizeof(commands.reg)); + if (retval < 0) { + dev_err(dev, "%s: failed to issue rezero command, error = %d.", + __func__, retval); + return retval; + } + } + + return count; +} + +#if RESUME_REZERO +static ssize_t f11_rezeroOnResume_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc = NULL; + unsigned int newValue; + struct f11_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + if (sscanf(buf, "%u", &newValue) != 1) + return -EINVAL; + if (newValue < 0 || newValue > 1) { + dev_err(dev, "rezeroOnResume must be either 1 or 0.\n"); + return -EINVAL; + } + + instance_data->rezero_on_resume = (newValue != 0); + + return count; +} + +static ssize_t f11_rezeroOnResume_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f11_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", + instance_data->rezero_on_resume); +} + +static ssize_t f11_rezeroWait_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc = NULL; + unsigned int newValue; + struct f11_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + if (sscanf(buf, "%u", &newValue) != 1) + return -EINVAL; + if (newValue < 0) { + dev_err(dev, "rezeroWait must be 0 or greater.\n"); + return -EINVAL; + } + + instance_data->rezero_wait_ms = (newValue != 0); + + return count; +} + +static ssize_t f11_rezeroWait_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f11_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", + instance_data->rezero_wait_ms); +} +#endif + +module_init(rmi_f11_module_init); +module_exit(rmi_f11_module_exit); + +MODULE_AUTHOR("Christopher Heiny +#include +#include +#include +#include "rmi_driver.h" +#define QUERY_BASE_INDEX 1 +#define MAX_NAME_LENGTH 256 + +union f17_device_query { + struct { + u8 number_of_sticks:3; + }; + u8 regs[1]; +}; + +#define F17_MANUFACTURER_SYNAPTICS 0 +#define F17_MANUFACTURER_NMB 1 +#define F17_MANUFACTURER_ALPS 2 + +struct f17_stick_query { + union { + struct { + u8 manufacturer:4; + u8 resistive:1; + u8 ballistics:1; + u8 reserved1:2; + u8 has_relative:1; + u8 has_absolute:1; + u8 has_gestures:1; + u8 has_dribble:1; + u8 reserved2:4; + }; + u8 regs[2]; + } general; + + union { + struct { + u8 has_single_tap:1; + u8 has_tap_and_hold:1; + u8 has_double_tap:1; + u8 has_early_tap:1; + u8 has_press:1; + }; + u8 regs[1]; + } gestures; +}; + +union f17_device_controls { + struct { + u8 reporting_mode:3; + u8 dribble:1; + }; + u8 regs[1]; +}; + +struct f17_stick_controls { + union { + struct { + u8 z_force_threshold; + u8 radial_force_threshold; + }; + u8 regs[3]; + } general; + + union { + struct { + u8 motion_sensitivity:4; + u8 antijitter:1; + }; + u8 regs[1]; + } relative; + + union { + struct { + u8 single_tap:1; + u8 tap_and_hold:1; + + u8 double_tap:1; + u8 early_tap:1; + u8 press:1; + }; + u8 regs[1]; + } enable; + + u8 maximum_tap_time; + u8 minimum_press_time; + u8 maximum_radial_force; +}; + + +union f17_device_commands { + struct { + u8 rezero:1; + }; + u8 regs[1]; +}; + +struct f17_stick_data { + union { + struct { + u8 x_force_high; + u8 y_force_high; + u8 y_force_low:4; + u8 x_force_low:4; + u8 z_force; + }; + u8 regs[4]; + } abs; + union { + struct { + s8 x_delta; + s8 y_delta; + }; + u8 regs[2]; + } rel; + union { + struct { + u8 single_tap:1; + u8 tap_and_hold:1; + u8 double_tap:1; + u8 early_tap:1; + u8 press:1; + }; + u8 regs[1]; + } gestures; +}; + + +/* data specific to f17 that needs to be kept around */ + +struct rmi_f17_stick_data { + struct f17_stick_query query; + struct f17_stick_controls controls; + struct f17_stick_data data; + + u16 abs_data_address; + u16 rel_data_address; + u16 gesture_data_address; + u16 control_address; + + int index; + + char input_name[MAX_NAME_LENGTH]; + char input_phys[MAX_NAME_LENGTH]; + struct input_dev *input; + char mouse_name[MAX_NAME_LENGTH]; + char mouse_phys[MAX_NAME_LENGTH]; + struct input_dev *mouse; +}; + +struct rmi_f17_device_data { + u16 control_address; + + union f17_device_query query; + union f17_device_commands commands; + union f17_device_controls controls; + + struct rmi_f17_stick_data *sticks; + +}; + +static ssize_t f17_rezero_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t f17_rezero_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + + + +static int f17_alloc_memory(struct rmi_function_container *fc); + +static void f17_free_memory(struct rmi_function_container *fc); + +static int f17_initialize(struct rmi_function_container *fc); + +static int f17_register_devices(struct rmi_function_container *fc); + +static int f17_create_sysfs(struct rmi_function_container *fc); + +static int f17_config(struct rmi_function_container *fc); + +static int f17_reset(struct rmi_function_container *fc); + +static struct device_attribute attrs[] = { + __ATTR(rezero, RMI_RW_ATTR, + f17_rezero_show, f17_rezero_store), +}; + + +int f17_read_control_parameters(struct rmi_device *rmi_dev, + struct rmi_f17_device_data *f17) +{ + int retval = 0; + + // TODO: read this or delete the function + + return retval; +} + + +static int f17_init(struct rmi_function_container *fc) +{ + int retval; + + retval = f17_alloc_memory(fc); + if (retval < 0) + goto err_free_data; + + retval = f17_initialize(fc); + if (retval < 0) + goto err_free_data; + + retval = f17_register_devices(fc); + if (retval < 0) + goto err_free_data; + + retval = f17_create_sysfs(fc); + if (retval < 0) + goto err_free_data; + + return 0; + +err_free_data: + f17_free_memory(fc); + + return retval; +} + +static int f17_alloc_memory(struct rmi_function_container *fc) +{ + struct rmi_f17_device_data *f17; + int retval; + int i; + + f17 = kzalloc(sizeof(struct rmi_f17_device_data), GFP_KERNEL); + if (!f17) { + dev_err(&fc->dev, "Failed to allocate function data.\n"); + return -ENOMEM; + } + fc->data = f17; + + retval = rmi_read_block(fc->rmi_dev, fc->fd.query_base_addr, + f17->query.regs, sizeof(f17->query.regs)); + if (retval < 0) { + dev_err(&fc->dev, "Failed to read query register.\n"); + goto error_exit; + } + dev_info(&fc->dev, "Found F17 with %d sticks.\n", + f17->query.number_of_sticks + 1); + + f17->sticks = kcalloc(f17->query.number_of_sticks + 1, + sizeof(struct rmi_f17_stick_data), GFP_KERNEL); + if (!f17->sticks) { + dev_err(&fc->dev, "Failed to allocate per stick data.\n"); + return -ENOMEM; + } + + for (i = 0; i < f17->query.number_of_sticks + 1; i++) { + // TODO: allocate any per stick stuff (or remove this loop) + } + + return 0; + +error_exit: + kfree(f17); + fc->data = NULL; + return retval; +} + +static void f17_free_memory(struct rmi_function_container *fc) +{ + struct rmi_f17_device_data *f17 = fc->data; + int i; + + if (f17) { + if (f17->sticks) { + for (i = 0; i < f17->query.number_of_sticks + 1; i++) { + // TODO: Free stick stuff + } + } + kfree(f17->sticks); + f17->sticks = NULL; + } + kfree(f17); + fc->data = NULL; +} + +static int f17_init_stick(struct rmi_device *rmi_dev, + struct rmi_f17_stick_data *stick, + u16 *next_query_reg, u16 *next_data_reg, + u16 *next_control_reg) { + int retval = 0; + + retval = rmi_read_block(rmi_dev, *next_query_reg, + stick->query.general.regs, + sizeof(stick->query.general.regs)); + if (retval < 0) { + dev_err(&rmi_dev->dev, "Failed to read stick general query.\n"); + return retval; + } + *next_query_reg += sizeof(stick->query.general.regs); + + dev_info(&rmi_dev->dev, "Stick %d found\n", stick->index); + dev_info(&rmi_dev->dev, " Manufacturer: %d.\n", stick->query.general.manufacturer); + dev_info(&rmi_dev->dev, " Resistive: %d.\n", stick->query.general.resistive); + dev_info(&rmi_dev->dev, " Ballistics: %d.\n", stick->query.general.ballistics); + dev_info(&rmi_dev->dev, " Manufacturer: %d.\n", stick->query.general.ballistics); + dev_info(&rmi_dev->dev, " Has relative: %d.\n", stick->query.general.has_relative); + dev_info(&rmi_dev->dev, " Has absolute: %d.\n", stick->query.general.has_absolute); + dev_info(&rmi_dev->dev, " Had dribble: %d.\n", stick->query.general.has_dribble); + dev_info(&rmi_dev->dev, " Has gestures: %d.\n", stick->query.general.has_gestures); + + if (stick->query.general.has_gestures) { + retval = rmi_read_block(rmi_dev, *next_query_reg, + stick->query.gestures.regs, + sizeof(stick->query.gestures.regs)); + if (retval < 0) { + dev_err(&rmi_dev->dev, "Failed to read stick gestures query.\n"); + return retval; + } + *next_query_reg += sizeof(stick->query.gestures.regs); + dev_info(&rmi_dev->dev, " single tap: %d.\n", stick->query.gestures.has_single_tap); + dev_info(&rmi_dev->dev, " tap & hold: %d.\n", stick->query.gestures.has_tap_and_hold); + dev_info(&rmi_dev->dev, " double tap: %d.\n", stick->query.gestures.has_double_tap); + dev_info(&rmi_dev->dev, " early tap: %d.\n", stick->query.gestures.has_early_tap); + dev_info(&rmi_dev->dev, " press: %d.\n", stick->query.gestures.has_press); + } + if (stick->query.general.has_absolute) { + stick->abs_data_address = *next_data_reg; + *next_data_reg += sizeof(stick->data.abs.regs); + } + if (stick->query.general.has_relative) { + stick->rel_data_address = *next_data_reg; + *next_data_reg += sizeof(stick->data.rel.regs); + } + if (stick->query.general.has_gestures) { + stick->gesture_data_address = *next_data_reg; + *next_data_reg += sizeof(stick->data.gestures.regs); + } + + return retval; +} + +static int f17_initialize(struct rmi_function_container *fc) +{ + struct rmi_device *rmi_dev = fc->rmi_dev; + struct rmi_f17_device_data *f17 = fc->data; + int i; + int retval; + u16 next_query_reg = fc->fd.query_base_addr; + u16 next_data_reg = fc->fd.data_base_addr; + u16 next_control_reg = fc->fd.control_base_addr; + + dev_info(&fc->dev, "Intializing F17 values."); + + retval = rmi_read_block(fc->rmi_dev, fc->fd.query_base_addr, + f17->query.regs, sizeof(f17->query.regs)); + if (retval < 0) { + dev_err(&fc->dev, "Failed to read query register.\n"); + return retval; + } + dev_info(&fc->dev, "Found F17 with %d sticks.\n", + f17->query.number_of_sticks + 1); + next_query_reg += sizeof(f17->query.regs); + + retval = rmi_read_block(rmi_dev, fc->fd.command_base_addr, + f17->commands.regs, sizeof(f17->commands.regs)); + if (retval < 0) { + dev_err(&fc->dev, "Failed to read command register.\n"); + return retval; + } + + f17->control_address = fc->fd.control_base_addr; + retval = f17_read_control_parameters(rmi_dev, f17); + if (retval < 0) { + dev_err(&fc->dev, "Failed to initialize F17 control params.\n"); + return retval; + } + + for (i = 0; i < f17->query.number_of_sticks + 1; i++) { + f17->sticks[i].index = i; + retval = f17_init_stick(rmi_dev, &f17->sticks[i], + &next_query_reg, &next_data_reg, + &next_control_reg); + if (!retval) { + dev_err(&fc->dev, "Failed to init stick %d.\n", i); + return retval; + } + } + + return retval; +} + +static int f17_register_stick(struct rmi_function_container *fc, + struct rmi_f17_stick_data *stick) { + struct rmi_device *rmi_dev = fc->rmi_dev; + int retval = 0; + + if (stick->query.general.has_absolute) { + struct input_dev *input_dev; + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&rmi_dev->dev, "Failed to allocate stick device %d.\n", + stick->index); + return -ENOMEM; + } + + snprintf(stick->input_name, sizeof(stick->input_name), + "RMI F%02x Stick %d", 0x17, stick->index); + snprintf(stick->input_phys, sizeof(stick->input_phys), + "sensor00fn%02x/stick%d", 0x17, stick->index); + input_dev->name = stick->input_name; + input_dev->phys = stick->input_phys; + input_dev->dev.parent = &fc->dev; + input_set_drvdata(input_dev, stick); + + retval = input_register_device(input_dev); + if (retval < 0) { + dev_err(&rmi_dev->dev, "Failed to register stick device %d.\n", + stick->index); + goto error_free_device; + } + stick->input = input_dev; + } + + if (stick->query.general.has_relative) { + struct input_dev *input_dev_mouse; + /*create input device for mouse events */ + input_dev_mouse = input_allocate_device(); + if (!input_dev_mouse) { + retval = -ENOMEM; + goto error_free_device; + } + + snprintf(stick->mouse_name, sizeof(stick->mouse_name), + "RMI F%02x Mouse %d", 0x17, stick->index); + snprintf(stick->mouse_phys, sizeof(stick->mouse_name), + "sensor00fn%02x/mouse%d", 0x17, stick->index); + input_dev_mouse->name = stick->mouse_name; + input_dev_mouse->phys = stick->mouse_phys; + input_dev_mouse->dev.parent = &fc->dev; + + input_dev_mouse->id.vendor = 0x18d1; + input_dev_mouse->id.product = 0x0210; + input_dev_mouse->id.version = 0x0100; + + set_bit(EV_REL, input_dev_mouse->evbit); + set_bit(REL_X, input_dev_mouse->relbit); + set_bit(REL_Y, input_dev_mouse->relbit); + + set_bit(BTN_MOUSE, input_dev_mouse->evbit); + /* Register device's buttons and keys */ + set_bit(EV_KEY, input_dev_mouse->evbit); + set_bit(BTN_LEFT, input_dev_mouse->keybit); + set_bit(BTN_MIDDLE, input_dev_mouse->keybit); + set_bit(BTN_RIGHT, input_dev_mouse->keybit); + + retval = input_register_device(input_dev_mouse); + if (retval < 0) + goto error_free_device; + stick->mouse = input_dev_mouse; + } + + return 0; + +error_free_device: + if (stick->input) { + input_free_device(stick->input); + stick->input = NULL; + } + if (stick->mouse) { + input_free_device(stick->mouse); + stick->mouse = NULL; + } + return retval; +} + +static int f17_register_devices(struct rmi_function_container *fc) +{ + struct rmi_f17_device_data *f17 = fc->data; + int i; + int retval = 0; + + for (i = 0; i < f17->query.number_of_sticks + 1 && !retval; i++) { + retval = f17_register_stick(fc, &f17->sticks[i]); + } + + return retval; +} + +static int f17_create_sysfs(struct rmi_function_container *fc) +{ + int attr_count = 0; + int rc; + + dev_dbg(&fc->dev, "Creating sysfs files.\n"); + /* Set up sysfs device attributes. */ + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { + if (sysfs_create_file + (&fc->dev.kobj, &attrs[attr_count].attr) < 0) { + dev_err(&fc->dev, + "Failed to create sysfs file for %s.", + attrs[attr_count].attr.name); + rc = -ENODEV; + goto err_remove_sysfs; + } + } + + return 0; + +err_remove_sysfs: + for (attr_count--; attr_count >= 0; attr_count--) + sysfs_remove_file(&fc->dev.kobj, &attrs[attr_count].attr); + return rc; + +} + +static int f17_config(struct rmi_function_container *fc) +{ + struct rmi_f17_device_data *f17 = fc->data; + int retval; + int i; + + retval = rmi_write_block(fc->rmi_dev, f17->control_address, + f17->controls.regs, sizeof(f17->controls.regs)); + if (retval < 0) { + dev_err(&fc->dev, "Could not write stick controls to 0x%04x\n", + f17->control_address); + return retval; + } + +#if 0 + if (f17->query.has_relative) { + retval = rmi_write_block(fc->rmi_dev, + f17->relative_control_address, + f17->controls.relative.regs, + sizeof(f17->controls.relative.regs)); + if (retval < 0) { + dev_err(&fc->dev, "Could not write stick controls to 0x%04x\n", + f17->control_address); + return retval; + } + } +#endif + + for (i = 0; i < f17->query.number_of_sticks + 1; i++) { + // TODO: Configure each styk + } + + return retval; +} + +static int f17_reset(struct rmi_function_container *fc) +{ + /* we do nothing here */ + return 0; +} + +static void f17_remove(struct rmi_function_container *fc) +{ + struct rmi_f17_device_data *f17 = fc->data; + int i = 0; + + for (i = 0; i < ARRAY_SIZE(attrs); i++) + sysfs_remove_file(&fc->dev.kobj, &attrs[i].attr); + + for (i = 0; i < f17->query.number_of_sticks + 1; i++) { + input_unregister_device(f17->sticks[i].input); + } + + f17_free_memory(fc); +} + +static int f17_process_stick(struct rmi_device *rmi_dev, + struct rmi_f17_stick_data *stick) { + int retval = 0; + + if (stick->query.general.has_absolute) { + retval = rmi_read_block(rmi_dev, stick->abs_data_address, + stick->data.abs.regs, sizeof(stick->data.abs.regs)); + if (retval < 0) { + dev_err(&rmi_dev->dev, "Failed to read abs data for stick %d.\n", + stick->index); + goto error_exit; + } + } + if (stick->query.general.has_relative) { + retval = rmi_read_block(rmi_dev, stick->rel_data_address, + stick->data.rel.regs, sizeof(stick->data.rel.regs)); + if (retval < 0) { + dev_err(&rmi_dev->dev, "Failed to read rel data for stick %d.\n", + stick->index); + goto error_exit; + } + dev_info(&rmi_dev->dev, "Reporting dX: %d, dy: %d\n", stick->data.rel.x_delta, stick->data.rel.y_delta); + input_report_rel(stick->mouse, REL_X, stick->data.rel.x_delta); + input_report_rel(stick->mouse, REL_Y, stick->data.rel.y_delta); + } + if (stick->query.general.has_gestures) { + retval = rmi_read_block(rmi_dev, stick->gesture_data_address, + stick->data.gestures.regs, sizeof(stick->data.gestures.regs)); + if (retval < 0) { + dev_err(&rmi_dev->dev, "Failed to read gesture data for stick %d.\n", + stick->index); + goto error_exit; + } + } + retval = 0; + +error_exit: + if (stick->input) + input_sync(stick->input); + if (stick->mouse) + input_sync(stick->mouse); + return retval; +} + +static int f17_attention(struct rmi_function_container *fc, u8 *irq_bits) +{ + struct rmi_device *rmi_dev = fc->rmi_dev; + struct rmi_f17_device_data *f17 = fc->data; + int i; + int retval = 0; + + for (i = 0; i < f17->query.number_of_sticks + 1 && !retval; i++) { + retval = f17_process_stick(rmi_dev, &f17->sticks[i]); + } + + return retval; +} + +static struct rmi_function_handler function_handler = { + .func = 0x17, + .init = f17_init, + .config = f17_config, + .reset = f17_reset, + .attention = f17_attention, + .remove = f17_remove +}; + +static int __init f17_module_init(void) +{ + int error; + + error = rmi_register_function_driver(&function_handler); + if (error < 0) { + pr_err("%s: register failed!\n", __func__); + return error; + } + + return 0; +} + +static void f17_module_exit(void) +{ + rmi_unregister_function_driver(&function_handler); +} + + +static ssize_t f17_rezero_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_f17_device_data *f17; + + fc = to_rmi_function_container(dev); + f17 = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", + f17->commands.rezero); + +} + +static ssize_t f17_rezero_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct rmi_function_container *fc; + struct rmi_f17_device_data *data; + unsigned int new_value; + int len; + + fc = to_rmi_function_container(dev); + data = fc->data; + len = sscanf(buf, "%u", &new_value); + if (new_value != 0 && new_value != 1) { + dev_err(dev, + "%s: Error - rezero is not a valid value 0x%x.\n", + __func__, new_value); + return -EINVAL; + } + data->commands.rezero = new_value; + len = rmi_write(fc->rmi_dev, fc->fd.command_base_addr, + data->commands.rezero); + + if (len < 0) { + dev_err(dev, "%s : Could not write rezero to 0x%x\n", + __func__, fc->fd.command_base_addr); + return -EINVAL; + } + return count; +} + + +module_init(f17_module_init); +module_exit(f17_module_exit); + +MODULE_AUTHOR("Christopher Heiny "); +MODULE_DESCRIPTION("RMI F17 module"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(RMI_DRIVER_VERSION); diff --git a/drivers/input/touchscreen/rmi4/rmi_f19.c b/drivers/input/touchscreen/rmi4/rmi_f19.c new file mode 100755 index 000000000000..37b341957885 --- /dev/null +++ b/drivers/input/touchscreen/rmi4/rmi_f19.c @@ -0,0 +1,1505 @@ +/* + * Copyright (c) 2011 Synaptics Incorporated + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include "rmi_driver.h" +#define QUERY_BASE_INDEX 1 +#define MAX_LEN 256 +#define MAX_BUFFER_LEN 80 + +#define SENSOR_MAP_MIN 0 +#define SENSOR_MAP_MAX 127 +#define SENSITIVITY_ADJ_MIN 0 +#define SENSITIVITY_ADJ_MAX 31 +#define HYSTERESIS_THRESHOLD_MIN 0 +#define HYSTERESIS_THRESHOLD_MAX 15 + +union f19_0d_query { + struct { + u8 configurable:1; + u8 has_sensitivity_adjust:1; + u8 has_hysteresis_threshold:1; + u8 reserved_1:5; + + u8 button_count:5; + u8 reserved_2:3; + }; + u8 regs[2]; +}; + +union f19_0d_control_0 { + struct { + u8 button_usage:2; + u8 filter_mode:2; + }; + u8 regs[1]; +}; + +struct f19_0d_control_3 { + u8 sensor_map_button:7; + /*u8 sensitivity_button;*/ +}; + +struct f19_0d_control_5 { + u8 sensitivity_adj:5; +}; + +struct f19_0d_control_6 { + u8 hysteresis_threshold:4; +}; + +struct f19_0d_control { + union f19_0d_control_0 general_control; + u8 *int_enabled_button; + u8 *single_button; + struct f19_0d_control_3 *sensor_map; + struct f19_0d_control_5 all_button_sensitivity_adj; + struct f19_0d_control_6 all_button_hysteresis_threshold; +}; +/* data specific to fn $19 that needs to be kept around */ +struct f19_data { + struct f19_0d_control button_control; + union f19_0d_query button_query; + u8 button_rezero; + unsigned char button_count; + unsigned char button_bitmask_size; + unsigned char *button_data_buffer; + unsigned short *button_map; + char input_name[MAX_LEN]; + char input_phys[MAX_LEN]; + struct input_dev *input; + int general_control_address; + int int_enable_button_address; + int single_button_address; + int sensor_map_address; + int all_button_sensitivity_address; + int all_button_threshold_address; +}; + +static ssize_t rmi_f19_button_count_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t rmi_f19_button_map_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t rmi_f19_button_map_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t rmi_f19_rezero_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t rmi_f19_rezero_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t rmi_f19_has_hysteresis_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t rmi_f19_has_sensitivity_adjust_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t rmi_f19_configurable_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t rmi_f19_filter_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t rmi_f19_filter_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t rmi_f19_button_usage_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t rmi_f19_button_usage_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t rmi_f19_interrupt_enable_button_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t rmi_f19_interrupt_enable_button_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t rmi_f19_single_button_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t rmi_f19_single_button_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t rmi_f19_sensor_map_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t rmi_f19_sensor_map_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t rmi_f19_sensitivity_adjust_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t rmi_f19_sensitivity_adjust_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t rmi_f19_hysteresis_threshold_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t rmi_f19_hysteresis_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + + + +static int rmi_f19_alloc_memory(struct rmi_function_container *fc); + +static void rmi_f19_free_memory(struct rmi_function_container *fc); + +static int rmi_f19_initialize(struct rmi_function_container *fc); + +static int rmi_f19_register_device(struct rmi_function_container *fc); + +static int rmi_f19_create_sysfs(struct rmi_function_container *fc); + +static int rmi_f19_config(struct rmi_function_container *fc); + +static int rmi_f19_reset(struct rmi_function_container *fc); + +static struct device_attribute attrs[] = { + __ATTR(button_count, RMI_RO_ATTR, + rmi_f19_button_count_show, rmi_store_error), + __ATTR(button_map, RMI_RW_ATTR, + rmi_f19_button_map_show, rmi_f19_button_map_store), + __ATTR(rezero, RMI_RW_ATTR, + rmi_f19_rezero_show, rmi_f19_rezero_store), + __ATTR(has_hysteresis_threshold, RMI_RO_ATTR, + rmi_f19_has_hysteresis_threshold_show, rmi_store_error), + __ATTR(has_sensitivity_adjust, RMI_RO_ATTR, + rmi_f19_has_sensitivity_adjust_show, rmi_store_error), + __ATTR(configurable, RMI_RO_ATTR, + rmi_f19_configurable_show, rmi_store_error), + __ATTR(filter_mode, RMI_RW_ATTR, + rmi_f19_filter_mode_show, rmi_f19_filter_mode_store), + __ATTR(button_usage, RMI_RW_ATTR, + rmi_f19_button_usage_show, rmi_f19_button_usage_store), + __ATTR(interrupt_enable_button, RMI_RW_ATTR, + rmi_f19_interrupt_enable_button_show, + rmi_f19_interrupt_enable_button_store), + __ATTR(single_button, RMI_RW_ATTR, + rmi_f19_single_button_show, rmi_f19_single_button_store), + __ATTR(sensor_map, RMI_RW_ATTR, + rmi_f19_sensor_map_show, rmi_f19_sensor_map_store), + __ATTR(sensitivity_adjust, RMI_RW_ATTR, + rmi_f19_sensitivity_adjust_show, + rmi_f19_sensitivity_adjust_store), + __ATTR(hysteresis_threshold, RMI_RW_ATTR, + rmi_f19_hysteresis_threshold_show, + rmi_f19_hysteresis_threshold_store) +}; + + +int rmi_f19_read_control_parameters(struct rmi_device *rmi_dev, + struct f19_data *f19) +{ + int error = 0; + struct f19_0d_control *button_control = &f19->button_control; + union f19_0d_query *button_query = &f19->button_query; + + int ctrl_base_addr = f19->general_control_address; + + error = rmi_read_block(rmi_dev, ctrl_base_addr, + (u8 *)&button_control->general_control, + sizeof(union f19_0d_control_0)); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read f19_0d_control_0, code:" + " %d.\n", error); + return error; + } + ctrl_base_addr = ctrl_base_addr + + sizeof(union f19_0d_control_0); + + f19->int_enable_button_address = ctrl_base_addr; + if (button_control->int_enabled_button) { + error = rmi_read_block(rmi_dev, ctrl_base_addr, + button_control->int_enabled_button, + f19->button_bitmask_size); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read f19_0d_control_2," + " code: %d.\n", error); + return error; + } + ctrl_base_addr = ctrl_base_addr + f19->button_bitmask_size; + } + + if (button_control->single_button) { + f19->single_button_address = ctrl_base_addr; + error = rmi_read_block(rmi_dev, ctrl_base_addr, + button_control->single_button, + f19->button_bitmask_size); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read f19_0d_control_2," + " code: %d.\n", error); + return error; + } + ctrl_base_addr = ctrl_base_addr + f19->button_bitmask_size; + } + + if (button_control->sensor_map) { + f19->sensor_map_address = ctrl_base_addr; + error = rmi_read_block(rmi_dev, ctrl_base_addr, + (u8 *)(button_control->sensor_map), + sizeof(struct f19_0d_control_3)*f19->button_count); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read f19_0d_control_3," + " code: %d.\n", error); + return error; + } + ctrl_base_addr = ctrl_base_addr + + (sizeof(struct f19_0d_control_3)*f19->button_count); + ctrl_base_addr += (sizeof(u8)*f19->button_count); + } + + if (button_query->has_sensitivity_adjust) { + f19->all_button_sensitivity_address = ctrl_base_addr; + error = rmi_read_block(rmi_dev, ctrl_base_addr, + (u8 *)&button_control-> + all_button_sensitivity_adj, + sizeof(struct f19_0d_control_5)); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read f19_0d_control_5," + " code: %d.\n", error); + return error; + } + ctrl_base_addr = ctrl_base_addr + + sizeof(struct f19_0d_control_5); + } + if (button_query->has_hysteresis_threshold) { + f19->all_button_threshold_address = ctrl_base_addr; + error = rmi_read_block(rmi_dev, ctrl_base_addr, + (u8 *)&button_control-> + all_button_hysteresis_threshold, + sizeof(struct f19_0d_control_6)); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read f19_0d_control_6," + " code: %d.\n", error); + return error; + } + ctrl_base_addr = ctrl_base_addr + + sizeof(struct f19_0d_control_6); + } + return 0; +} + + +static int rmi_f19_init(struct rmi_function_container *fc) +{ + int rc; + + rc = rmi_f19_alloc_memory(fc); + if (rc < 0) + goto err_free_data; + + rc = rmi_f19_initialize(fc); + if (rc < 0) + goto err_free_data; + + rc = rmi_f19_register_device(fc); + if (rc < 0) + goto err_free_data; + + rc = rmi_f19_create_sysfs(fc); + if (rc < 0) + goto err_free_data; + + return 0; + +err_free_data: + rmi_f19_free_memory(fc); + + return rc; +} + + +static int rmi_f19_alloc_memory(struct rmi_function_container *fc) +{ + struct f19_data *f19; + int rc; + + f19 = kzalloc(sizeof(struct f19_data), GFP_KERNEL); + if (!f19) { + dev_err(&fc->dev, "Failed to allocate function data.\n"); + return -ENOMEM; + } + fc->data = f19; + + rc = rmi_read_block(fc->rmi_dev, + fc->fd.query_base_addr, + (u8 *)&f19->button_query, + sizeof(union f19_0d_query)); + if (rc < 0) { + dev_err(&fc->dev, "Failed to read query register.\n"); + return rc; + } + + f19->button_count = f19->button_query.button_count; + f19->button_bitmask_size = sizeof(u8)*(f19->button_count + 7) / 8; + f19->button_data_buffer = + kcalloc(f19->button_bitmask_size, + sizeof(unsigned char), GFP_KERNEL); + if (!f19->button_data_buffer) { + dev_err(&fc->dev, "Failed to allocate button data buffer.\n"); + return -ENOMEM; + } + + f19->button_map = kcalloc(f19->button_count, + sizeof(unsigned short), GFP_KERNEL); + if (!f19->button_map) { + dev_err(&fc->dev, "Failed to allocate button map.\n"); + return -ENOMEM; + } + + f19->button_control.int_enabled_button = + kzalloc(f19->button_bitmask_size, GFP_KERNEL); + if (!f19->button_control.int_enabled_button) { + dev_err(&fc->dev, "Failed to allocate interrupt button.\n"); + return -ENOMEM; + } + + f19->button_control.single_button = + kzalloc(f19->button_bitmask_size, GFP_KERNEL); + if (!f19->button_control.single_button) { + dev_err(&fc->dev, "Failed to allocate" + " single button.\n"); + return -ENOMEM; + } + + f19->button_control.sensor_map = kzalloc(f19->button_count * + sizeof(struct f19_0d_control_3), GFP_KERNEL); + if (!f19->button_control.sensor_map) { + dev_err(&fc->dev, "Failed to allocate" + " f19_0d_control_3.\n"); + return -ENOMEM; + } + + return 0; +} + + + +static void rmi_f19_free_memory(struct rmi_function_container *fc) +{ + struct f19_data *f19 = fc->data; + + if (f19) { + kfree(f19->button_data_buffer); + kfree(f19->button_map); + kfree(f19->button_control.int_enabled_button); + kfree(f19->button_control.single_button); + kfree(f19->button_control.sensor_map); + kfree(f19); + fc->data = NULL; + } +} + + +static int rmi_f19_initialize(struct rmi_function_container *fc) +{ + struct rmi_device *rmi_dev = fc->rmi_dev; + struct rmi_device_platform_data *pdata; + struct f19_data *f19 = fc->data; + int i; + int rc; + + dev_info(&fc->dev, "Intializing F19 values."); + + /* initial all default values for f19 data here */ + rc = rmi_read(rmi_dev, fc->fd.command_base_addr, + (u8 *)&f19->button_rezero); + if (rc < 0) { + dev_err(&fc->dev, "Failed to read command register.\n"); + return rc; + } + f19->button_rezero = f19->button_rezero & 1; + + pdata = to_rmi_platform_data(rmi_dev); + if (pdata) { + if (!pdata->button_map) { + dev_warn(&fc->dev, "%s - button_map is NULL", __func__); + } else if (pdata->button_map->nbuttons != f19->button_count) { + dev_warn(&fc->dev, + "Platformdata button map size (%d) != number " + "of buttons on device (%d) - ignored.\n", + pdata->button_map->nbuttons, + f19->button_count); + } else if (!pdata->button_map->map) { + dev_warn(&fc->dev, + "Platformdata button map is missing!\n"); + } else { + for (i = 0; i < pdata->button_map->nbuttons; i++) + f19->button_map[i] = pdata->button_map->map[i]; + } + } + + f19->general_control_address = fc->fd.control_base_addr; + rc = rmi_f19_read_control_parameters(rmi_dev, f19); + if (rc < 0) { + dev_err(&fc->dev, + "Failed to initialize F19 control params.\n"); + return rc; + } + + return 0; +} + + + +static int rmi_f19_register_device(struct rmi_function_container *fc) +{ + struct rmi_device *rmi_dev = fc->rmi_dev; + struct input_dev *input_dev; + struct f19_data *f19 = fc->data; + int i; + int rc; + + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&fc->dev, "Failed to allocate input device.\n"); + return -ENOMEM; + } + + f19->input = input_dev; + snprintf(f19->input_name, MAX_LEN, "%sfn%02x", dev_name(&rmi_dev->dev), + fc->fd.function_number); + input_dev->name = f19->input_name; + snprintf(f19->input_phys, MAX_LEN, "%s/input0", input_dev->name); + input_dev->phys = f19->input_phys; + input_dev->dev.parent = &rmi_dev->dev; + input_set_drvdata(input_dev, f19); + + /* Set up any input events. */ + set_bit(EV_SYN, input_dev->evbit); + set_bit(EV_KEY, input_dev->evbit); + /* set bits for each button... */ + for (i = 0; i < f19->button_count; i++) + set_bit(f19->button_map[i], input_dev->keybit); + rc = input_register_device(input_dev); + if (rc < 0) { + dev_err(&fc->dev, "Failed to register input device.\n"); + goto error_free_device; + } + + return 0; + +error_free_device: + input_free_device(input_dev); + + return rc; +} + + +static int rmi_f19_create_sysfs(struct rmi_function_container *fc) +{ + int attr_count = 0; + int rc; + char *name; + struct f19_data *data; + union f19_0d_query *button_query; + + data = fc->data; + button_query = &data->button_query; + + dev_dbg(&fc->dev, "Creating sysfs files.\n"); + /* Set up sysfs device attributes. */ + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { + name = (char *) attrs[attr_count].attr.name; + if (!button_query->has_sensitivity_adjust && + !strcmp(name, "sensitivity_adjust")) + continue; + if (!button_query->has_hysteresis_threshold && + !strcmp(name, "hysteresis_threshold")) + continue; + if (sysfs_create_file + (&fc->dev.kobj, &attrs[attr_count].attr) < 0) { + dev_err(&fc->dev, + "Failed to create sysfs file for %s.", + attrs[attr_count].attr.name); + rc = -ENODEV; + goto err_remove_sysfs; + } + } + + return 0; + +err_remove_sysfs: + for (attr_count--; attr_count >= 0; attr_count--) + sysfs_remove_file(&fc->dev.kobj, + &attrs[attr_count].attr); + return rc; + +} + + + +static int rmi_f19_config(struct rmi_function_container *fc) +{ + struct f19_data *data; + int retval; + union f19_0d_query *button_query; + + data = fc->data; + button_query = &data->button_query; + retval = rmi_write_block(fc->rmi_dev, data->general_control_address, + (u8 *)&data->button_control.general_control, + sizeof(union f19_0d_control_0)); + if (retval < 0) { + dev_err(&fc->dev, "%s : Could not write general_control to 0x%x\n", + __func__, fc->fd.control_base_addr); + return retval; + } + + retval = rmi_write_block(fc->rmi_dev, data->int_enable_button_address, + data->button_control.int_enabled_button, + data->button_bitmask_size); + if (retval < 0) { + dev_err(&fc->dev, "%s : Could not write interrupt_enable_store" + " to 0x%x\n", __func__, + data->int_enable_button_address); + return retval; + } + + retval = rmi_write_block(fc->rmi_dev, data->single_button_address, + data->button_control.single_button, + data->button_bitmask_size); + if (retval < 0) { + dev_err(&fc->dev, + "%s : Could not write interrupt_enable_store to" + " 0x%x\n", __func__, + data->single_button_address); + return -EINVAL; + } + + retval = rmi_write_block(fc->rmi_dev, data->sensor_map_address, + (u8 *)data->button_control.sensor_map, + sizeof(struct f19_0d_control_3)*data->button_count); + if (retval < 0) { + dev_err(&fc->dev, "%s : Could not sensor_map_store to 0x%x\n", + __func__, data->sensor_map_address); + return -EINVAL; + } + if (button_query->has_sensitivity_adjust) { + retval = rmi_write_block(fc->rmi_dev, + data->all_button_sensitivity_address, + (u8 *)&data->button_control.all_button_sensitivity_adj, + sizeof(struct f19_0d_control_5)); + if (retval < 0) { + dev_err(&fc->dev, "%s : Could not sensitivity_adjust_store to" + " 0x%x\n", __func__, + data->all_button_sensitivity_address); + return retval; + } + } + if (!button_query->has_hysteresis_threshold) { + retval = rmi_write_block(fc->rmi_dev, + data->all_button_threshold_address, + (u8 *)&data->button_control. + all_button_hysteresis_threshold, + sizeof(struct f19_0d_control_6)); + if (retval < 0) { + dev_err(&fc->dev, "%s : Could not write all_button hysteresis " + "threshold to 0x%x\n", __func__, + data->all_button_threshold_address); + return -EINVAL; + } + } + return 0; +} + + +static int rmi_f19_reset(struct rmi_function_container *fc) +{ + /* we do nnothing here */ + return 0; +} + + +static void rmi_f19_remove(struct rmi_function_container *fc) +{ + struct f19_data *f19 = fc->data; + int attr_count = 0; + + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) + sysfs_remove_file(&fc->dev.kobj, + &attrs[attr_count].attr); + + input_unregister_device(f19->input); + + rmi_f19_free_memory(fc); +} + +int rmi_f19_attention(struct rmi_function_container *fc, u8 *irq_bits) +{ + struct rmi_device *rmi_dev = fc->rmi_dev; + struct f19_data *f19 = fc->data; + int data_base_addr = fc->fd.data_base_addr; + int error; + int button; + + /* Read the button data. */ + + error = rmi_read_block(rmi_dev, data_base_addr, f19->button_data_buffer, + f19->button_bitmask_size); + if (error < 0) { + dev_err(&fc->dev, "%s: Failed to read button data registers.\n", + __func__); + return error; + } + + /* Generate events for buttons that change state. */ + for (button = 0; button < f19->button_count; + button++) { + int button_reg; + int button_shift; + bool button_status; + + /* determine which data byte the button status is in */ + button_reg = button / 8; + /* bit shift to get button's status */ + button_shift = button % 8; + button_status = + ((f19->button_data_buffer[button_reg] >> button_shift) + & 0x01) != 0; + + /* if the button state changed from the last time report it + * and store the new state */ + /* Generate an event here. */ + input_report_key(f19->input, f19->button_map[button], + button_status); + } + + input_sync(f19->input); /* sync after groups of events */ + return 0; +} + +static struct rmi_function_handler function_handler = { + .func = 0x19, + .init = rmi_f19_init, + .config = rmi_f19_config, + .reset = rmi_f19_reset, + .attention = rmi_f19_attention, + .remove = rmi_f19_remove +}; + +static int __init rmi_f19_module_init(void) +{ + int error; + + error = rmi_register_function_driver(&function_handler); + if (error < 0) { + pr_err("%s: register failed!\n", __func__); + return error; + } + + return 0; +} + +static void rmi_f19_module_exit(void) +{ + rmi_unregister_function_driver(&function_handler); +} + +static ssize_t rmi_f19_filter_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f19_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", + data->button_control.general_control.filter_mode); + +} + +static ssize_t rmi_f19_filter_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct f19_data *data; + unsigned int new_value; + unsigned int old_value; + int result; + + fc = to_rmi_function_container(dev); + data = fc->data; + if (sscanf(buf, "%u", &new_value) < 1) { + dev_err(dev, + "%s: Error - filter_mode_store has an invalid len.\n", + __func__); + return -EINVAL; + } + + if (new_value < 0 || new_value > 4) { + dev_err(dev, "%s: Error - filter_mode_store has an invalid value %d.\n", + __func__, new_value); + return -EINVAL; + } + old_value = data->button_control.general_control.filter_mode; + data->button_control.general_control.filter_mode = new_value; + result = rmi_write_block(fc->rmi_dev, data->general_control_address, + (u8 *)&(data->button_control.general_control), + sizeof(union f19_0d_control_0)); + if (result < 0) { + data->button_control.general_control.filter_mode = old_value; + dev_err(dev, "%s : Could not write filter_mode_store to 0x%x\n", + __func__, fc->fd.control_base_addr); + return result; + } + + return count; +} + +static ssize_t rmi_f19_button_usage_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f19_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", + data->button_control.general_control.button_usage); + +} + +static ssize_t rmi_f19_button_usage_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct f19_data *data; + unsigned int new_value; + unsigned int old_value; + int result; + + fc = to_rmi_function_container(dev); + data = fc->data; + if (sscanf(buf, "%u", &new_value) < 1) { + dev_err(dev, + "%s: Error - button_usage_store has an invalid len.\n", + __func__); + return -EINVAL; + } + + if (new_value < 0 || new_value > 4) { + dev_err(dev, "%s: Error - button_usage_store has an invalid value %d.\n", + __func__, new_value); + return -EINVAL; + } + old_value = data->button_control.general_control.button_usage; + data->button_control.general_control.button_usage = new_value; + result = rmi_write_block(fc->rmi_dev, data->general_control_address, + (u8 *)&(data->button_control.general_control), + sizeof(union f19_0d_control_0)); + if (result < 0) { + data->button_control.general_control.button_usage = old_value; + dev_err(dev, "%s : Could not write button_usage_store to 0x%x\n", + __func__, fc->fd.control_base_addr); + return result; + } + + return count; + +} + +static ssize_t rmi_f19_interrupt_enable_button_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f19_data *data; + int i, len, total_len = 0; + char *current_buf = buf; + fc = to_rmi_function_container(dev); + data = fc->data; + + /* loop through each button map value and copy its + * string representation into buf */ + for (i = 0; i < data->button_count; i++) { + int button_reg; + int button_shift; + int interrupt_button; + + button_reg = i / 8; + button_shift = i % 8; + interrupt_button = + ((data->button_control.int_enabled_button[button_reg] + >> button_shift) & 0x01); + + /* get next button mapping value and write it to buf */ + len = snprintf(current_buf, PAGE_SIZE - total_len, + "%u ", interrupt_button); + /* bump up ptr to next location in buf if the + * snprintf was valid. Otherwise issue an error + * and return. */ + if (len > 0) { + current_buf += len; + total_len += len; + } else { + dev_err(dev, "%s: Failed to build interrupt button buffer, code = %d.\n", + __func__, len); + return snprintf(buf, PAGE_SIZE, "unknown\n"); + } + } + len = snprintf(current_buf, PAGE_SIZE - total_len, "\n"); + if (len > 0) + total_len += len; + else + dev_warn(dev, "%s: Failed to append carriage return.\n", __func__); + return total_len; + +} + +static ssize_t rmi_f19_interrupt_enable_button_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct f19_data *data; + int i; + int button_count = 0; + int retval = count; + int button_reg = 0; + u8 *new_value; + + fc = to_rmi_function_container(dev); + data = fc->data; + new_value = kzalloc(data->button_bitmask_size, GFP_KERNEL); + if (!new_value) { + dev_err(dev, "%s: Error - failed to allocate button interrupt enable.\n", __func__); + return -ENOMEM; + } + for (i = 0; i < data->button_count && *buf != 0; + i++, buf += 2) { + int button_shift; + int button; + int result; + + button_reg = i / 8; + button_shift = i % 8; + /* get next button mapping value and store and bump up to + * point to next item in buf */ + result = sscanf(buf, "%u", &button); + + if ((result != 1) || (button != 0 && button != 1)) { + dev_err(dev, + "%s: Error-int enable button for button %d is not a valid value 0x%x.\n", + __func__, i, button); + return -EINVAL; + } + + if (button) + new_value[button_reg] |= (1 << button_shift); + + button_count++; + } + + /* Make sure the button count matches */ + if (button_count != data->button_count) { + dev_err(dev, + "%s: Error-int enable button count of %d doesn't match device button count of %d.\n", + __func__, button_count, data->button_count); + kfree(new_value); + return -EINVAL; + } + + /* write back to the control register */ + retval = rmi_write_block(fc->rmi_dev, data->int_enable_button_address, + new_value, + data->button_bitmask_size); + if (retval < 0) { + dev_err(dev, "%s : Could not write interrupt_enable_store to 0x%x\n", __func__, + data->int_enable_button_address); + kfree(new_value); + return retval; + } + memcpy(data->button_control.int_enabled_button, + new_value, data->button_bitmask_size); + + kfree(new_value); + + return count; +} + +static ssize_t rmi_f19_single_button_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f19_data *data; + int i, len, total_len = 0; + char *current_buf = buf; + + fc = to_rmi_function_container(dev); + data = fc->data; + /* loop through each button map value and copy its + * string representation into buf */ + for (i = 0; i < data->button_count; i++) { + int button_reg; + int button_shift; + int single_button; + + button_reg = i / 8; + button_shift = i % 8; + single_button = + ((data->button_control.single_button[button_reg] + >> button_shift) & 0x01); + + /* get next button mapping value and write it to buf */ + len = snprintf(current_buf, PAGE_SIZE - total_len, + "%u ", single_button); + /* bump up ptr to next location in buf if the + * snprintf was valid. Otherwise issue an error + * and return. */ + if (len > 0) { + current_buf += len; + total_len += len; + } else { + dev_err(dev, "%s: Failed to build signle button buffer, code = %d.\n", + __func__, len); + return snprintf(buf, PAGE_SIZE, "unknown\n"); + } + } + len = snprintf(current_buf, PAGE_SIZE - total_len, "\n"); + if (len > 0) + total_len += len; + else + dev_warn(dev, "%s: Failed to append carriage return.\n", __func__); + + return total_len; + +} + +static ssize_t rmi_f19_single_button_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct f19_data *data; + int i; + int button_count = 0; + int retval = count; + int button_reg = 0; + u8 *new_value; + + fc = to_rmi_function_container(dev); + data = fc->data; + new_value = kzalloc(data->button_bitmask_size, GFP_KERNEL); + if (!new_value) { + dev_err(dev, "%s: Error - failed to allocate button interrupt enable.\n", __func__); + return -ENOMEM; + } + for (i = 0; i < data->button_count && *buf != 0; + i++, buf += 2) { + int button_shift; + int button; + int result; + + button_reg = i / 8; + button_shift = i % 8; + /* get next button mapping value and store and bump up to + * point to next item in buf */ + result = sscanf(buf, "%u", &button); + + if ((result != 1) || (button != 0 && button != 1)) { + dev_err(dev, + "%s: Error - single button for button %d is not a valid value 0x%x.\n", + __func__, i, button); + kfree(new_value); + return -EINVAL; + } + + if (button) { + new_value[button_reg] |= + (1 << button_shift); + } + button_count++; + } + + /* Make sure the button count matches */ + if (button_count != data->button_count) { + dev_err(dev, + "%s:Error-single button count of %d doesn't match device button count of %d\n", + __func__, button_count, data->button_count); + kfree(new_value); + return -EINVAL; + } + /* write back to the control register */ + retval = rmi_write_block(fc->rmi_dev, data->single_button_address, + new_value, + data->button_bitmask_size); + if (retval < 0) { + dev_err(dev, "%s : Could not write interrupt_enable_store to 0x%x\n", + __func__, data->single_button_address); + kfree(new_value); + return -EINVAL; + } + memcpy(data->button_control.single_button, + new_value, data->button_bitmask_size); + + kfree(new_value); + return count; +} + +static ssize_t rmi_f19_sensor_map_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f19_data *data; + int i, len, total_len = 0; + char *current_buf = buf; + + fc = to_rmi_function_container(dev); + data = fc->data; + + for (i = 0; i < data->button_count; i++) { + len = snprintf(current_buf, PAGE_SIZE - total_len, + "%u ", data->button_control.sensor_map[i]. + sensor_map_button); + /* bump up ptr to next location in buf if the + * snprintf was valid. Otherwise issue an error + * and return. */ + if (len > 0) { + current_buf += len; + total_len += len; + } else { + dev_err(dev, "%s: Failed to build sensor map buffer, code = %d.\n", __func__, len); + return snprintf(buf, PAGE_SIZE, "unknown\n"); + } + } + len = snprintf(current_buf, PAGE_SIZE - total_len, "\n"); + if (len > 0) + total_len += len; + else + dev_warn(dev, "%s: Failed to append carriage return.\n", __func__); + return total_len; + + +} + +static ssize_t rmi_f19_sensor_map_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct f19_data *data; + int i; + int retval = count; + int button_count = 0; + u8 *new_value; + char *tail; + char *p = (char *) buf; + fc = to_rmi_function_container(dev); + data = fc->data; + new_value = kzalloc(data->button_count, GFP_KERNEL); + if (!new_value) { + dev_err(dev, "%s: Error - failed to allocate sensor map.\n", __func__); + return -ENOMEM; + } + + if (data->button_query.configurable == 0) { + dev_err(dev, "%s: Error - sensor map is not configuralbe at run-time", __func__); + return -EINVAL; + } + + for (i = 0; i < data->button_count && *p != 0; i++) { + new_value[i] = simple_strtoul(p, &tail, 10); + if (new_value[i] == 0 && p[0] != '0') { + dev_err(dev, "%s: Error - reading sensor map is invalid\n", __func__); + return -EINVAL; + } + if (new_value[i] > INT_MAX) { + dev_err(dev, "%s: Error - reading sensor map is out for range\n", __func__); + return -ERANGE; + } + p = tail; + /* Make sure the key is a valid key */ + if (new_value[i] < SENSOR_MAP_MIN || + new_value[i] > SENSOR_MAP_MAX) { + dev_err(dev, + "%s: Error - sensor map for button %d is not a valid value 0x%x.\n", + __func__, i, new_value[i]); + return -EINVAL; + } + button_count++; + while (p[0] == ' ') + p++; + } + + if (button_count != data->button_count) { + dev_err(dev, + "%s: Error - button map count of %d doesn't match device button count of %d.\n", __func__, button_count, data->button_count); + return -EINVAL; + } + + /* write back to the control register */ + retval = rmi_write_block(fc->rmi_dev, data->sensor_map_address, + new_value, + sizeof(struct f19_0d_control_3)*button_count); + if (retval < 0) { + dev_err(dev, "%s : Could not sensor_map_store to 0x%x\n", + __func__, data->sensor_map_address); + return -EINVAL; + } + memcpy(data->button_control.sensor_map, new_value, data->button_count); + kfree(new_value); + return count; +} + +static ssize_t rmi_f19_sensitivity_adjust_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f19_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", data->button_control. + all_button_sensitivity_adj.sensitivity_adj); + +} + +static ssize_t rmi_f19_sensitivity_adjust_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct f19_data *data; + unsigned int old_value; + unsigned int new_value; + int len; + struct f19_0d_control_5 *all_button_sensitivity_adj; + fc = to_rmi_function_container(dev); + data = fc->data; + all_button_sensitivity_adj = + &data->button_control.all_button_sensitivity_adj; + + if (data->button_query.configurable == 0) { + dev_err(dev, + "%s: Error - sensitivity_adjust is not configuralbe at run-time", __func__); + return -EINVAL; + } + + len = sscanf(buf, "%u", &new_value); + if (len < 1 || new_value < SENSITIVITY_ADJ_MIN || + new_value > SENSITIVITY_ADJ_MAX) + return -EINVAL; + old_value = all_button_sensitivity_adj->sensitivity_adj; + all_button_sensitivity_adj->sensitivity_adj = new_value; + /* write back to the control register */ + len = rmi_write_block(fc->rmi_dev, data->all_button_sensitivity_address, + (u8 *)all_button_sensitivity_adj, + sizeof(struct f19_0d_control_5)); + if (len < 0) { + all_button_sensitivity_adj->sensitivity_adj = old_value; + dev_err(dev, "%s : Could not sensitivity_adjust_store to 0x%x\n", __func__, + data->all_button_sensitivity_address); + return len; + } + + return len; +} + +static ssize_t rmi_f19_hysteresis_threshold_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f19_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", data->button_control. + all_button_hysteresis_threshold.hysteresis_threshold); + +} +static ssize_t rmi_f19_hysteresis_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct f19_data *data; + unsigned int new_value; + unsigned int old_value; + int len; + struct f19_0d_control_6 *all_button_hysteresis_threshold; + + fc = to_rmi_function_container(dev); + data = fc->data; + all_button_hysteresis_threshold = + &data->button_control.all_button_hysteresis_threshold; + len = sscanf(buf, "%u", &new_value); + if (new_value < HYSTERESIS_THRESHOLD_MIN || + new_value > HYSTERESIS_THRESHOLD_MAX) { + dev_err(dev, "%s: Error - hysteresis_threshold_store has an invalid value %d.\n", + __func__, new_value); + return -EINVAL; + } + old_value = all_button_hysteresis_threshold->hysteresis_threshold; + all_button_hysteresis_threshold->hysteresis_threshold = new_value; + /* write back to the control register */ + len = rmi_write_block(fc->rmi_dev, data->all_button_threshold_address, + (u8 *)all_button_hysteresis_threshold, + sizeof(struct f19_0d_control_6)); + if (len < 0) { + all_button_hysteresis_threshold->hysteresis_threshold = + old_value; + dev_err(dev, "%s : Could not write all_button hysteresis threshold to 0x%x.\n", __func__, + data->all_button_threshold_address); + return -EINVAL; + } + return count; +} + +static ssize_t rmi_f19_has_hysteresis_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rmi_function_container *fc; + struct f19_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", + data->button_query.has_hysteresis_threshold); +} + +static ssize_t rmi_f19_has_sensitivity_adjust_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rmi_function_container *fc; + struct f19_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", + data->button_query.has_sensitivity_adjust); +} + +static ssize_t rmi_f19_configurable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rmi_function_container *fc; + struct f19_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", + data->button_query.configurable); +} + +static ssize_t rmi_f19_rezero_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f19_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", + data->button_rezero); + +} + +static ssize_t rmi_f19_rezero_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct rmi_function_container *fc; + struct f19_data *data; + unsigned int new_value; + int len; + + fc = to_rmi_function_container(dev); + data = fc->data; + len = sscanf(buf, "%u", &new_value); + if (new_value != 0 && new_value != 1) { + dev_err(dev, "%s: Error - rezero is not a valid value 0x%x.\n", + __func__, new_value); + return -EINVAL; + } + data->button_rezero = new_value & 1; + len = rmi_write(fc->rmi_dev, fc->fd.command_base_addr, + data->button_rezero); + + if (len < 0) { + dev_err(dev, "%s : Could not write rezero to 0x%x\n", + __func__, fc->fd.command_base_addr); + return -EINVAL; + } + return count; +} + +static ssize_t rmi_f19_button_count_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f19_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->button_count); +} + +static ssize_t rmi_f19_button_map_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + + struct rmi_function_container *fc; + struct f19_data *data; + int i, len, total_len = 0; + char *current_buf = buf; + + fc = to_rmi_function_container(dev); + data = fc->data; + /* loop through each button map value and copy its + * string representation into buf */ + for (i = 0; i < data->button_count; i++) { + /* get next button mapping value and write it to buf */ + len = snprintf(current_buf, PAGE_SIZE - total_len, + "%u ", data->button_map[i]); + /* bump up ptr to next location in buf if the + * snprintf was valid. Otherwise issue an error + * and return. */ + if (len > 0) { + current_buf += len; + total_len += len; + } else { + dev_err(dev, "%s: Failed to build button map buffer, code = %d.\n", __func__, len); + return snprintf(buf, PAGE_SIZE, "unknown\n"); + } + } + len = snprintf(current_buf, PAGE_SIZE - total_len, "\n"); + if (len > 0) + total_len += len; + else + dev_warn(dev, "%s: Failed to append carriage return.\n", + __func__); + return total_len; +} + +static ssize_t rmi_f19_button_map_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct rmi_function_container *fc; + struct f19_data *data; + int i; + int retval = count; + int button_count = 0; + unsigned short *temp_button_map; + char *p = (char *) buf; + char *tail; + + + fc = to_rmi_function_container(dev); + data = fc->data; + temp_button_map = kcalloc(data->button_count, + sizeof(unsigned short), GFP_KERNEL); + + if (!temp_button_map) { + dev_err(dev, "%s: Error - failed to allocate button map.\n", __func__); + return -ENOMEM; + } + /* Do validation on the button map data passed in. Store button + * mappings into a temp buffer and then verify button count and + * data prior to clearing out old button mappings and storing the + * new ones. */ + for (i = 0; i < data->button_count && *p != 0; i++) { + temp_button_map[i] = simple_strtoul(p, &tail, 10); + if (temp_button_map[i] == 0 && p[0] != '0') { + dev_err(dev, "%s: Error - reading button map is invalid\n", __func__); + retval = -EINVAL; + goto err_ret; + } + if (temp_button_map[i] > INT_MAX) { + dev_err(dev, "%s: Error - reading button map is out for range\n", __func__); + retval = -ERANGE; + goto err_ret; + } + p = tail; + + /* Make sure the key is a valid key */ + if (temp_button_map[i] > KEY_MAX) { + dev_err(dev, + "%s: Error - button map for button %d is not avalid value 0x%x.\n", + __func__, i, temp_button_map[i]); + retval = -EINVAL; + goto err_ret; + } + button_count++; + while (p[0] == ' ') + p++; + } + + /* Make sure the button count matches */ + if (button_count != data->button_count) { + dev_err(dev, + "%s: Error - button map count of %d doesn't match device button count of %d.\n", + __func__, button_count, data->button_count); + retval = -EINVAL; + goto err_ret; + } + + /* Clear the key bits for the old button map. */ + for (i = 0; i < button_count; i++) + clear_bit(data->button_map[i], data->input->keybit); + + /* Loop through the key map and set the key bit for the new mapping. */ + for (i = 0; i < button_count; i++) { + data->button_map[i] = temp_button_map[i]; + set_bit(data->button_map[i], data->input->keybit); + } + +err_ret: + kfree(temp_button_map); + return retval; +} + +module_init(rmi_f19_module_init); +module_exit(rmi_f19_module_exit); + +MODULE_AUTHOR("Vivian Ly "); +MODULE_DESCRIPTION("RMI F19 module"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(RMI_DRIVER_VERSION); diff --git a/drivers/input/touchscreen/rmi4/rmi_f1a.c b/drivers/input/touchscreen/rmi4/rmi_f1a.c new file mode 100755 index 000000000000..7e93e2cfbb0c --- /dev/null +++ b/drivers/input/touchscreen/rmi4/rmi_f1a.c @@ -0,0 +1,1809 @@ +/* + * Copyright (c) 2012 Synaptics Incorporated + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include "rmi_driver.h" +#define QUERY_BASE_INDEX 1 +#define MAX_NAME_LEN 256 +#define MAX_BUFFER_LEN 80 + +#define FILTER_MODE_MIN 0 +#define FILTER_MODE_MAX 3 +#define MULTI_BUTTON_REPORT_MIN 0 +#define MULTI_BUTTON_REPORT_MAX 3 +#define TX_RX_BUTTON_MIN 0 +#define TX_RX_BUTTON_MAX 255 +#define THREADHOLD_BUTTON_MIN 0 +#define THREADHOLD_BUTTON_MAX 255 +#define RELEASE_THREADHOLD_BUTTON_MIN 0 +#define RELEASE_THREADHOLD_BUTTON_MAX 255 +#define STRONGEST_BUTTON_HYSTERESIS_MIN 0 +#define STRONGEST_BUTTON_HYSTERESIS_MAX 255 +#define FILTER_STRENGTH_MIN 0 +#define FILTER_STRENGTH_MAX 255 + +union f1a_0d_query { + struct { + u8 max_button_count:3; + u8 reserved:5; + + u8 has_general_control:1; + u8 has_interrupt_enable:1; + u8 has_multibutton_select:1; + u8 has_tx_rx_map:1; + u8 has_perbutton_threshold:1; + u8 has_release_threshold:1; + u8 has_strongestbtn_hysteresis:1; + u8 has_filter_strength:1; + }; + u8 regs[2]; +}; + +union f1a_0d_control_0 { + struct { + u8 multibutton_report:2; + u8 filter_mode:2; + }; + u8 regs[1]; +}; + +struct f1a_0d_control_3_4 { + u8 transmitterbutton; + u8 receiverbutton; +}; + +struct f1a_0d_control { + union f1a_0d_control_0 general_control; + u8 *button_int_enable; + u8 *multi_button; + struct f1a_0d_control_3_4 *electrode_map; + u8 *button_threshold; + u8 button_release_threshold; + u8 strongest_button_hysteresis; + u8 filter_strength; +}; + +/* data specific to fn $1a that needs to be kept around */ +struct f1a_data { + struct f1a_0d_control button_control; + union f1a_0d_query button_query; + u8 button_count; + int button_bitmask_size; + u8 *button_data_buffer; + u8 *button_map; + char input_name[MAX_NAME_LEN]; + char input_phys[MAX_NAME_LEN]; + struct input_dev *input; + int general_control_address; + int button_int_enable_address; + int multi_button_address; + int electrode_map_address; + int button_threshold_address; + int button_release_threshold_address; + int strongest_button_hysteresis_address; + int filter_strength_address; +}; + +static ssize_t rmi_f1a_button_count_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t rmi_f1a_button_map_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t rmi_f1a_button_map_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t rmi_f1a_has_general_control_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t rmi_f1a_has_interrupt_enable_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t rmi_f1a_has_multibutton_select_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t rmi_f1a_has_tx_rx_map_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t rmi_f1a_has_perbutton_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t rmi_f1a_has_release_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t rmi_f1a_has_strongestbtn_hysteresis_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t rmi_f1a_has_filter_strength_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t rmi_f1a_multibutton_report_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t rmi_f1a_multibutton_report_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t rmi_f1a_filter_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t rmi_f1a_filter_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t rmi_f1a_button_int_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t rmi_f1a_button_int_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t rmi_f1a_multibutton_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t rmi_f1a_multibutton_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t rmi_f1a_electrode_map_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t rmi_f1a_electrode_map_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t rmi_f1a_threshold_button_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t rmi_f1a_threshold_button_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t rmi_f1a_button_release_threshold_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t rmi_f1a_button_release_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t rmi_f1a_strongest_button_hysteresis_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t rmi_f1a_strongest_button_hysteresis_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t rmi_f1a_filter_strength_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t rmi_f1a_filter_strength_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static int rmi_f1a_alloc_memory(struct rmi_function_container *fc); + +static void rmi_f1a_free_memory(struct rmi_function_container *fc); + +static int rmi_f1a_initialize(struct rmi_function_container *fc); + +static int rmi_f1a_register_device(struct rmi_function_container *fc); + +static int rmi_f1a_create_sysfs(struct rmi_function_container *fc); + +static int rmi_f1a_config(struct rmi_function_container *fc); + +static int rmi_f1a_reset(struct rmi_function_container *fc); + +static struct device_attribute attrs[] = { + __ATTR(button_count, RMI_RO_ATTR, + rmi_f1a_button_count_show, rmi_store_error), + __ATTR(button_map, RMI_RW_ATTR, + rmi_f1a_button_map_show, rmi_f1a_button_map_store), + __ATTR(has_general_control, RMI_RO_ATTR, + rmi_f1a_has_general_control_show, rmi_store_error), + __ATTR(has_interrupt_enable, RMI_RO_ATTR, + rmi_f1a_has_interrupt_enable_show, rmi_store_error), + __ATTR(has_multibutton_select, RMI_RO_ATTR, + rmi_f1a_has_multibutton_select_show, rmi_store_error), + __ATTR(has_tx_rx_map, RMI_RO_ATTR, + rmi_f1a_has_tx_rx_map_show, rmi_store_error), + __ATTR(has_perbutton_threshold, RMI_RO_ATTR, + rmi_f1a_has_perbutton_threshold_show, rmi_store_error), + __ATTR(has_release_threshold, RMI_RO_ATTR, + rmi_f1a_has_release_threshold_show, rmi_store_error), + __ATTR(has_strongestbtn_hysteresis, RMI_RO_ATTR, + rmi_f1a_has_strongestbtn_hysteresis_show, rmi_store_error), + __ATTR(has_filter_strength, RMI_RO_ATTR, + rmi_f1a_has_filter_strength_show, rmi_store_error), + __ATTR(multibutton_report, RMI_RW_ATTR, + rmi_f1a_multibutton_report_show, + rmi_f1a_multibutton_report_store), + __ATTR(filter_mode, RMI_RW_ATTR, + rmi_f1a_filter_mode_show, rmi_f1a_filter_mode_store), + __ATTR(button_int_enable, RMI_RW_ATTR, + rmi_f1a_button_int_enable_show, + rmi_f1a_button_int_enable_store), + __ATTR(multibutton, RMI_RW_ATTR, + rmi_f1a_multibutton_show, rmi_f1a_multibutton_store), + __ATTR(electrode_map, RMI_RW_ATTR, + rmi_f1a_electrode_map_show, + rmi_f1a_electrode_map_store), + __ATTR(threshold_button, RMI_RW_ATTR, + rmi_f1a_threshold_button_show, + rmi_f1a_threshold_button_store), + __ATTR(button_release_threshold, RMI_RW_ATTR, + rmi_f1a_button_release_threshold_show, + rmi_f1a_button_release_threshold_store), + __ATTR(strongest_button_hysteresis, RMI_RW_ATTR, + rmi_f1a_strongest_button_hysteresis_show, + rmi_f1a_strongest_button_hysteresis_store), + __ATTR(filter_strength, RMI_RW_ATTR, + rmi_f1a_filter_strength_show, + rmi_f1a_filter_strength_store) +}; + +static int rmi_f1a_read_control_parameters(struct rmi_device *rmi_dev, + struct f1a_data *f1a) +{ + int error = 0; + struct f1a_0d_control *button_control = &f1a->button_control; + union f1a_0d_query *button_query = &f1a->button_query; + int ctrl_base_addr = f1a->general_control_address; + int button_bitmask_size = f1a->button_bitmask_size; + + if (button_query->has_general_control) { + error = rmi_read_block(rmi_dev, ctrl_base_addr, + (u8 *)&button_control->general_control, + sizeof(union f1a_0d_control_0)); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read f1a_0d_control_0, code: %d.\n", error); + return error; + } + ctrl_base_addr = ctrl_base_addr + + sizeof(union f1a_0d_control_0); + } + + if (button_query->has_interrupt_enable && + button_control->button_int_enable) { + f1a->button_int_enable_address = ctrl_base_addr; + error = rmi_read_block(rmi_dev, ctrl_base_addr, + button_control->button_int_enable, + button_bitmask_size); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read f1a_0d_control_1, code: %d.\n", error); + return error; + } + ctrl_base_addr = ctrl_base_addr + button_bitmask_size; + } + + if (button_query->has_multibutton_select && + button_control->multi_button) { + f1a->multi_button_address = ctrl_base_addr; + error = rmi_read_block(rmi_dev, ctrl_base_addr, + button_control->multi_button, + button_bitmask_size); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read f1a_0d_control_2, code: %d.\n", error); + return error; + } + ctrl_base_addr = ctrl_base_addr + button_bitmask_size; + } + + if (button_query->has_tx_rx_map && + button_control->electrode_map) { + f1a->electrode_map_address = ctrl_base_addr; + error = rmi_read_block(rmi_dev, ctrl_base_addr, + (u8 *)(button_control->electrode_map), + sizeof(struct f1a_0d_control_3_4)*f1a->button_count); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read f1a_0d_control_3_4, code: %d.\n", error); + return error; + } + ctrl_base_addr = ctrl_base_addr + + (sizeof(struct f1a_0d_control_3_4)*f1a->button_count); + } + if (button_query->has_perbutton_threshold && + button_control->button_threshold) { + f1a->button_threshold_address = ctrl_base_addr; + error = rmi_read_block(rmi_dev, ctrl_base_addr, + button_control->button_threshold, + f1a->button_count); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read f1a_0d_control_5, code: %d.\n", error); + return error; + } + ctrl_base_addr = ctrl_base_addr + + (sizeof(u8)*f1a->button_count); + } + + if (button_query->has_release_threshold) { + f1a->button_release_threshold_address = ctrl_base_addr; + error = rmi_read_block(rmi_dev, ctrl_base_addr, + &button_control->button_release_threshold, + sizeof(u8)); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read f1a_0d_control_6, code: %d.\n", error); + return error; + } + ctrl_base_addr = ctrl_base_addr + sizeof(u8); + } + + if (button_query->has_strongestbtn_hysteresis) { + f1a->strongest_button_hysteresis_address = ctrl_base_addr; + error = rmi_read_block(rmi_dev, ctrl_base_addr, + &button_control-> + strongest_button_hysteresis, + sizeof(u8)); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read f1a_0d_control_7, code: %d.\n", error); + return error; + } + ctrl_base_addr = ctrl_base_addr + sizeof(u8); + } + + if (button_query->has_filter_strength) { + f1a->filter_strength_address = ctrl_base_addr; + error = rmi_read_block(rmi_dev, ctrl_base_addr, + (u8 *)&button_control->filter_strength, + sizeof(u8)); + if (error < 0) { + dev_err(&rmi_dev->dev, + "Failed to read f1a_0d_control_8, code: %d.\n", error); + return error; + } + } + return 0; +} + + +static int rmi_f1a_init(struct rmi_function_container *fc) +{ + int rc; + + rc = rmi_f1a_alloc_memory(fc); + if (rc < 0) + goto err_free_data; + + rc = rmi_f1a_initialize(fc); + if (rc < 0) + goto err_free_data; + + rc = rmi_f1a_register_device(fc); + if (rc < 0) + goto err_free_data; + + rc = rmi_f1a_create_sysfs(fc); + if (rc < 0) + goto err_free_data; + + return 0; + +err_free_data: + rmi_f1a_free_memory(fc); + + return rc; +} + + +static int rmi_f1a_alloc_memory(struct rmi_function_container *fc) +{ + struct f1a_data *f1a; + int rc; + + f1a = kzalloc(sizeof(struct f1a_data), GFP_KERNEL); + if (!f1a) { + dev_err(&fc->dev, "Failed to allocate function data.\n"); + return -ENOMEM; + } + fc->data = f1a; + + rc = rmi_read_block(fc->rmi_dev, fc->fd.query_base_addr, + (u8 *)&f1a->button_query, + sizeof(union f1a_0d_query)); + if (rc < 0) { + dev_err(&fc->dev, "Failed to read query register.\n"); + return rc; + } + + f1a->button_count = f1a->button_query.max_button_count+1; + + f1a->button_bitmask_size = sizeof(u8)*(f1a->button_count + 7) / 8; + f1a->button_data_buffer = kcalloc(f1a->button_bitmask_size, + sizeof(u8), GFP_KERNEL); + if (!f1a->button_data_buffer) { + dev_err(&fc->dev, "Failed to allocate button data buffer.\n"); + return -ENOMEM; + } + + f1a->button_map = kcalloc(f1a->button_count, + sizeof(unsigned char), GFP_KERNEL); + if (!f1a->button_map) { + dev_err(&fc->dev, "Failed to allocate button map.\n"); + return -ENOMEM; + } + if (f1a->button_query.has_interrupt_enable) { + f1a->button_control.button_int_enable = + kzalloc(f1a->button_bitmask_size, GFP_KERNEL); + if (!f1a->button_control.button_int_enable) { + dev_err(&fc->dev, "Failed to allocate interrupt button.\n"); + return -ENOMEM; + } + } + if (f1a->button_query.has_multibutton_select) { + f1a->button_control.multi_button = + kzalloc(f1a->button_bitmask_size, GFP_KERNEL); + if (!f1a->button_control.multi_button) { + dev_err(&fc->dev, "Failed to allocate multi button group select.\n"); + return -ENOMEM; + } + } + if (f1a->button_query.has_tx_rx_map) { + f1a->button_control.electrode_map = + kzalloc(f1a->button_count * + sizeof(struct f1a_0d_control_3_4), GFP_KERNEL); + if (!f1a->button_control.electrode_map) { + dev_err(&fc->dev, "Failed to allocate f1a_0d_control_3_4.\n"); + return -ENOMEM; + } + } + if (f1a->button_query.has_perbutton_threshold) { + f1a->button_control.button_threshold = + kzalloc(f1a->button_count, GFP_KERNEL); + if (!f1a->button_control.button_threshold) { + dev_err(&fc->dev, "Failed to allocate button threshold.\n"); + return -ENOMEM; + } + } + return 0; +} + + + +static void rmi_f1a_free_memory(struct rmi_function_container *fc) +{ + struct f1a_data *f1a = fc->data; + + if (f1a) { + kfree(f1a->button_data_buffer); + kfree(f1a->button_map); + kfree(f1a->button_control.button_int_enable); + kfree(f1a->button_control.multi_button); + kfree(f1a->button_control.electrode_map); + kfree(f1a->button_control.button_threshold); + kfree(f1a); + fc->data = NULL; + } +} + + +static int rmi_f1a_initialize(struct rmi_function_container *fc) +{ + struct rmi_device *rmi_dev = fc->rmi_dev; + struct rmi_device_platform_data *pdata; + struct f1a_data *f1a = fc->data; + int i; + int rc; + + dev_info(&fc->dev, "Intializing F1a values."); + + /* initial all default values for f1a data here */ + pdata = to_rmi_platform_data(rmi_dev); + if (pdata) { + if (!pdata->f1a_button_map) + dev_warn(&fc->dev, "%s - button_map is NULL", __func__); + else if (pdata->f1a_button_map->nbuttons != + f1a->button_count) + dev_warn(&fc->dev, + "Platformdata button map size (%d) != number " + "of buttons on device (%d) - ignored.\n", + pdata->f1a_button_map->nbuttons, + f1a->button_count); + else if (!pdata->f1a_button_map->map) + dev_warn(&fc->dev, + "Platformdata button map is missing!\n"); + else + for (i = 0; i < pdata->f1a_button_map->nbuttons; i++) + f1a->button_map[i] = + pdata->f1a_button_map->map[i]; + } + + f1a->general_control_address = fc->fd.control_base_addr; + rc = rmi_f1a_read_control_parameters(rmi_dev, f1a); + if (rc < 0) { + dev_err(&fc->dev, + "Failed to initialize F1a control params.\n"); + return rc; + } + + return 0; +} + + + +static int rmi_f1a_register_device(struct rmi_function_container *fc) +{ + struct rmi_device *rmi_dev = fc->rmi_dev; + struct input_dev *input_dev; + struct f1a_data *f1a = fc->data; + int i; + int rc; + + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&fc->dev, "Failed to allocate input device.\n"); + return -ENOMEM; + } + + f1a->input = input_dev; + snprintf(f1a->input_name, MAX_NAME_LEN, "%sfn%02x", + dev_name(&rmi_dev->dev), + fc->fd.function_number); + input_dev->name = f1a->input_name; + snprintf(f1a->input_phys, MAX_NAME_LEN, "%s/input0", input_dev->name); + input_dev->phys = f1a->input_phys; + input_dev->dev.parent = &rmi_dev->dev; + input_set_drvdata(input_dev, f1a); + + /* Set up any input events. */ + set_bit(EV_SYN, input_dev->evbit); + set_bit(EV_KEY, input_dev->evbit); + /* set bits for each button... */ + for (i = 0; i < f1a->button_count; i++) + set_bit(f1a->button_map[i], input_dev->keybit); + rc = input_register_device(input_dev); + if (rc < 0) { + dev_err(&fc->dev, "Failed to register input device.\n"); + goto error_free_device; + } + + return 0; + +error_free_device: + input_free_device(input_dev); + + return rc; +} + + +static int rmi_f1a_create_sysfs(struct rmi_function_container *fc) +{ + int attr_count = 0; + int rc; + struct f1a_data *data; + union f1a_0d_query *button_query; + char *name; + data = fc->data; + button_query = &data->button_query; + + dev_dbg(&fc->dev, "Creating sysfs files.\n"); + /* Set up sysfs device attributes. */ + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { + name = (char *) attrs[attr_count].attr.name; + if (!button_query->has_general_control && + (!strcmp(name, "multibutton_report") || + !strcmp(name, "filter_mode"))) + continue; + if (!button_query->has_interrupt_enable && + !strcmp(name, "button_int_enable")) + continue; + if (!button_query->has_multibutton_select && + !strcmp(name, "multibutton")) + continue; + if (!button_query->has_tx_rx_map && + !strcmp(name, "electrode_map")) + continue; + if (!button_query->has_perbutton_threshold && + !strcmp(name, "threshold_button")) + continue; + if (!button_query->has_release_threshold && + !strcmp(name, "button_release_threshold")) + continue; + if (!button_query->has_strongestbtn_hysteresis && + !strcmp(name, "strongest_button_hysteresis")) + continue; + if (!button_query->has_filter_strength && + !strcmp(name, "filter_strength")) + continue; + if (sysfs_create_file + (&fc->dev.kobj, &attrs[attr_count].attr) < 0) { + dev_err(&fc->dev, + "Failed to create sysfs file for %s.", + attrs[attr_count].attr.name); + rc = -ENODEV; + goto err_remove_sysfs; + } + } + + return 0; + +err_remove_sysfs: + for (attr_count--; attr_count >= 0; attr_count--) + sysfs_remove_file(&fc->dev.kobj, + &attrs[attr_count].attr); + return rc; + +} + + + +static int rmi_f1a_config(struct rmi_function_container *fc) +{ + struct f1a_data *data; + int retval; + union f1a_0d_query *button_query; + + data = fc->data; + button_query = &data->button_query; + if (button_query->has_general_control) { + retval = rmi_write_block(fc->rmi_dev, + data->general_control_address, + (u8 *)&data->button_control.general_control, + sizeof(union f1a_0d_control_0)); + if (retval < 0) { + dev_err(&fc->dev, "%s : Could not write general_control to 0x%x\n", + __func__, fc->fd.control_base_addr); + return retval; + } + } + if (button_query->has_interrupt_enable) { + retval = rmi_write_block(fc->rmi_dev, + data->button_int_enable_address, + data->button_control.button_int_enable, + data->button_bitmask_size); + if (retval < 0) { + dev_err(&fc->dev, "%s : Could not write interrupt_enable_store to 0x%x\n", + __func__, data->button_int_enable_address); + return retval; + } + } + if (button_query->has_multibutton_select) { + retval = rmi_write_block(fc->rmi_dev, + data->multi_button_address, + data->button_control.multi_button, + data->button_bitmask_size); + if (retval < 0) { + dev_err(&fc->dev, "%s : Could not write multi_button_store to 0x%x\n", + __func__, data->multi_button_address); + return -EINVAL; + } + } + if (button_query->has_tx_rx_map) { + retval = rmi_write_block(fc->rmi_dev, + data->electrode_map_address, + (u8 *)data->button_control.electrode_map, + sizeof(struct f1a_0d_control_3_4)* + data->button_count); + if (retval < 0) { + dev_err(&fc->dev, "%s : Could not electrode_map_store to 0x%x\n", + __func__, data->electrode_map_address); + return -EINVAL; + } + } + if (button_query->has_perbutton_threshold) { + retval = rmi_write_block(fc->rmi_dev, + data->button_threshold_address, + data->button_control.button_threshold, + data->button_count); + if (retval < 0) { + dev_err(&fc->dev, "%s : Could not button_threshold_store to 0x%x\n", + __func__, data->button_threshold_address); + return retval; + } + } + if (button_query->has_release_threshold) { + retval = rmi_write_block(fc->rmi_dev, + data->button_release_threshold_address, + &data->button_control.button_release_threshold, + sizeof(u8)); + if (retval < 0) { + dev_err(&fc->dev, "%s : Could not write button_release_threshold store to 0x%x\n", + __func__, + data->button_release_threshold_address); + return -EINVAL; + } + } + if (button_query->has_strongestbtn_hysteresis) { + retval = rmi_write_block(fc->rmi_dev, + data->strongest_button_hysteresis_address, + &data->button_control.strongest_button_hysteresis, + sizeof(u8)); + if (retval < 0) { + dev_err(&fc->dev, "%s : Could not write strongest_button_hysteresis store" + " to 0x%x\n", + __func__, + data->strongest_button_hysteresis_address); + return -EINVAL; + } + } + if (button_query->has_filter_strength) { + retval = rmi_write_block(fc->rmi_dev, + data->filter_strength_address, + &data->button_control.filter_strength, + sizeof(u8)); + if (retval < 0) { + dev_err(&fc->dev, "%s : Could not write filter_strength store to 0x%x\n", __func__, + data->filter_strength_address); + return -EINVAL; + } + } + return 0; +} + + +static int rmi_f1a_reset(struct rmi_function_container *fc) +{ + /* we do nnothing here */ + return 0; +} + + +static void rmi_f1a_remove(struct rmi_function_container *fc) +{ + struct f1a_data *f1a = fc->data; + int attr_count = 0; + + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) + sysfs_remove_file(&fc->dev.kobj, + &attrs[attr_count].attr); + + input_unregister_device(f1a->input); + + rmi_f1a_free_memory(fc); +} + +int rmi_f1a_attention(struct rmi_function_container *fc, u8 *irq_bits) +{ + struct rmi_device *rmi_dev = fc->rmi_dev; + struct f1a_data *f1a = fc->data; + u16 data_base_addr = fc->fd.data_base_addr; + int error; + int button; + //char buf[256]; + /* Read the button data. */ + error = rmi_read_block(rmi_dev, data_base_addr, f1a->button_data_buffer, + f1a->button_bitmask_size); + if (error < 0) { + dev_err(&fc->dev, "%s: Failed to read button data registers.\n", + __func__); + return error; + } + //printk("++++++++++++button_data_buffer:%x\n", f1a->button_data_buffer[0]); + /* Generate events for buttons that change state. */ + for (button = 0; button < f1a->button_count; button++) { + int button_reg; + int button_shift; + bool button_status; + + /* determine which data byte the button status is in */ + button_reg = button / 8; + /* bit shift to get button's status */ + button_shift = button % 8; + button_status = + ((f1a->button_data_buffer[button_reg] >> button_shift) + & 0x01) != 0; + + dev_dbg(&fc->dev, "%s: Button %d (code %d) -> %d.\n", + __func__, button, f1a->button_map[button], + button_status); + /* Generate an event here. */ + input_report_key(f1a->input, f1a->button_map[button], + button_status); + } + + input_sync(f1a->input); /* sync after groups of events */ + return 0; +} + +static struct rmi_function_handler function_handler = { + .func = 0x1a, + .init = rmi_f1a_init, + .config = rmi_f1a_config, + .reset = rmi_f1a_reset, + .attention = rmi_f1a_attention, + .remove = rmi_f1a_remove +}; + +static int __init rmi_f1a_module_init(void) +{ + int error; + + error = rmi_register_function_driver(&function_handler); + if (error < 0) { + pr_err("%s: register failed!\n", __func__); + return error; + } + + return 0; +} + +static void rmi_f1a_module_exit(void) +{ + rmi_unregister_function_driver(&function_handler); +} + +static ssize_t rmi_f1a_filter_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", + data->button_control.general_control.filter_mode); + +} + +static ssize_t rmi_f1a_filter_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + unsigned int new_value; + unsigned int old_value; + int result; + + fc = to_rmi_function_container(dev); + data = fc->data; + if (sscanf(buf, "%u", &new_value) < 1) { + dev_err(dev, "%s: Error - filter_mode_store has an invalid len.\n", __func__); + return -EINVAL; + } + + if (new_value < FILTER_MODE_MIN || new_value > FILTER_MODE_MAX) { + dev_err(dev, "%s: Error - filter_mode_store has an " + "invalid value %d.\n", + __func__, new_value); + return -EINVAL; + } + old_value = data->button_control.general_control.filter_mode; + data->button_control.general_control.filter_mode = new_value; + result = rmi_write_block(fc->rmi_dev, data->general_control_address, + (u8 *)&(data->button_control.general_control), + sizeof(union f1a_0d_control_0)); + if (result < 0) { + data->button_control.general_control.filter_mode = old_value; + dev_err(dev, "%s : Could not write filter_mode_store to 0x%x\n", + __func__, fc->fd.control_base_addr); + return result; + } + + return count; +} + +static ssize_t rmi_f1a_multibutton_report_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", + data->button_control.general_control.multibutton_report); + +} + +static ssize_t rmi_f1a_multibutton_report_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + unsigned int new_value; + unsigned int old_value; + int result; + + fc = to_rmi_function_container(dev); + data = fc->data; + if (sscanf(buf, "%u", &new_value) < 1) { + dev_err(dev, + "%s: Error - multibutton_report_store has an " + "invalid len.\n", + __func__); + return -EINVAL; + } + + if (new_value < MULTI_BUTTON_REPORT_MIN || + new_value > MULTI_BUTTON_REPORT_MAX) { + dev_err(dev, "%s: Error - multibutton_report_store has an " + "invalid value %d.\n", + __func__, new_value); + return -EINVAL; + } + old_value = data->button_control.general_control.multibutton_report; + data->button_control.general_control.multibutton_report = new_value; + result = rmi_write_block(fc->rmi_dev, data->general_control_address, + (u8 *)&(data->button_control.general_control), + sizeof(union f1a_0d_control_0)); + if (result < 0) { + data->button_control.general_control.multibutton_report = + old_value; + dev_err(dev, "%s : Could not write multibutton_report_store to 0x%x\n", + __func__, fc->fd.control_base_addr); + return result; + } + + return count; + +} + +static ssize_t rmi_f1a_button_int_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + int i, len, total_len = 0; + char *current_buf = buf; + + fc = to_rmi_function_container(dev); + data = fc->data; + /* loop through each button map value and copy its + * string representation into buf */ + for (i = 0; i < data->button_count; i++) { + int button_reg; + int button_shift; + int interrupt_button; + + button_reg = i / 8; + button_shift = i % 8; + interrupt_button = + ((data->button_control.button_int_enable[button_reg] >> + button_shift) & 0x01); + + /* get next button mapping value and write it to buf */ + len = snprintf(current_buf, PAGE_SIZE - total_len, + "%u ", interrupt_button); + /* bump up ptr to next location in buf if the + * snprintf was valid. Otherwise issue an error + * and return. */ + if (len > 0) { + current_buf += len; + total_len += len; + } else { + dev_err(dev, "%s: Failed to build interrupt button" + " buffer, code = %d.\n", __func__, len); + return snprintf(buf, PAGE_SIZE, "unknown\n"); + } + } + len = snprintf(current_buf, PAGE_SIZE - total_len, "\n"); + if (len > 0) + total_len += len; + else + dev_warn(dev, "%s: Failed to append carriage return.\n", + __func__); + return total_len; + +} + +static ssize_t rmi_f1a_button_int_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + int i; + int button_count = 0; + int retval = count; + int button_reg = 0; + u8 *new_value; + fc = to_rmi_function_container(dev); + data = fc->data; + new_value = kzalloc(data->button_bitmask_size, GFP_KERNEL); + if (!new_value) { + dev_err(dev, "%s: Error - failed to allocate button interrupt enable.\n", __func__); + return -ENOMEM; + } + for (i = 0; i < data->button_count && *buf != 0; + i++, buf += 2) { + int button_shift; + int button; + int result; + + button_reg = i / 8; + button_shift = i % 8; + /* get next button mapping value and store and bump up to + * point to next item in buf */ + result = sscanf(buf, "%u", &button); + + if ((result != 1) || (button != 0 && button != 1)) { + dev_err(dev, + "%s: Error - interrupt enable button for" + "button %d is not a valid value 0x%x.\n", + __func__, i, button); + kfree(new_value); + return -EINVAL; + } + if (button) + new_value[button_reg] |= (1 << button_shift); + + button_count++; + } + + /* Make sure the button count matches */ + if (button_count != data->button_count) { + dev_err(dev, + "%s: Error - interrupt enable button count of %d" + " doesn't match device button count of %d.\n", + __func__, button_count, data->button_count); + kfree(new_value); + return -EINVAL; + } + /* write back to the control register */ + retval = rmi_write_block(fc->rmi_dev, + data->button_int_enable_address, + new_value, data->button_bitmask_size); + if (retval < 0) { + dev_err(dev, "%s : Could not write interrupt_enable_store to 0x%x\n", + __func__, data->button_int_enable_address); + return retval; + } + memcpy(data->button_control.button_int_enable, + new_value, data->button_bitmask_size); + + kfree(new_value); + return count; +} + +static ssize_t rmi_f1a_multibutton_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + int i, len, total_len = 0; + char *current_buf = buf; + + fc = to_rmi_function_container(dev); + data = fc->data; + /* loop through each button map value and copy its + * string representation into buf */ + for (i = 0; i < data->button_count; i++) { + int button_reg; + int button_shift; + int multibutton; + + button_reg = i / 8; + button_shift = i % 8; + multibutton = ((data->button_control. + multi_button[button_reg] >> button_shift) & 0x01); + + /* get next button mapping value and write it to buf */ + len = snprintf(current_buf, PAGE_SIZE - total_len, + "%u ", multibutton); + /* bump up ptr to next location in buf if the + * snprintf was valid. Otherwise issue an error + * and return. */ + if (len > 0) { + current_buf += len; + total_len += len; + } else { + dev_err(dev, "%s: Failed to build multibutton buffer" + ", code = %d.\n", __func__, len); + return snprintf(buf, PAGE_SIZE, "unknown\n"); + } + } + len = snprintf(current_buf, PAGE_SIZE - total_len, "\n"); + if (len > 0) + total_len += len; + else + dev_warn(dev, "%s: Failed to append carriage return.\n", + __func__); + + return total_len; + +} + +static ssize_t rmi_f1a_multibutton_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + int i; + int button_count = 0; + int retval = count; + int button_reg = 0; + u8 *new_value; + + fc = to_rmi_function_container(dev); + data = fc->data; + new_value = kzalloc(data->button_bitmask_size, GFP_KERNEL); + if (!new_value) { + dev_err(dev, "%s: Error - failed to allocate multi button.\n", __func__); + return -ENOMEM; + } + for (i = 0; i < data->button_count && *buf != 0; + i++, buf += 2) { + int button_shift; + int button; + int result; + + button_reg = i / 8; + button_shift = i % 8; + /* get next button mapping value and store and bump up to + * point to next item in buf */ + result = sscanf(buf, "%u", &button); + + if ((result < 1) || (button < 0 || button > 1)) { + dev_err(dev, + "%s: Error - multibutton for button %d" + " is not a valid value 0x%x.\n", + __func__, i, button); + kfree(new_value); + return -EINVAL; + } + + if (button) + new_value[button_reg] |= (1 << button_shift); + + button_count++; + } + + /* Make sure the button count matches */ + if (button_count != data->button_count) { + dev_err(dev, + "%s: Error - multibutton count of %d doesn't match" + " device button count of %d.\n", __func__, button_count, + data->button_count); + kfree(new_value); + return -EINVAL; + } + /* write back to the control register */ + retval = rmi_write_block(fc->rmi_dev, data->multi_button_address, + new_value, + data->button_bitmask_size); + if (retval < 0) { + dev_err(dev, "%s : Could not write multibutton_store to" + " 0x%x\n", __func__, data->multi_button_address); + kfree(new_value); + return -EINVAL; + } + memcpy(data->button_control.multi_button, new_value, + data->button_bitmask_size); + kfree(new_value); + return count; +} + +static ssize_t rmi_f1a_electrode_map_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + int i, len, total_len = 0; + char *current_buf = buf; + struct f1a_0d_control *button_control; + fc = to_rmi_function_container(dev); + data = fc->data; + button_control = &data->button_control; + for (i = 0; i < data->button_count; i++) { + len = snprintf(current_buf, PAGE_SIZE - total_len, "%u:%u ", + button_control->electrode_map[i].transmitterbutton, + button_control->electrode_map[i].receiverbutton); + /* bump up ptr to next location in buf if the + * snprintf was valid. Otherwise issue an error + * and return. */ + if (len > 0) { + current_buf += len; + total_len += len; + } else { + dev_err(dev, "%s: Failed to build electrode map buffer, code = %d.\n", + __func__, len); + return snprintf(buf, PAGE_SIZE, "unknown\n"); + } + } + len = snprintf(current_buf, PAGE_SIZE - total_len, "\n"); + if (len > 0) + total_len += len; + else + dev_warn(dev, "%s: Failed to append carriage return.\n", + __func__); + return total_len; + + +} + +static ssize_t rmi_f1a_electrode_map_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + char colon; + int i; + int result; + int retval = count; + int button_count = 0; + char tx_rx[MAX_BUFFER_LEN]; + struct f1a_0d_control_3_4 *new_value; + fc = to_rmi_function_container(dev); + data = fc->data; + + new_value = kzalloc(data->button_count * + sizeof(struct f1a_0d_control_3_4), GFP_KERNEL); + if (!new_value) { + dev_err(dev, "%s: Error - failed to allocate eletrode map.\n", __func__); + return -ENOMEM; + } + for (i = 0; i < data->button_count && *buf != 0; i++) { + /* get next button mapping value and store and bump up to + * point to next item in buf */ + result = sscanf(buf, "%s ", tx_rx); + if (result < 1) { + dev_err(dev, "%s: Error - scanf threshold button\n", __func__); + kfree(new_value); + return -EINVAL; + } + result = sscanf(tx_rx, "%u%c%u", + (unsigned int *)&new_value[i].transmitterbutton, + &colon, + (unsigned int *)&new_value[i].receiverbutton); + buf += strlen(tx_rx)+1; + /* Make sure the key is a valid key */ + if ((result < 3) || (colon != ':') || + (new_value[i].transmitterbutton < TX_RX_BUTTON_MIN || + new_value[i].transmitterbutton > TX_RX_BUTTON_MAX) || + (new_value[i].receiverbutton < TX_RX_BUTTON_MIN || + new_value[i].receiverbutton > TX_RX_BUTTON_MAX)) { + dev_err(dev, "%s: Error - electrode map for button %d " + "is not a valid value 0x%x:0x%x.\n", + __func__, i, new_value[i].transmitterbutton, + new_value[i].receiverbutton); + kfree(new_value); + return -EINVAL; + } + button_count++; + } + + if (button_count != data->button_count) { + dev_err(dev, + "%s: Error - button map count of %d doesn't match device " + "button count of %d.\n", __func__, button_count, + data->button_count); + kfree(new_value); + return -EINVAL; + } + /* write back to the control register */ + retval = rmi_write_block(fc->rmi_dev, data->electrode_map_address, + (u8 *)new_value, + sizeof(struct f1a_0d_control_3_4)*button_count); + if (retval < 0) { + dev_err(dev, "%s : Could not transmitter_btn_store to 0x%x\n", + __func__, data->electrode_map_address); + return -EINVAL; + kfree(new_value); + } + for (i = 0; i < data->button_count; i++) { + data->button_control.electrode_map[i].transmitterbutton = + new_value[i].transmitterbutton; + data->button_control.electrode_map[i].receiverbutton = + new_value[i].receiverbutton; + } + kfree(new_value); + return count; +} + +static ssize_t rmi_f1a_threshold_button_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + int i, len, total_len = 0; + char *current_buf = buf; + + fc = to_rmi_function_container(dev); + data = fc->data; + + for (i = 0; i < data->button_count; i++) { + len = snprintf(current_buf, PAGE_SIZE - total_len, "%u ", + data->button_control.button_threshold[i]); + /* bump up ptr to next location in buf if the + * snprintf was valid. Otherwise issue an error + * and return. */ + if (len > 0) { + current_buf += len; + total_len += len; + } else { + dev_err(dev, "%s: Failed to build threshold_button, " + "code = %d.\n", __func__, len); + return snprintf(buf, PAGE_SIZE, "unknown\n"); + } + } + len = snprintf(current_buf, PAGE_SIZE - total_len, "\n"); + if (len > 0) + total_len += len; + else + dev_warn(dev, "%s: Failed to append carriage return.\n", + __func__); + return total_len; + + +} + +static ssize_t rmi_f1a_threshold_button_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + int i; + int result; + int retval = count; + int button_count = 0; + char threshold_button[MAX_BUFFER_LEN]; + u8 *new_value; + fc = to_rmi_function_container(dev); + data = fc->data; + new_value = kzalloc(data->button_count, GFP_KERNEL); + if (!new_value) { + dev_err(dev, "%s: Error - failed to allocate threshold button.\n", __func__); + return -ENOMEM; + } + + for (i = 0; i < data->button_count && *buf != 0; i++) { + /* get next button mapping value and store and bump up to + * point to next item in buf */ + result = sscanf(buf, "%s ", threshold_button); + if (result < 1) { + dev_err(dev, "%s: Error - scanf threshold button\n", __func__); + kfree(new_value); + return -EINVAL; + } + result = sscanf(threshold_button, "%u", + (unsigned int *)&new_value[i]); + buf += strlen(threshold_button)+1; + /* Make sure the key is a valid key */ + if ((result < 1) || + (new_value[i] < THREADHOLD_BUTTON_MIN || + new_value[i] > THREADHOLD_BUTTON_MAX)) { + dev_err(dev, + "%s: Error - threshold_button for button %d " + "is not a valid value 0x%x.\n", + __func__, i, new_value[i]); + kfree(new_value); + return -EINVAL; + } + button_count++; + } + + if (button_count != data->button_count) { + dev_err(dev, + "%s: Error - button map count of %d doesn't match device " + "button count of %d.\n", __func__, button_count, + data->button_count); + kfree(new_value); + return -EINVAL; + } + + /* write back to the control register */ + retval = rmi_write_block(fc->rmi_dev, data->button_threshold_address, + new_value, data->button_count); + if (retval < 0) { + dev_err(dev, "%s : Could not threshold_button_store to 0x%x\n", + __func__, data->button_threshold_address); + kfree(new_value); + return -EINVAL; + } + memcpy(data->button_control.button_threshold, new_value, + data->button_count); + kfree(new_value); + return count; +} + + +static ssize_t rmi_f1a_button_release_threshold_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", data->button_control. + button_release_threshold); + +} +static ssize_t rmi_f1a_button_release_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + u8 new_value; + u8 old_value; + int len; + + fc = to_rmi_function_container(dev); + + data = fc->data; + + len = sscanf(buf, "%u", (unsigned int *)&new_value); + if ((len < 1) || + (new_value < RELEASE_THREADHOLD_BUTTON_MIN || + new_value > RELEASE_THREADHOLD_BUTTON_MAX)) { + dev_err(dev, + "%s: Error - release threshold_button " + "is not a valid value 0x%x.\n", + __func__, new_value); + return -EINVAL; + } + old_value = data->button_control.button_release_threshold; + data->button_control.button_release_threshold = new_value; + /* write back to the control register */ + len = rmi_write_block(fc->rmi_dev, + data->button_release_threshold_address, + (u8 *)&(data->button_control.button_release_threshold), + sizeof(u8)); + if (len < 0) { + data->button_control.button_release_threshold = old_value; + dev_err(dev, "%s : Could not button_release_threshold_store to" + " 0x%x\n", __func__, + data->button_release_threshold_address); + return len; + } + + return count; +} + +static ssize_t rmi_f1a_strongest_button_hysteresis_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", data->button_control. + strongest_button_hysteresis); + +} +static ssize_t rmi_f1a_strongest_button_hysteresis_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + u8 new_value; + u8 old_value; + int len; + + fc = to_rmi_function_container(dev); + + data = fc->data; + + len = sscanf(buf, "%u", (unsigned int *)&new_value); + if ((len < 1) || + (new_value < STRONGEST_BUTTON_HYSTERESIS_MIN || + new_value > STRONGEST_BUTTON_HYSTERESIS_MAX)) { + dev_err(dev, + "%s: Error - strongest button hysteresis is not a valid value 0x%x.\n", + __func__, new_value); + return -EINVAL; + } + old_value = data->button_control.strongest_button_hysteresis; + data->button_control.strongest_button_hysteresis = new_value; + /* write back to the control register */ + len = rmi_write_block(fc->rmi_dev, + data->strongest_button_hysteresis_address, + (u8 *)&(data->button_control.strongest_button_hysteresis), + sizeof(u8)); + if (len < 0) { + data->button_control.strongest_button_hysteresis = old_value; + dev_err(dev, "%s : Could not strongest_button_hysteresis_store" + " to 0x%x\n", __func__, + data->strongest_button_hysteresis_address); + return len; + } + + return count; +} + +static ssize_t rmi_f1a_filter_strength_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", data->button_control. + filter_strength); + +} + +static ssize_t rmi_f1a_filter_strength_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + int new_value; + int old_value; + int len; + + fc = to_rmi_function_container(dev); + + data = fc->data; + + len = sscanf(buf, "%u", &new_value); + if ((len < 1) || + (new_value < FILTER_STRENGTH_MIN || + new_value > FILTER_STRENGTH_MAX)) { + dev_err(dev, + "%s: Error - filter strength button is not a valid value 0x%x.\n", + __func__, new_value); + return -EINVAL; + } + old_value = data->button_control.filter_strength; + data->button_control.filter_strength = new_value; + /* write back to the control register */ + len = rmi_write_block(fc->rmi_dev, + data->filter_strength_address, + (u8 *)&(data->button_control.filter_strength), + sizeof(u8)); + if (len < 0) { + data->button_control.filter_strength = old_value; + dev_err(dev, "%s : Could not filter_strength_store to 0x%x\n", __func__, + data->filter_strength_address); + return len; + } + + return count; +} + + +static ssize_t rmi_f1a_button_count_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->button_query.max_button_count); +} + +static ssize_t rmi_f1a_has_general_control_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->button_query.has_general_control); +} + +static ssize_t rmi_f1a_has_interrupt_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->button_query.has_interrupt_enable); +} + +static ssize_t rmi_f1a_has_multibutton_select_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->button_query.has_multibutton_select); +} + +static ssize_t rmi_f1a_has_tx_rx_map_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->button_query.has_tx_rx_map); +} + +static ssize_t rmi_f1a_has_perbutton_threshold_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->button_query.has_perbutton_threshold); +} + +static ssize_t rmi_f1a_has_release_threshold_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->button_query.has_release_threshold); +} + +static ssize_t rmi_f1a_has_strongestbtn_hysteresis_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->button_query.has_strongestbtn_hysteresis); +} + +static ssize_t rmi_f1a_has_filter_strength_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + return snprintf(buf, PAGE_SIZE, "%u\n", + data->button_query.has_filter_strength); +} + +static ssize_t rmi_f1a_button_map_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + + struct rmi_function_container *fc; + struct f1a_data *data; + int i, len, total_len = 0; + char *current_buf = buf; + + fc = to_rmi_function_container(dev); + data = fc->data; + /* loop through each button map value and copy its + * string representation into buf */ + for (i = 0; i < data->button_count; i++) { + /* get next button mapping value and write it to buf */ + len = snprintf(current_buf, PAGE_SIZE - total_len, + "%u ", data->button_map[i]); + /* bump up ptr to next location in buf if the + * snprintf was valid. Otherwise issue an error + * and return. */ + if (len > 0) { + current_buf += len; + total_len += len; + } else { + dev_err(dev, "%s: Failed to build button map buffer, " + "code = %d.\n", __func__, len); + return snprintf(buf, PAGE_SIZE, "unknown\n"); + } + } + len = snprintf(current_buf, PAGE_SIZE - total_len, "\n"); + if (len > 0) + total_len += len; + else + dev_warn(dev, "%s: Failed to append carriage return.\n", + __func__); + return total_len; +} + +static ssize_t rmi_f1a_button_map_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct rmi_function_container *fc; + struct f1a_data *data; + unsigned int button; + int i; + int retval = count; + int button_count = 0; + unsigned char temp_button_map[KEY_MAX]; + + fc = to_rmi_function_container(dev); + data = fc->data; + + /* Do validation on the button map data passed in. Store button + * mappings into a temp buffer and then verify button count and + * data prior to clearing out old button mappings and storing the + * new ones. */ + for (i = 0; i < data->button_count && *buf != 0; + i++) { + /* get next button mapping value and store and bump up to + * point to next item in buf */ + sscanf(buf, "%u", &button); + + /* Make sure the key is a valid key */ + if (button > KEY_MAX) { + dev_err(dev, + "%s: Error - button map for button %d is not a" + " valid value 0x%x.\n", __func__, i, button); + retval = -EINVAL; + goto err_ret; + } + + temp_button_map[i] = button; + button_count++; + + /* bump up buf to point to next item to read */ + while (*buf != 0) { + buf++; + if (*(buf - 1) == ' ') + break; + } + } + + /* Make sure the button count matches */ + if (button_count != data->button_count) { + dev_err(dev, + "%s: Error - button map count of %d doesn't match device " + "button count of %d.\n", __func__, button_count, + data->button_count); + retval = -EINVAL; + goto err_ret; + } + + /* Clear the key bits for the old button map. */ + for (i = 0; i < button_count; i++) + clear_bit(data->button_map[i], data->input->keybit); + + /* Switch to the new map. */ + memcpy(data->button_map, temp_button_map, + data->button_count); + + /* Loop through the key map and set the key bit for the new mapping. */ + for (i = 0; i < button_count; i++) + set_bit(data->button_map[i], data->input->keybit); + +err_ret: + return retval; +} + +module_init(rmi_f1a_module_init); +module_exit(rmi_f1a_module_exit); + +MODULE_AUTHOR("Vivian Ly "); +MODULE_DESCRIPTION("RMI F1a module"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(RMI_DRIVER_VERSION); diff --git a/drivers/input/touchscreen/rmi4/rmi_f21.c b/drivers/input/touchscreen/rmi4/rmi_f21.c new file mode 100755 index 000000000000..a8a163bc3bfe --- /dev/null +++ b/drivers/input/touchscreen/rmi4/rmi_f21.c @@ -0,0 +1,751 @@ + +/* + * Copyright (c) 2012 Synaptics Incorporated + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define FUNCTION_DATA rmi_fn_21_data +#define FNUM 21 + + +#include +#include +#include +#include "rmi_driver.h" + +union f21_2df_query { + struct { + /* Query 0 */ + u8 max_force_sensor_count:3; + u8 f21_2df_query0_b3__6:4; + u8 has_high_resolution:1; + }; + struct { + u8 regs[1]; + u16 address; + }; +}; + +union f21_2df_control_0__3 { + struct { + /* Control 0 */ + u8 reporting_mode:2; + u8 no_rezero:1; + u8 f21_2df_control0_b5__7:4; + + /* Control 1 */ + u8 force_click_threshold; + + /* Control 2 */ + u8 int_en_force_0:1; + u8 int_en_force_1:1; + u8 int_en_force_2:1; + u8 int_en_force_3:1; + u8 int_en_force_4:1; + u8 int_en_force_5:1; + u8 int_en_force_6:1; + u8 f21_ap_control2_b4__6:3; + u8 int_en_click:1; + + /* Control 3 */ + u8 force_interrupt_threshold; + }; + struct { + u8 regs[4]; + u16 address; + }; +}; + +struct f21_2df_control_4n { + /*Control 4.* */ + u8 one_newton_calibration:7; + u8 use_cfg_cal:1; +}; + +struct f21_2df_control_4{ + struct f21_2df_control_4n *regs; + u16 address; + u8 length; +}; + +struct f21_2df_control_5n { + /*Control 5.* */ + u8 x_location; +}; + +struct f21_2df_control_5{ + struct f21_2df_control_5n *regs; + u16 address; + u8 length; +}; + +struct f21_2df_control_6n { + /*Control 6.* */ + u8 y_location; +}; + +struct f21_2df_control_6{ + struct f21_2df_control_6n *regs; + u16 address; + u8 length; +}; + +struct f21_2df_control_7n { + /*Control 7.* */ + u8 transmitter_force_sensor; +}; + +struct f21_2df_control_7{ + struct f21_2df_control_7n *regs; + u16 address; + u8 length; +}; + +struct f21_2df_control_8n { + /*Control 8.* */ + u8 receiver_force_sensor; +}; + +struct f21_2df_control_8{ + struct f21_2df_control_8n *regs; + u16 address; + u8 length; +}; + + +#define RMI_F21_NUM_CTRL_REGS 8 +struct f21_2df_control { + /* Control 0-3 */ + union f21_2df_control_0__3 *reg_0__3; + + /* Control 4 */ + struct f21_2df_control_4 *reg_4; + + /* Control 5 */ + struct f21_2df_control_5 *reg_5; + + /* Control 6 */ + struct f21_2df_control_6 *reg_6; + + /* Control 7 */ + struct f21_2df_control_7 *reg_7; + + /* Control 8 */ + struct f21_2df_control_8 *reg_8; +}; + +union f21_2df_data_2 { + struct { + /* Data 2 */ + u8 force_click:1; + u8 f21_2df_control0_b2__7:7; + }; + struct { + u8 regs[1]; + u16 address; + }; +}; + +struct f21_2df_data { + /* Data 0 */ + struct { + u8 *force_hi_lo; + u16 address; + } reg_0__1; + + /* Data 2 */ + union f21_2df_data_2 *reg_2; +}; + +#define F21_REZERO_CMD 0x01 + +/* data specific to fn $21 that needs to be kept around */ +struct rmi_fn_21_data { + union f21_2df_query query; + struct f21_2df_control control; + struct f21_2df_data data; + + struct mutex control_mutex; + struct mutex data_mutex; +}; + +static int rmi_f21_alloc_memory(struct rmi_function_container *fc); + +static void rmi_f21_free_memory(struct rmi_function_container *fc); + +static int rmi_f21_initialize(struct rmi_function_container *fc); + +static int rmi_f21_config(struct rmi_function_container *fc); + +static int rmi_f21_create_sysfs(struct rmi_function_container *fc); + +/* Sysfs files */ + +/* Query sysfs files */ + + +show_union_struct_prototype(max_force_sensor_count) +show_union_struct_prototype(has_high_resolution) + +static struct attribute *attrs[] = { + attrify(max_force_sensor_count), + attrify(has_high_resolution), + NULL +}; +static struct attribute_group attrs_query = GROUP(attrs); +/* Control sysfs files */ + +show_store_union_struct_prototype(reporting_mode) +show_store_union_struct_prototype(no_rezero) +show_store_union_struct_prototype(force_click_threshold) +show_store_union_struct_prototype(int_en_force_0) +show_store_union_struct_prototype(int_en_force_1) +show_store_union_struct_prototype(int_en_force_2) +show_store_union_struct_prototype(int_en_force_3) +show_store_union_struct_prototype(int_en_force_4) +show_store_union_struct_prototype(int_en_force_5) +show_store_union_struct_prototype(int_en_force_6) +show_store_union_struct_prototype(int_en_click) +show_store_union_struct_prototype(force_interrupt_threshold) + +show_store_union_struct_prototype(use_cfg_cal) +show_store_union_struct_prototype(one_newton_calibration) +show_store_union_struct_prototype(x_location) +show_store_union_struct_prototype(y_location) +show_store_union_struct_prototype(transmitter_force_sensor) +show_store_union_struct_prototype(receiver_force_sensor) + + +static struct attribute *attrs2[] = { + attrify(reporting_mode), + attrify(no_rezero), + attrify(force_click_threshold), + attrify(int_en_click), + attrify(force_interrupt_threshold), + attrify(use_cfg_cal), + attrify(one_newton_calibration), + attrify(x_location), + attrify(y_location), + attrify(transmitter_force_sensor), + attrify(receiver_force_sensor), + NULL +}; +static struct attribute_group attrs_control = GROUP(attrs2); + +/* Data sysfs files */ +show_union_struct_prototype(force) +show_union_struct_prototype(force_click) + +static struct attribute *attrs3[] = { + attrify(force), + attrify(force_click), + NULL +}; +static struct attribute_group attrs_data = GROUP(attrs3); + +/* Command sysfs files */ + +static ssize_t rmi_fn_21_rezero_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +DEVICE_ATTR(rezero, RMI_WO_ATTR, + rmi_show_error, + rmi_fn_21_rezero_store); + +static struct attribute *attrs4[] = { + attrify(rezero), + NULL +}; +static struct attribute_group attrs_command = GROUP(attrs4); + +static int rmi_f21_init(struct rmi_function_container *fc) +{ + int retval = 0; + + dev_info(&fc->dev, "Intializing F21."); + + retval = rmi_f21_alloc_memory(fc); + if (retval < 0) + goto error_exit; + + retval = rmi_f21_initialize(fc); + if (retval < 0) + goto error_exit; + + retval = rmi_f21_create_sysfs(fc); + if (retval < 0) + goto error_exit; + + return retval; + +error_exit: + rmi_f21_free_memory(fc); + + return retval; +} + +static int rmi_f21_alloc_memory(struct rmi_function_container *fc) +{ + struct rmi_fn_21_data *f21; + + f21 = kzalloc(sizeof(struct rmi_fn_21_data), GFP_KERNEL); + if (!f21) { + dev_err(&fc->dev, "Failed to allocate rmi_fn_21_data.\n"); + return -ENOMEM; + } + fc->data = f21; + + return 0; +} + + +static void rmi_f21_free_memory(struct rmi_function_container *fc) +{ + struct rmi_fn_21_data *f21 = fc->data; + u8 int_num = f21->query.max_force_sensor_count; + sysfs_remove_group(&fc->dev.kobj, &attrs_query); + sysfs_remove_group(&fc->dev.kobj, &attrs_control); + switch(int_num) { + case 7: + sysfs_remove_file(&fc->dev.kobj, attrify(int_en_force_6)); + case 6: + sysfs_remove_file(&fc->dev.kobj, attrify(int_en_force_5)); + case 5: + sysfs_remove_file(&fc->dev.kobj, attrify(int_en_force_4)); + case 4: + sysfs_remove_file(&fc->dev.kobj, attrify(int_en_force_3)); + case 3: + sysfs_remove_file(&fc->dev.kobj, attrify(int_en_force_2)); + case 2: + sysfs_remove_file(&fc->dev.kobj, attrify(int_en_force_1)); + case 1: + sysfs_remove_file(&fc->dev.kobj, attrify(int_en_force_0)); + default: + break; + } + sysfs_remove_group(&fc->dev.kobj, &attrs_data); + sysfs_remove_group(&fc->dev.kobj, &attrs_command); + if (f21) { + kfree(f21->control.reg_0__3); + kfree(f21->control.reg_4->regs); + kfree(f21->control.reg_4); + kfree(f21->control.reg_5->regs); + kfree(f21->control.reg_5); + kfree(f21->control.reg_6->regs); + kfree(f21->control.reg_6); + kfree(f21->control.reg_7->regs); + kfree(f21->control.reg_7); + kfree(f21->control.reg_8->regs); + kfree(f21->control.reg_8); + kfree(f21); + fc->data = NULL; + } +} + + +static int rmi_f21_initialize(struct rmi_function_container *fc) +{ + struct rmi_fn_21_data *instance_data = fc->data; + int retval = 0; + u16 next_loc; + + /* Read F21 Query Data */ + instance_data->query.address = fc->fd.query_base_addr; + retval = rmi_read_block(fc->rmi_dev, instance_data->query.address, + (u8 *)&instance_data->query, sizeof(instance_data->query.regs)); + if (retval < 0) { + dev_err(&fc->dev, "Could not read query registers from 0x%04x\n", instance_data->query.address); + return retval; + } + + /* Initialize Control Data */ + next_loc = fc->fd.control_base_addr; + + instance_data->control.reg_0__3 = + kzalloc(sizeof(union f21_2df_control_0__3), GFP_KERNEL); + if (!instance_data->control.reg_0__3) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + instance_data->control.reg_0__3->address = next_loc; + next_loc += sizeof(instance_data->control.reg_0__3->regs); + + instance_data->control.reg_4 = + kzalloc(sizeof(struct f21_2df_control_4), GFP_KERNEL); + if (!instance_data->control.reg_4) { + dev_err(&fc->dev, "Failed to allocate control register."); + return -ENOMEM; + } + instance_data->control.reg_4->length = instance_data->query.max_force_sensor_count; + instance_data->control.reg_4->regs = + kzalloc(sizeof(struct f21_2df_control_4n) + * instance_data->control.reg_4->length, GFP_KERNEL); + if (!instance_data->control.reg_4->regs) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + instance_data->control.reg_4->address = next_loc; + next_loc += instance_data->control.reg_4->length; + + instance_data->control.reg_5 = + kzalloc(sizeof(struct f21_2df_control_5), GFP_KERNEL); + if (!instance_data->control.reg_5) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + instance_data->control.reg_5->length = instance_data->query.max_force_sensor_count; + instance_data->control.reg_5->regs = + kzalloc(sizeof(struct f21_2df_control_5n) + * instance_data->control.reg_5->length, GFP_KERNEL); + if (!instance_data->control.reg_5->regs) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + instance_data->control.reg_5->address = next_loc; + next_loc += instance_data->control.reg_5->length; + + instance_data->control.reg_6 = + kzalloc(sizeof(struct f21_2df_control_6), GFP_KERNEL); + if (!instance_data->control.reg_6) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + instance_data->control.reg_6->length = instance_data->query.max_force_sensor_count; + instance_data->control.reg_6->regs = + kzalloc(sizeof(struct f21_2df_control_6n) + * instance_data->control.reg_6->length, GFP_KERNEL); + if (!instance_data->control.reg_6->regs) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + instance_data->control.reg_6->address = next_loc; + next_loc += instance_data->control.reg_6->length; + + instance_data->control.reg_7 = + kzalloc(sizeof(struct f21_2df_control_7), GFP_KERNEL); + if (!instance_data->control.reg_7) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + instance_data->control.reg_7->length = instance_data->query.max_force_sensor_count; + instance_data->control.reg_7->regs = + kzalloc(sizeof(struct f21_2df_control_7n) + * instance_data->control.reg_7->length, GFP_KERNEL); + if (!instance_data->control.reg_7->regs) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + instance_data->control.reg_7->address = next_loc; + next_loc += instance_data->control.reg_7->length; + + instance_data->control.reg_8 = + kzalloc(sizeof(struct f21_2df_control_8), GFP_KERNEL); + if (!instance_data->control.reg_8) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + instance_data->control.reg_8->length = instance_data->query.max_force_sensor_count; + instance_data->control.reg_8->regs = + kzalloc(sizeof(struct f21_2df_control_8n) + * instance_data->control.reg_8->length, GFP_KERNEL); + if (!instance_data->control.reg_8->regs) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + instance_data->control.reg_8->address = next_loc; + + + /* initialize data registers */ + next_loc = fc->fd.data_base_addr; + + instance_data->data.reg_0__1.force_hi_lo = kzalloc( + 2 * instance_data->query.max_force_sensor_count * sizeof(u8), + GFP_KERNEL); + if (!instance_data->data.reg_0__1.force_hi_lo) { + dev_err(&fc->dev, "Failed to allocate data registers."); + return -ENOMEM; + } + instance_data->data.reg_0__1.address = next_loc; + next_loc += 2 * instance_data->query.max_force_sensor_count; + + instance_data->data.reg_2 = + kzalloc(sizeof(union f21_2df_data_2), GFP_KERNEL); + if (!instance_data->data.reg_2) { + dev_err(&fc->dev, "Failed to allocate data registers."); + return -ENOMEM; + } + instance_data->control.reg_0__3->address = next_loc; + + mutex_init(&instance_data->control_mutex); + return 0; +} + + +static int rmi_f21_create_sysfs(struct rmi_function_container *fc) +{ + struct rmi_fn_21_data *instance_data = fc->data; + u8 int_num = instance_data->query.max_force_sensor_count; + if (int_num > 7) + int_num = 7; + dev_dbg(&fc->dev, "Creating sysfs files."); + + /* Set up sysfs device attributes. */ + if (sysfs_create_group(&fc->dev.kobj, &attrs_query) < 0 ) { + dev_err(&fc->dev, "Failed to create query sysfs files."); + return -ENODEV; + } + if (sysfs_create_group(&fc->dev.kobj, &attrs_control) < 0 ) { + dev_err(&fc->dev, "Failed to create control sysfs files."); + return -ENODEV; + } + switch(int_num) { + case 7: + if (sysfs_create_file(&fc->dev.kobj, attrify(int_en_force_6)) < 0) { + dev_err(&fc->dev, "Failed to create control sysfs files."); + return -ENODEV; + } + case 6: + if (sysfs_create_file(&fc->dev.kobj, attrify(int_en_force_5)) < 0) { + dev_err(&fc->dev, "Failed to create control sysfs files."); + return -ENODEV; + } + case 5: + if (sysfs_create_file(&fc->dev.kobj, attrify(int_en_force_4)) < 0) { + dev_err(&fc->dev, "Failed to create control sysfs files."); + return -ENODEV; + } + case 4: + if (sysfs_create_file(&fc->dev.kobj, attrify(int_en_force_3)) < 0) { + dev_err(&fc->dev, "Failed to create control sysfs files."); + return -ENODEV; + } + case 3: + if (sysfs_create_file(&fc->dev.kobj, attrify(int_en_force_2)) < 0) { + dev_err(&fc->dev, "Failed to create control sysfs files."); + return -ENODEV; + } + case 2: + if (sysfs_create_file(&fc->dev.kobj, attrify(int_en_force_1)) < 0) { + dev_err(&fc->dev, "Failed to create control sysfs files."); + return -ENODEV; + } + case 1: + if (sysfs_create_file(&fc->dev.kobj, attrify(int_en_force_0)) < 0) { + dev_err(&fc->dev, "Failed to create control sysfs files."); + return -ENODEV; + } + default: + break; + } + if (sysfs_create_group(&fc->dev.kobj, &attrs_data) < 0 ) { + dev_err(&fc->dev, "Failed to create data sysfs files."); + return -ENODEV; + } + if (sysfs_create_group(&fc->dev.kobj, &attrs_command) < 0 ) { + dev_err(&fc->dev, "Failed to create command sysfs files."); + return -ENODEV; + } + return 0; +} + + +static int rmi_f21_config(struct rmi_function_container *fc) +{ + struct rmi_fn_21_data *data = fc->data; +/* repeated register functions */ + + /* Write Control Register values back to device */ + rmi_write_block(fc->rmi_dev, data->control.reg_0__3->address, + (u8 *)data->control.reg_0__3, + sizeof(data->control.reg_0__3->regs)); + + rmi_write_block(fc->rmi_dev, data->control.reg_4->address, + (u8*) data->control.reg_4->regs, + data->query.max_force_sensor_count * sizeof(u8)); + + rmi_write_block(fc->rmi_dev, data->control.reg_5->address, + (u8*) data->control.reg_5->regs, + data->query.max_force_sensor_count * sizeof(u8)); + + rmi_write_block(fc->rmi_dev, data->control.reg_6->address, + (u8*) data->control.reg_6->regs, + data->query.max_force_sensor_count * sizeof(u8)); + + rmi_write_block(fc->rmi_dev, data->control.reg_7->address, + (u8*) data->control.reg_7->regs, + data->query.max_force_sensor_count * sizeof(u8)); + + rmi_write_block(fc->rmi_dev, data->control.reg_8->address, + (u8*) data->control.reg_8->regs, + data->query.max_force_sensor_count * sizeof(u8)); + + + return 0; +} + +static void rmi_f21_remove(struct rmi_function_container *fc) +{ + + dev_info(&fc->dev, "Removing F21."); + rmi_f21_free_memory(fc); +} + +/* sysfs functions */ +/* Query */ +simple_show_union_struct_unsigned(query, max_force_sensor_count) +simple_show_union_struct_unsigned(query, has_high_resolution) + +/* Control */ +show_store_union_struct_unsigned(control, reg_0__3, reporting_mode) +show_store_union_struct_unsigned(control, reg_0__3, no_rezero) + +show_store_union_struct_unsigned(control, reg_0__3, force_click_threshold) + +show_store_union_struct_unsigned(control, reg_0__3, int_en_force_0) +show_store_union_struct_unsigned(control, reg_0__3, int_en_force_1) +show_store_union_struct_unsigned(control, reg_0__3, int_en_force_2) +show_store_union_struct_unsigned(control, reg_0__3, int_en_force_3) +show_store_union_struct_unsigned(control, reg_0__3, int_en_force_4) +show_store_union_struct_unsigned(control, reg_0__3, int_en_force_5) +show_store_union_struct_unsigned(control, reg_0__3, int_en_force_6) +show_store_union_struct_unsigned(control, reg_0__3, int_en_click) +show_store_union_struct_unsigned(control, reg_0__3, force_interrupt_threshold) + + +/* repeated register functions */ +show_store_repeated_union_struct_unsigned(control, reg_4, use_cfg_cal) +show_store_repeated_union_struct_unsigned(control, reg_4, one_newton_calibration) +show_store_repeated_union_struct_unsigned(control, reg_5, x_location) +show_store_repeated_union_struct_unsigned(control, reg_6, y_location) +show_store_repeated_union_struct_unsigned(control, reg_7, transmitter_force_sensor) +show_store_repeated_union_struct_unsigned(control, reg_8, receiver_force_sensor) + +/* Data */ +static ssize_t rmi_fn_21_force_show(struct device *dev, + struct device_attribute *attr, + char *buf) { + struct rmi_function_container *fc; + struct FUNCTION_DATA *data; + int reg_length; + int result, size = 0; + char *temp; + int i; + + fc = to_rmi_function_container(dev); + data = fc->data; + + /* Read current regtype values */ + reg_length = data->query.max_force_sensor_count; + result = rmi_read_block(fc->rmi_dev, data->data.reg_0__1.address, + data->data.reg_0__1.force_hi_lo, + 2 *reg_length * sizeof(u8)); + + if (result < 0) { + dev_err(dev, "%s : Could not read regtype at 0x%x\nData may be outdated.", __func__, + data->data.reg_0__1.address); + } + temp = buf; + for (i = 0; i < reg_length; i++) { + result = snprintf(temp, PAGE_SIZE - size, "%d ", + data->data.reg_0__1.force_hi_lo[i] * (2 << 3) + + data->data.reg_0__1.force_hi_lo[i + reg_length]); + if (result < 0) { + dev_err(dev, "%s : Could not write output.", __func__); + return result; + } + size += result; + temp += result; + } + result = snprintf(temp, PAGE_SIZE - size, "\n"); + if (result < 0) { + dev_err(dev, "%s : Could not write output.", __func__); + return result; + } + return size + result; +} + +show_union_struct_unsigned(data, reg_2, force_click) + +/* Command */ + +static ssize_t rmi_fn_21_rezero_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { + unsigned long val; + int error, result; + struct rmi_function_container *fc; + struct rmi_fn_21_data *instance_data; + struct rmi_driver *driver; + u8 command; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + driver = fc->rmi_dev->driver; + + /* need to convert the string data to an actual value */ + error = strict_strtoul(buf, 10, &val); + if (error) + return error; + /* Do nothing if not set to 1. This prevents accidental commands. */ + if (val != 1) + return count; + + command = (unsigned char)F21_REZERO_CMD; + + /* Write the command to the command register */ + result = rmi_write_block(fc->rmi_dev, fc->fd.command_base_addr, + &command, 1); + if (result < 0) { + dev_err(dev, "%s : Could not write command to 0x%x\n", + __func__, fc->fd.command_base_addr); + return result; + } + return count; +} + +static struct rmi_function_handler function_handler = { + .func = 0x21, + .init = rmi_f21_init, + .config = rmi_f21_config, + .reset = NULL, + .attention = NULL, + .remove = rmi_f21_remove +}; + +static int __init rmi_f21_module_init(void) +{ + int error; + + error = rmi_register_function_driver(&function_handler); + if (error < 0) { + pr_err("%s: register failed!\n", __func__); + return error; + } + return 0; +} + +static void rmi_f21_module_exit(void) +{ + rmi_unregister_function_driver(&function_handler); +} + +module_init(rmi_f21_module_init); +module_exit(rmi_f21_module_exit); + +MODULE_AUTHOR("Daniel Rosenberg "); +MODULE_DESCRIPTION("RMI F21 module"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(RMI_DRIVER_VERSION); diff --git a/drivers/input/touchscreen/rmi4/rmi_f34.c b/drivers/input/touchscreen/rmi4/rmi_f34.c new file mode 100755 index 000000000000..3a93a32b9a0b --- /dev/null +++ b/drivers/input/touchscreen/rmi4/rmi_f34.c @@ -0,0 +1,962 @@ +/* + * Copyright (c) 2011 Synaptics Incorporated + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include "rmi_driver.h" + +/* define fn $34 commands */ +#define WRITE_FW_BLOCK 0x2 +#define ERASE_ALL 0x3 +#define READ_CONFIG_BLOCK 0x5 +#define WRITE_CONFIG_BLOCK 0x6 +#define ERASE_CONFIG 0x7 +#define ENABLE_FLASH_PROG 0xf + +#define STATUS_IN_PROGRESS 0xff +#define STATUS_IDLE 0x80 + +#define PDT_START_SCAN_LOCATION 0x00e9 +#define PDT_END_SCAN_LOCATION 0x0005 + +#define BLK_SZ_OFF 3 +#define IMG_BLK_CNT_OFF 5 +#define CFG_BLK_CNT_OFF 7 + +#define BLK_NUM_OFF 2 + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32) +#define KERNEL_VERSION_ABOVE_2_6_32 1 +#endif + +/* data specific to fn $34 that needs to be kept around */ +struct rmi_fn_34_data { + unsigned char status; + unsigned char cmd; + unsigned short bootloaderid; + unsigned short blocksize; + unsigned short imageblockcount; + unsigned short configblockcount; + unsigned short blocknum; + bool inflashprogmode; + struct mutex attn_mutex; +}; + +static ssize_t rmi_fn_34_status_show(struct device *dev, + struct device_attribute *attr, char *buf); + + +static ssize_t rmi_fn_34_status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t rmi_fn_34_cmd_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t rmi_fn_34_cmd_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +#ifdef KERNEL_VERSION_ABOVE_2_6_32 +static ssize_t rmi_fn_34_data_read(struct file *data_file, struct kobject *kobj, + struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count); + +static ssize_t rmi_fn_34_data_write(struct file *data_file, + struct kobject *kobj, + struct bin_attribute *attributes, char *buf, + loff_t pos, size_t count); +#else +static ssize_t rmi_fn_34_data_read(struct kobject *kobj, + struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count); + +static ssize_t rmi_fn_34_data_write(struct kobject *kobj, + struct bin_attribute *attributes, char *buf, + loff_t pos, size_t count); +#endif + +static ssize_t rmi_fn_34_bootloaderid_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_34_bootloaderid_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t rmi_fn_34_blocksize_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_34_imageblockcount_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_34_configblockcount_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_34_blocknum_show(struct device *dev, + struct device_attribute *attr, + char *buf); + +static ssize_t rmi_fn_34_blocknum_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t rmi_fn_34_rescanPDT_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + + +static int rmi_f34_alloc_memory(struct rmi_function_container *fc); + +static void rmi_f34_free_memory(struct rmi_function_container *fc); + +static int rmi_f34_initialize(struct rmi_function_container *fc); + +static int rmi_f34_config(struct rmi_function_container *fc); + +static int rmi_f34_reset(struct rmi_function_container *fc); + +static int rmi_f34_create_sysfs(struct rmi_function_container *fc); + + + +static struct device_attribute attrs[] = { + __ATTR(status, RMI_RW_ATTR, + rmi_fn_34_status_show, rmi_fn_34_status_store), + + /* Also, sysfs will need to have a file set up to distinguish + * between commands - like Config write/read, Image write/verify. */ + __ATTR(cmd, RMI_RW_ATTR, + rmi_fn_34_cmd_show, rmi_fn_34_cmd_store), + __ATTR(bootloaderid, RMI_RW_ATTR, + rmi_fn_34_bootloaderid_show, rmi_fn_34_bootloaderid_store), + __ATTR(blocksize, RMI_RO_ATTR, + rmi_fn_34_blocksize_show, rmi_store_error), + __ATTR(imageblockcount, RMI_RO_ATTR, + rmi_fn_34_imageblockcount_show, rmi_store_error), + __ATTR(configblockcount, RMI_RO_ATTR, + rmi_fn_34_configblockcount_show, rmi_store_error), + __ATTR(blocknum, RMI_RW_ATTR, + rmi_fn_34_blocknum_show, rmi_fn_34_blocknum_store), + __ATTR(rescanPDT, RMI_WO_ATTR, + rmi_show_error, rmi_fn_34_rescanPDT_store) +}; + +struct bin_attribute dev_attr_data = { + .attr = { + .name = "data", + .mode = 0666}, + .size = 0, + .read = rmi_fn_34_data_read, + .write = rmi_fn_34_data_write, +}; + + +static int rmi_f34_init(struct rmi_function_container *fc) +{ + int retval; + + dev_info(&fc->dev, "Intializing f34 values."); + + /* init instance data, fill in values and create any sysfs files */ + retval = rmi_f34_alloc_memory(fc); + if (retval < 0) + goto exit_free_data; + + retval = rmi_f34_initialize(fc); + if (retval < 0) + goto exit_free_data; + + retval = rmi_f34_create_sysfs(fc); + if (retval < 0) + goto exit_free_data; + + return 0; + +exit_free_data: + rmi_f34_free_memory(fc); + + return retval; +} + +static int rmi_f34_alloc_memory(struct rmi_function_container *fc) +{ + struct rmi_fn_34_data *f34; + + f34 = kzalloc(sizeof(struct rmi_fn_34_data), GFP_KERNEL); + if (!f34) { + dev_err(&fc->dev, "Failed to allocate rmi_fn_34_data.\n"); + return -ENOMEM; + } + fc->data = f34; + + return 0; +} + +static void rmi_f34_free_memory(struct rmi_function_container *fc) +{ + kfree(fc->data); + fc->data = NULL; +} + +static int rmi_f34_initialize(struct rmi_function_container *fc) +{ + struct rmi_device *rmi_dev = fc->rmi_dev; + struct rmi_device_platform_data *pdata; + int retval = 0; + struct rmi_fn_34_data *f34 = fc->data; + u16 query_base_addr; + u16 control_base_addr; + unsigned char buf[2]; + + pdata = to_rmi_platform_data(rmi_dev); + dev_dbg(&fc->dev, "Initializing F34 values for %s.\n", + pdata->sensor_name); + + mutex_init(&f34->attn_mutex); + + /* get the Bootloader ID and Block Size. */ + query_base_addr = fc->fd.query_base_addr; + control_base_addr = fc->fd.control_base_addr; + + retval = rmi_read_block(fc->rmi_dev, query_base_addr, buf, + ARRAY_SIZE(buf)); + + if (retval < 0) { + dev_err(&fc->dev, "Could not read bootloaderid from 0x%04x.\n", + query_base_addr); + return retval; + } + + batohs(&f34->bootloaderid, buf); + + retval = rmi_read_block(fc->rmi_dev, query_base_addr + BLK_SZ_OFF, buf, + ARRAY_SIZE(buf)); + + if (retval < 0) { + dev_err(&fc->dev, "Could not read block size from 0x%04x, " + "error=%d.\n", query_base_addr + BLK_SZ_OFF, retval); + return retval; + } + batohs(&f34->blocksize, buf); + + /* Get firmware image block count and store it in the instance data */ + retval = rmi_read_block(fc->rmi_dev, query_base_addr + IMG_BLK_CNT_OFF, + buf, ARRAY_SIZE(buf)); + + if (retval < 0) { + dev_err(&fc->dev, "Couldn't read image block count from 0x%x, " + "error=%d.\n", query_base_addr + IMG_BLK_CNT_OFF, + retval); + return retval; + } + batohs(&f34->imageblockcount, buf); + + /* Get config block count and store it in the instance data */ + retval = rmi_read_block(fc->rmi_dev, query_base_addr + 7, buf, + ARRAY_SIZE(buf)); + + if (retval < 0) { + dev_err(&fc->dev, "Couldn't read config block count from 0x%x, " + "error=%d.\n", query_base_addr + CFG_BLK_CNT_OFF, + retval); + return retval; + } + batohs(&f34->configblockcount, buf); + + return 0; +} + +static int rmi_f34_create_sysfs(struct rmi_function_container *fc) +{ + int attr_count = 0; + int rc; + + dev_dbg(&fc->dev, "Creating sysfs files."); + + /* We need a sysfs file for the image/config block to write or read. + * Set up sysfs bin file for binary data block. Since the image is + * already in our format there is no need to convert the data for + * endianess. */ + rc = sysfs_create_bin_file(&fc->dev.kobj, + &dev_attr_data); + if (rc < 0) { + dev_err(&fc->dev, "Failed to create sysfs file for F34 data " + "(error = %d).\n", rc); + return -ENODEV; + } + + /* Set up sysfs device attributes. */ + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { + if (sysfs_create_file + (&fc->dev.kobj, &attrs[attr_count].attr) < 0) { + dev_err(&fc->dev, "Failed to create sysfs file for %s.", + attrs[attr_count].attr.name); + rc = -ENODEV; + goto err_remove_sysfs; + } + } + + return 0; + +err_remove_sysfs: + sysfs_remove_bin_file(&fc->dev.kobj, &dev_attr_data); + + for (attr_count--; attr_count >= 0; attr_count--) + sysfs_remove_file(&fc->dev.kobj, + &attrs[attr_count].attr); + return rc; +} + +static int rmi_f34_config(struct rmi_function_container *fc) +{ + /* for this function we should do nothing here */ + return 0; +} + + +static int rmi_f34_reset(struct rmi_function_container *fc) +{ + struct rmi_fn_34_data *instance_data = fc->data; + + instance_data->status = ECONNRESET; + + return 0; +} + +static void rmi_f34_remove(struct rmi_function_container *fc) +{ + int attr_count; + + sysfs_remove_bin_file(&fc->dev.kobj, + &dev_attr_data); + + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) + sysfs_remove_file(&fc->dev.kobj, + &attrs[attr_count].attr); + + rmi_f34_free_memory(fc); +} + +static int f34_read_status(struct rmi_function_container *fc) +{ + struct rmi_fn_34_data *instance_data = fc->data; + u16 data_base_addr = fc->fd.data_base_addr; + u8 status; + int retval; + + if (instance_data->status == ECONNRESET) + return instance_data->status; + + /* Read the Fn $34 status from F34_Flash_Data3 to see the previous + * commands status. F34_Flash_Data3 will be the address after the + * 2 block number registers plus blocksize Data registers. + * inform user space - through a sysfs param. */ + retval = rmi_read(fc->rmi_dev, + data_base_addr + instance_data->blocksize + + BLK_NUM_OFF, &status); + + if (retval < 0) { + dev_err(&fc->dev, "Could not read status from 0x%x\n", + data_base_addr + instance_data->blocksize + BLK_NUM_OFF); + status = 0xff; /* failure */ + } + + /* set a sysfs value that the user mode can read - only + * upper 4 bits are the status. successful is $80, anything + * else is failure */ + instance_data->status = status & 0xf0; + + /* put mode into Flash Prog Mode when we successfully do + * an Enable Flash Prog cmd. */ + if ((instance_data->status == STATUS_IDLE) && + (instance_data->cmd == ENABLE_FLASH_PROG)) + instance_data->inflashprogmode = true; + + return retval; +} + +int rmi_f34_attention(struct rmi_function_container *fc, u8 *irq_bits) +{ + int retval; + struct rmi_fn_34_data *data = fc->data; + + mutex_lock(&data->attn_mutex); + retval = f34_read_status(fc); + mutex_unlock(&data->attn_mutex); + return retval; +} + +static struct rmi_function_handler function_handler = { + .func = 0x34, + .init = rmi_f34_init, + .config = rmi_f34_config, + .reset = rmi_f34_reset, + .attention = rmi_f34_attention, + .remove = rmi_f34_remove +}; + +static ssize_t rmi_fn_34_bootloaderid_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_34_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->bootloaderid); +} + +static ssize_t rmi_fn_34_bootloaderid_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + int error; + unsigned long val; + unsigned char data[2]; + struct rmi_function_container *fc; + struct rmi_fn_34_data *instance_data; + u16 data_base_addr; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + /* need to convert the string data to an actual value */ + error = strict_strtoul(buf, 10, &val); + + if (error) + return error; + + instance_data->bootloaderid = val; + + /* Write the Bootloader ID key data back to the first two Block + * Data registers (F34_Flash_Data2.0 and F34_Flash_Data2.1). */ + hstoba(data, (unsigned short)val); + data_base_addr = fc->fd.data_base_addr; + + error = rmi_write_block(fc->rmi_dev, + data_base_addr + BLK_NUM_OFF, + data, + ARRAY_SIZE(data)); + + if (error < 0) { + dev_err(dev, "%s : Could not write bootloader id to 0x%x\n", + __func__, data_base_addr + BLK_NUM_OFF); + return error; + } + + return count; +} + +static ssize_t rmi_fn_34_blocksize_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_34_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->blocksize); +} + +static ssize_t rmi_fn_34_imageblockcount_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_34_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", + instance_data->imageblockcount); +} + +static ssize_t rmi_fn_34_configblockcount_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_34_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", + instance_data->configblockcount); +} + +static ssize_t rmi_fn_34_status_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_34_data *instance_data; + int retval; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + mutex_lock(&instance_data->attn_mutex); + retval = f34_read_status(fc); + mutex_unlock(&instance_data->attn_mutex); + + if (retval < 0) + return retval; + + return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->status); +} + + +static ssize_t rmi_fn_34_status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct rmi_fn_34_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + instance_data->status = 0; + + return 0; +} + + +static ssize_t rmi_fn_34_cmd_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_34_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->cmd); +} + +static ssize_t rmi_fn_34_cmd_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct rmi_function_container *fc; + struct rmi_fn_34_data *instance_data; + unsigned long val; + u16 data_base_addr; + int error; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + data_base_addr = fc->fd.data_base_addr; + + /* need to convert the string data to an actual value */ + error = strict_strtoul(buf, 10, &val); + if (error) + return error; + + /* make sure we are in Flash Prog mode for all cmds except the + * Enable Flash Programming cmd - otherwise we are in error */ + if ((val != ENABLE_FLASH_PROG) && !instance_data->inflashprogmode) { + dev_err(dev, "%s: CANNOT SEND CMD %d TO SENSOR - " + "NOT IN FLASH PROG MODE\n" + , __func__, data_base_addr); + return -EINVAL; + } + + instance_data->cmd = val; + + /* Validate command value and (if necessary) write it to the command + * register. + */ + switch (instance_data->cmd) { + case ENABLE_FLASH_PROG: + case ERASE_ALL: + case ERASE_CONFIG: + case WRITE_FW_BLOCK: + case READ_CONFIG_BLOCK: + case WRITE_CONFIG_BLOCK: + /* Reset the status to indicate we are in progress on a cmd. */ + /* The status will change when the ATTN interrupt happens + and the status of the cmd that was issued is read from + the F34_Flash_Data3 register - result should be 0x80 for + success - any other value indicates an error */ + + /* Issue the command to the device. */ + error = rmi_write(fc->rmi_dev, + data_base_addr + instance_data->blocksize + + BLK_NUM_OFF, instance_data->cmd); + + if (error < 0) { + dev_err(dev, "%s: Could not write command 0x%02x " + "to 0x%04x\n", __func__, instance_data->cmd, + data_base_addr + instance_data->blocksize + + BLK_NUM_OFF); + return error; + } + + if (instance_data->cmd == ENABLE_FLASH_PROG) + instance_data->inflashprogmode = true; + + /* set status to indicate we are in progress */ + instance_data->status = STATUS_IN_PROGRESS; + break; + default: + dev_dbg(dev, "%s: RMI4 function $34 - " + "unknown command 0x%02lx.\n", __func__, val); + count = -EINVAL; + break; + } + + return count; +} + +static ssize_t rmi_fn_34_blocknum_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rmi_function_container *fc; + struct rmi_fn_34_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->blocknum); +} + +static ssize_t rmi_fn_34_blocknum_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + int error; + unsigned long val; + unsigned char data[2]; + struct rmi_function_container *fc; + struct rmi_fn_34_data *instance_data; + u16 data_base_addr; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + data_base_addr = fc->fd.data_base_addr; + + /* need to convert the string data to an actual value */ + error = strict_strtoul(buf, 10, &val); + + if (error) + return error; + + instance_data->blocknum = val; + + /* Write the Block Number data back to the first two Block + * Data registers (F34_Flash_Data_0 and F34_Flash_Data_1). */ + hstoba(data, (unsigned short)val); + + error = rmi_write_block(fc->rmi_dev, + data_base_addr, + data, + ARRAY_SIZE(data)); + + if (error < 0) { + dev_err(dev, "%s : Could not write block number %u to 0x%x\n", + __func__, instance_data->blocknum, data_base_addr); + return error; + } + + return count; +} + +static ssize_t rmi_fn_34_rescanPDT_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rmi_function_container *fc; + struct rmi_fn_34_data *instance_data; + struct rmi_device *rmi_dev; + struct rmi_driver_data *driver_data; + struct pdt_entry pdt_entry; + bool fn01found = false; + bool fn34found = false; + unsigned int rescan; + int irq_count = 0; + int retval = 0; + int i; + + /* Rescan of the PDT is needed since issuing the Flash Enable cmd + * the device registers for Fn$01 and Fn$34 moving around because + * of the change from Bootloader mode to Flash Programming mode + * may change to a different PDT with only Fn$01 and Fn$34 that + * could have addresses for query, control, data, command registers + * that differ from the PDT scan done at device initialization. */ + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + rmi_dev = fc->rmi_dev; + driver_data = rmi_get_driverdata(rmi_dev); + + /* Make sure we are only in Flash Programming mode - DON'T + * ALLOW THIS IN UI MODE. */ + if (instance_data->cmd != ENABLE_FLASH_PROG) { + dev_err(dev, "%s: NOT IN FLASH PROG MODE - CAN'T RESCAN PDT.\n" + , __func__); + return -EINVAL; + } + + /* The only good value to write to this is 1, we allow 0, but with + * no effect (this is consistent with the way the command bit works. */ + if (sscanf(buf, "%u", &rescan) != 1) + return -EINVAL; + if (rescan < 0 || rescan > 1) + return -EINVAL; + + /* 0 has no effect, so we skip it entirely. */ + if (rescan) { + /* rescan the PDT - filling in Fn01 and Fn34 addresses - + * this is only temporary - the device will need to be reset + * to return the PDT to the normal values. */ + + /* mini-parse the PDT - we only have to get Fn$01 and Fn$34 and + since we are Flash Programming mode we only have page 0. */ + for (i = PDT_START_SCAN_LOCATION; i >= PDT_END_SCAN_LOCATION; + i -= sizeof(pdt_entry)) { + retval = rmi_read_block(rmi_dev, i, (u8 *)&pdt_entry, + sizeof(pdt_entry)); + if (retval != sizeof(pdt_entry)) { + dev_err(dev, "%s: err frm rmi_read_block pdt " + "entry data from PDT, " + "error = %d.", __func__, retval); + return retval; + } + + if ((pdt_entry.function_number == 0x00) || + (pdt_entry.function_number == 0xff)) + break; + + dev_dbg(dev, "%s: Found F%.2X\n", + __func__, pdt_entry.function_number); + + /* f01 found - just fill in the new addresses in + * the existing fc. */ + if (pdt_entry.function_number == 0x01) { + struct rmi_function_container *f01_fc = + driver_data->f01_container; + fn01found = true; + f01_fc->fd.query_base_addr = + pdt_entry.query_base_addr; + f01_fc->fd.command_base_addr = + pdt_entry.command_base_addr; + f01_fc->fd.control_base_addr = + pdt_entry.control_base_addr; + f01_fc->fd.data_base_addr = + pdt_entry.data_base_addr; + f01_fc->fd.function_number = + pdt_entry.function_number; + f01_fc->fd.interrupt_source_count = + pdt_entry.interrupt_source_count; + f01_fc->num_of_irqs = + pdt_entry.interrupt_source_count; + f01_fc->irq_pos = irq_count; + + irq_count += f01_fc->num_of_irqs; + + if (fn34found) + break; + } + + /* f34 found - just fill in the new addresses in + * the existing fc. */ + if (pdt_entry.function_number == 0x34) { + fn34found = true; + fc->fd.query_base_addr = + pdt_entry.query_base_addr; + fc->fd.command_base_addr = + pdt_entry.command_base_addr; + fc->fd.control_base_addr = + pdt_entry.control_base_addr; + fc->fd.data_base_addr = + pdt_entry.data_base_addr; + fc->fd.function_number = + pdt_entry.function_number; + fc->fd.interrupt_source_count = + pdt_entry.interrupt_source_count; + fc->num_of_irqs = + pdt_entry.interrupt_source_count; + fc->irq_pos = irq_count; + + irq_count += fc->num_of_irqs; + + if (fn01found) + break; + } + + } + + if (!fn01found || !fn34found) { + dev_err(dev, "%s: failed to find fn$01 or fn$34 trying " + "to do rescan PDT.\n" + , __func__); + return -EINVAL; + } + } + + return count; +} + +#ifdef KERNEL_VERSION_ABOVE_2_6_32 +static ssize_t rmi_fn_34_data_read(struct file *data_file, + struct kobject *kobj, + struct bin_attribute *attributes, + char *buf, + loff_t pos, + size_t count) +#else +static ssize_t rmi_fn_34_data_read(struct kobject *kobj, + struct bin_attribute *attributes, + char *buf, + loff_t pos, + size_t count) +#endif +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct rmi_function_container *fc; + struct rmi_fn_34_data *instance_data; + u16 data_base_addr; + int error; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + data_base_addr = fc->fd.data_base_addr; + + if (count != instance_data->blocksize) { + dev_err(dev, + "%s : Incorrect F34 block size %d. " + "Expected size %d.\n", + __func__, count, instance_data->blocksize); + return -EINVAL; + } + + /* Read the data from flash into buf. The app layer will be blocked + * at reading from the sysfs file. When we return the count (or + * error if we fail) the app will resume. */ + error = rmi_read_block(fc->rmi_dev, data_base_addr + BLK_NUM_OFF, + (unsigned char *)buf, count); + + if (error < 0) { + dev_err(dev, "%s : Could not read data from 0x%04x\n", + __func__, data_base_addr + BLK_NUM_OFF); + return error; + } + + return count; +} + +#ifdef KERNEL_VERSION_ABOVE_2_6_32 +static ssize_t rmi_fn_34_data_write(struct file *data_file, + struct kobject *kobj, + struct bin_attribute *attributes, + char *buf, + loff_t pos, + size_t count) +#else +static ssize_t rmi_fn_34_data_write(struct kobject *kobj, + struct bin_attribute *attributes, + char *buf, + loff_t pos, + size_t count) +#endif +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct rmi_function_container *fc; + struct rmi_fn_34_data *instance_data; + u16 data_base_addr; + int error; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + data_base_addr = fc->fd.data_base_addr; + + /* Write the data from buf to flash. The app layer will be + * blocked at writing to the sysfs file. When we return the + * count (or error if we fail) the app will resume. */ + + if (count != instance_data->blocksize) { + dev_err(dev, + "%s : Incorrect F34 block size %d. " + "Expected size %d.\n", + __func__, count, instance_data->blocksize); + return -EINVAL; + } + + /* Write the data block - only if the count is non-zero */ + if (count) { + error = rmi_write_block(fc->rmi_dev, + data_base_addr + BLK_NUM_OFF, + (unsigned char *)buf, + count); + + if (error < 0) { + dev_err(dev, "%s : Could not write block data " + "to 0x%x\n", __func__, + data_base_addr + BLK_NUM_OFF); + return error; + } + } + + return count; +} + +static int __init rmi_f34_module_init(void) +{ + int error; + + error = rmi_register_function_driver(&function_handler); + if (error < 0) { + pr_err("%s : register failed !\n", __func__); + return error; + } + + return 0; +} + +static void rmi_f34_module_exit(void) +{ + rmi_unregister_function_driver(&function_handler); +} + +module_init(rmi_f34_module_init); +module_exit(rmi_f34_module_exit); + +MODULE_AUTHOR("William Manson +#include +#include +#include +#include +#include +#define FUNCTION_DATA rmi_fn_54_data +#define FNUM 54 + +#include "rmi_driver.h" + +/* Set this to 1 for raw hex dump of returned data. */ +#define RAW_HEX 0 +/* Set this to 1 for human readable dump of returned data. */ +#define HUMAN_READABLE 0 +/* The watchdog timer can be useful when debugging certain firmware related + * issues. + */ +#define F54_WATCHDOG 1 + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32) +#define KERNEL_VERSION_ABOVE_2_6_32 1 +#endif + +/* define fn $54 commands */ +#define GET_REPORT 1 +#define FORCE_CAL 2 + +#define NO_AUTO_CAL_MASK 1 +/* status */ +#define BUSY 1 +#define IDLE 0 + +/* Offsets for data */ +#define RMI_F54_REPORT_DATA_OFFSET 3 +#define RMI_F54_FIFO_OFFSET 1 +#define RMI_F54_NUM_TX_OFFSET 1 +#define RMI_F54_NUM_RX_OFFSET 0 + +/* Fixed sizes of reports */ +#define RMI_54_FULL_RAW_CAP_MIN_MAX_SIZE 4 +#define RMI_54_HIGH_RESISTANCE_SIZE 6 + +/* definitions for F54 Query Registers */ +union f54_ad_query { + struct { + /* query 0 */ + u8 num_of_rx_electrodes; + + /* query 1 */ + u8 num_of_tx_electrodes; + + /* query2 */ + u8 f54_ad_query2_b0__1:2; + u8 has_baseline:1; + u8 has_image8:1; + u8 f54_ad_query2_b4__5:2; + u8 has_image16:1; + u8 f54_ad_query2_b7:1; + + /* query 3.0 and 3.1 */ + u16 clock_rate; + + /* query 4 */ + u8 touch_controller_family; + + /* query 5 */ + u8 has_pixel_touch_threshold_adjustment:1; + u8 f54_ad_query5_b1__7:7; + + /* query 6 */ + u8 has_sensor_assignment:1; + u8 has_interference_metric:1; + u8 has_sense_frequency_control:1; + u8 has_firmware_noise_mitigation:1; + u8 f54_ad_query6_b4:1; + u8 has_two_byte_report_rate:1; + u8 has_one_byte_report_rate:1; + u8 has_relaxation_control:1; + + /* query 7 */ + u8 curve_compensation_mode:2; + u8 f54_ad_query7_b2__7:6; + + /* query 8 */ + u8 f54_ad_query2_b0:1; + u8 has_iir_filter:1; + u8 has_cmn_removal:1; + u8 has_cmn_maximum:1; + u8 has_touch_hysteresis:1; + u8 has_edge_compensation:1; + u8 has_per_frequency_noise_control:1; + u8 f54_ad_query8_b7:1; + + u8 f54_ad_query9; + u8 f54_ad_query10; + u8 f54_ad_query11; + + /* query 12 */ + u8 number_of_sensing_frequencies:4; + u8 f54_ad_query12_b4__7:4; + }; + struct { + u8 regs[14]; + u16 address; + }; +}; + +/* And now for the very large amount of control registers */ + +/* Ctrl registers */ + +union f54_ad_control_0 { + /* control 0 */ + struct { + u8 no_relax:1; + u8 no_scan:1; + u8 f54_ad_ctrl0_b2__7:6; + }; + struct { + u8 regs[1]; + u16 address; + }; +}; + +union f54_ad_control_1 { + /* control 1 */ + struct { + /* control 1 */ + u8 bursts_per_cluster:4; + u8 f54_ad_ctrl1_b4__7:4; + }; + struct { + u8 regs[1]; + u16 address; + }; +}; + +union f54_ad_control_2 { + /* control 2 */ + struct { + u16 saturation_cap; + u16 f54_ctrl2; + }; + struct { + u8 regs[4]; + u16 address; + }; +}; + +union f54_ad_control_3 { + /* control 3 */ + struct { + u16 pixel_touch_threshold; + u16 f54_ctrl3; + }; + struct { + u8 regs[4]; + u16 address; + }; +}; + +union f54_ad_control_4__6 { + struct { + /* control 4 */ + u8 rx_feedback_cap:2; + u8 f54_ad_ctrl4_b2__7:6; + + /* control 5 */ + u8 low_ref_cap:2; + u8 low_ref_feedback_cap:2; + u8 low_ref_polarity:1; + u8 f54_ad_ctrl5_b5__7:3; + + /* control 6 */ + u8 high_ref_cap:2; + u8 high_ref_feedback_cap:2; + u8 high_ref_polarity:1; + u8 f54_ad_ctrl6_b5__7:3; + }; + struct { + u8 regs[3]; + u16 address; + }; +}; + +union f54_ad_control_7 { + struct { + /* control 7 */ + u8 cbc_cap:2; + u8 cbc_polarity:2; + u8 cbc_tx_carrier_selection:1; + u8 f54_ad_ctrl6_b5__7:3; + }; + struct { + u8 regs[1]; + u16 address; + }; +}; + +union f54_ad_control_8__9 { + struct { + /* control 8 */ + u16 integration_duration:10; + u16 f54_ad_ctrl8_b10__15:6; + /* control 9 */ + u8 reset_duration; + u8 f54_ctrl9; + }; + struct { + u8 regs[4]; + u16 address; + }; +}; + +union f54_ad_control_10 { + struct { + /* control 10 */ + u8 noise_sensing_bursts_per_image:4; + u8 f54_ad_ctrl10_b4__7:4; + }; + struct { + u8 regs[1]; + u16 address; + }; +}; + +union f54_ad_control_11 { + struct { + /* control 11 */ + u8 reserved; + u8 f54_ctrl11; + }; + struct { + u8 regs[2]; + u16 address; + }; +}; + +union f54_ad_control_12__13 { + struct { + /* control 12 */ + u8 slow_relaxation_rate; + u8 f54_ctrl12; + + /* control 13 */ + u8 fast_relaxation_rate; + u8 f54_ctrl13; + }; + struct { + u8 regs[4]; + u16 address; + }; +}; + +union f54_ad_control_14 { + struct { + /* control 14 */ + u8 rxs_on_xaxis:1; + u8 curve_comp_on_txs:1; + u8 f54_ad_ctrl14b2__7:6; + }; + struct { + u8 regs[1]; + u16 address; + }; +}; + +struct f54_ad_control_15n { + /*Control 15.* */ + u8 sensor_rx_assignment; +}; + +struct f54_ad_control_15{ + struct f54_ad_control_15n *regs; + u16 address; + u8 length; +}; + +struct f54_ad_control_16n { + /*Control 16.* */ + u8 sensor_tx_assignment; +}; + +struct f54_ad_control_16{ + struct f54_ad_control_16n *regs; + u16 address; + u8 length; +}; + + +/* control 17 */ +struct f54_ad_control_17n { + u8 burst_countb10__8:3; + u8 disable:1; + u8 f54_ad_ctrlb4:1; + u8 filter_bandwidth:3; +}; + +struct f54_ad_control_17{ + struct f54_ad_control_17n *regs; + u16 address; + u8 length; +}; + +struct f54_ad_control_18n { + /*Control 18.* */ + u8 burst_countb7__0n; +}; + +struct f54_ad_control_18{ + struct f54_ad_control_18n *regs; + u16 address; + u8 length; +}; + +struct f54_ad_control_19n { + /*Control 19.* */ + u8 stretch_duration; +}; + +struct f54_ad_control_19{ + struct f54_ad_control_19n *regs; + u16 address; + u8 length; +}; + +union f54_ad_control_20 { + struct { + /* control 20 */ + u8 disable_noise_mitigation:1; + u8 f54_ad_ctrl20b2__7:7; + }; + struct { + u8 regs[1]; + u16 address; + }; +}; + +union f54_ad_control_21 { + struct { + /* control 21 */ + u16 freq_shift_noise_threshold; + u16 f54_ctrl21; + }; + struct { + u8 regs[4]; + u16 address; + }; +}; + +union f54_ad_control_22__26 { + struct { + /* control 22 */ + u8 noise_density_threshold; + u8 f54_ctrl22; + + /* control 23 */ + u16 medium_noise_threshold; + u8 f54_ctrl23; + + /* control 24 */ + u16 high_noise_threshold; + u16 f54_ctrl24; + + /* control 25 */ + u8 noise_density; + u8 f54_ctrl25; + + /* control 26 */ + u8 frame_count; + u8 f54_ctrl26; + }; + struct { + u8 regs[13]; + u16 address; + }; +}; + +union f54_ad_control_27 { + struct { + /* control 27 */ + u8 iir_filter_coef; + u8 f54_ctrl27; + }; + struct { + u8 regs[2]; + u16 address; + }; +}; + +union f54_ad_control_28 { + struct { + /* control 28 */ + u16 quiet_threshold; + u16 f54_ctrl28; + }; + struct { + u8 regs[4]; + u16 address; + }; +}; + + +union f54_ad_control_29 { + struct { + /* control 29 */ + u8 f54_ad_ctrl20b0__6:7; + u8 cmn_filter_disable:1; + }; + struct { + u8 regs[1]; + u16 address; + }; +}; + +union f54_ad_control_30 { + struct { + /* control 30 */ + u8 cmn_filter_max; + u8 f54_ctrl30; + }; + struct { + u8 regs[2]; + u16 address; + }; +}; + +union f54_ad_control_31 { + struct { + /* control 31 */ + u8 touch_hysteresis; + u8 f54_ctrl31; + }; + struct { + u8 regs[2]; + u16 address; + }; +}; + +union f54_ad_control_32__35 { + struct { + /* control 32 */ + u16 rx_low_edge_comp; + u16 f54_ctrl32; + + /* control 33 */ + u16 rx_high_edge_comp; + u16 f54_ctrl33; + + /* control 34 */ + u16 tx_low_edge_comp; + u16 f54_ctrl34; + + /* control 35 */ + u16 tx_high_edge_comp; + u16 f54_ctrl35; + }; + struct { + u8 regs[16]; + u16 address; + }; +}; + +struct f54_ad_control_36n { + /*Control 36.* */ + u8 axis1_comp; +}; + +struct f54_ad_control_36{ + struct f54_ad_control_36n *regs; + u16 address; + u8 length; +}; + +struct f54_ad_control_37n { + /*Control 37.* */ + u8 axis2_comp; +}; + +struct f54_ad_control_37{ + struct f54_ad_control_37n *regs; + u16 address; + u8 length; +}; + +struct f54_ad_control_38n { + /*Control 38.* */ + u8 noise_control_1; +}; + +struct f54_ad_control_38{ + struct f54_ad_control_38n *regs; + u16 address; + u8 length; +}; + +struct f54_ad_control_39n { + /*Control 39.* */ + u8 noise_control_2; +}; + +struct f54_ad_control_39{ + struct f54_ad_control_39n *regs; + u16 address; + u8 length; +}; + +struct f54_ad_control_40n { + /*Control 40.* */ + u8 noise_control_3; +}; + +struct f54_ad_control_40{ + struct f54_ad_control_40n *regs; + u16 address; + u8 length; +}; + +struct f54_ad_control { + union f54_ad_control_0 *reg_0; + union f54_ad_control_1 *reg_1; + union f54_ad_control_2 *reg_2; + union f54_ad_control_3 *reg_3; + union f54_ad_control_4__6 *reg_4__6; + union f54_ad_control_7 *reg_7; + union f54_ad_control_8__9 *reg_8__9; + union f54_ad_control_10 *reg_10; + union f54_ad_control_11 *reg_11; + union f54_ad_control_12__13 *reg_12__13; + union f54_ad_control_14 *reg_14; + /* control 15 */ + struct f54_ad_control_15 *reg_15; + /* control 16 */ + struct f54_ad_control_16 *reg_16; + + /* This register is n repetitions of f54_ad_control_17 */ + struct f54_ad_control_17 *reg_17; + + /* control 18 */ + struct f54_ad_control_18 *reg_18; + + /* control 19 */ + struct f54_ad_control_19 *reg_19; + + union f54_ad_control_20 *reg_20; + union f54_ad_control_21 *reg_21; + union f54_ad_control_22__26 *reg_22__26; + union f54_ad_control_27 *reg_27; + union f54_ad_control_28 *reg_28; + union f54_ad_control_29 *reg_29; + union f54_ad_control_30 *reg_30; + union f54_ad_control_31 *reg_31; + union f54_ad_control_32__35 *reg_32__35; + /* control 36 */ + struct f54_ad_control_36 *reg_36; + + /* control 37 */ + struct f54_ad_control_37 *reg_37; + + /* control 38 */ + struct f54_ad_control_38 *reg_38; + + /* control 39 */ + struct f54_ad_control_39 *reg_39; + + /* control 40 */ + struct f54_ad_control_40 *reg_40; +}; + +/* define report types */ +enum f54_report_types { + F54_8BIT_IMAGE = 1, + F54_16BIT_IMAGE = 2, + F54_RAW_16BIT_IMAGE = 3, + F54_HIGH_RESISTANCE = 4, + F54_TX_TO_TX_SHORT = 5, + F54_RX_TO_RX1 = 7, + F54_TRUE_BASELINE = 9, + F54_FULL_RAW_CAP_MIN_MAX = 13, + F54_RX_OPENS1 = 14, + F54_TX_OPEN = 15, + F54_TX_TO_GROUND = 16, + F54_RX_TO_RX2 = 17, + F54_RX_OPENS2 = 18, + F54_FULL_RAW_CAP = 19, + F54_FULL_RAW_CAP_RX_COUPLING_COMP = 20 +}; + +/* data specific to fn $54 that needs to be kept around */ +struct rmi_fn_54_data { + union f54_ad_query query; + struct f54_ad_control control; + enum f54_report_types report_type; + u16 fifoindex; + signed char status; + bool no_auto_cal; + unsigned int report_size; + unsigned char *report_data; + unsigned int bufsize; + struct mutex data_mutex; + struct mutex status_mutex; + struct mutex control_mutex; +#if F54_WATCHDOG + struct hrtimer watchdog; +#endif + struct rmi_function_container *fc; + struct work_struct work; +}; + +/* sysfs functions */ +show_store_union_struct_prototype(report_type) + +store_union_struct_prototype(get_report) + +store_union_struct_prototype(force_cal) + +show_union_struct_prototype(status) + +#ifdef KERNEL_VERSION_ABOVE_2_6_32 +static ssize_t rmi_fn_54_data_read(struct file *data_file, struct kobject *kobj, + struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count); +#else +static ssize_t rmi_fn_54_data_read(struct kobject *kobj, + struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count); +#endif + +show_union_struct_prototype(num_of_rx_electrodes) +show_union_struct_prototype(num_of_tx_electrodes) +show_union_struct_prototype(has_image16) +show_union_struct_prototype(has_image8) +show_union_struct_prototype(has_baseline) +show_union_struct_prototype(clock_rate) +show_union_struct_prototype(touch_controller_family) +show_union_struct_prototype(has_pixel_touch_threshold_adjustment) +show_union_struct_prototype(has_sensor_assignment) +show_union_struct_prototype(has_interference_metric) +show_union_struct_prototype(has_sense_frequency_control) +show_union_struct_prototype(has_firmware_noise_mitigation) +show_union_struct_prototype(has_two_byte_report_rate) +show_union_struct_prototype(has_one_byte_report_rate) +show_union_struct_prototype(has_relaxation_control) +show_union_struct_prototype(curve_compensation_mode) +show_union_struct_prototype(has_iir_filter) +show_union_struct_prototype(has_cmn_removal) +show_union_struct_prototype(has_cmn_maximum) +show_union_struct_prototype(has_touch_hysteresis) +show_union_struct_prototype(has_edge_compensation) +show_union_struct_prototype(has_per_frequency_noise_control) +show_union_struct_prototype(number_of_sensing_frequencies) +show_store_union_struct_prototype(no_auto_cal) +show_store_union_struct_prototype(fifoindex) + +/* Repeated Control Registers */ +show_union_struct_prototype(sensor_rx_assignment) +show_union_struct_prototype(sensor_tx_assignment) +show_union_struct_prototype(filter_bandwidth) +show_union_struct_prototype(disable) +show_union_struct_prototype(burst_count) +show_union_struct_prototype(stretch_duration) +show_store_union_struct_prototype(axis1_comp) +show_store_union_struct_prototype(axis2_comp) +show_union_struct_prototype(noise_control_1) +show_union_struct_prototype(noise_control_2) +show_union_struct_prototype(noise_control_3) + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ +show_store_union_struct_prototype(no_relax) +show_store_union_struct_prototype(no_scan) +show_store_union_struct_prototype(bursts_per_cluster) +show_store_union_struct_prototype(saturation_cap) +show_store_union_struct_prototype(pixel_touch_threshold) +show_store_union_struct_prototype(rx_feedback_cap) +show_store_union_struct_prototype(low_ref_cap) +show_store_union_struct_prototype(low_ref_feedback_cap) +show_store_union_struct_prototype(low_ref_polarity) +show_store_union_struct_prototype(high_ref_cap) +show_store_union_struct_prototype(high_ref_feedback_cap) +show_store_union_struct_prototype(high_ref_polarity) +show_store_union_struct_prototype(cbc_cap) +show_store_union_struct_prototype(cbc_polarity) +show_store_union_struct_prototype(cbc_tx_carrier_selection) +show_store_union_struct_prototype(integration_duration) +show_store_union_struct_prototype(reset_duration) +show_store_union_struct_prototype(noise_sensing_bursts_per_image) +show_store_union_struct_prototype(slow_relaxation_rate) +show_store_union_struct_prototype(fast_relaxation_rate) +show_store_union_struct_prototype(rxs_on_xaxis) +show_store_union_struct_prototype(curve_comp_on_txs) +show_store_union_struct_prototype(disable_noise_mitigation) +show_store_union_struct_prototype(freq_shift_noise_threshold) +show_store_union_struct_prototype(noise_density_threshold) +show_store_union_struct_prototype(medium_noise_threshold) +show_store_union_struct_prototype(high_noise_threshold) +show_store_union_struct_prototype(noise_density) +show_store_union_struct_prototype(frame_count) +show_store_union_struct_prototype(iir_filter_coef) +show_store_union_struct_prototype(quiet_threshold) +show_store_union_struct_prototype(cmn_filter_disable) +show_store_union_struct_prototype(cmn_filter_max) +show_store_union_struct_prototype(touch_hysteresis) +show_store_union_struct_prototype(rx_low_edge_comp) +show_store_union_struct_prototype(rx_high_edge_comp) +show_store_union_struct_prototype(tx_low_edge_comp) +show_store_union_struct_prototype(tx_high_edge_comp) + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +static struct attribute *attrs[] = { + attrify(report_type), + attrify(get_report), + attrify(force_cal), + attrify(status), + attrify(num_of_rx_electrodes), + attrify(num_of_tx_electrodes), + attrify(has_image16), + attrify(has_image8), + attrify(has_baseline), + attrify(clock_rate), + attrify(touch_controller_family), + attrify(has_pixel_touch_threshold_adjustment), + attrify(has_sensor_assignment), + attrify(has_interference_metric), + attrify(has_sense_frequency_control), + attrify(has_firmware_noise_mitigation), + attrify(has_two_byte_report_rate), + attrify(has_one_byte_report_rate), + attrify(has_relaxation_control), + attrify(curve_compensation_mode), + attrify(has_iir_filter), + attrify(has_cmn_removal), + attrify(has_cmn_maximum), + attrify(has_touch_hysteresis), + attrify(has_edge_compensation), + attrify(has_per_frequency_noise_control), + attrify(number_of_sensing_frequencies), + attrify(no_auto_cal), + attrify(fifoindex), + NULL +}; + +static struct attribute_group attrs_query = GROUP(attrs); + +struct bin_attribute dev_rep_data = { + .attr = { + .name = "rep_data", + .mode = RMI_RO_ATTR}, + .size = 0, + .read = rmi_fn_54_data_read, +}; + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +static struct attribute *attrs_reg_0[] = { + attrify(no_relax), + attrify(no_scan), + NULL +}; + +static struct attribute *attrs_reg_1[] = { + attrify(bursts_per_cluster), + NULL +}; + +static struct attribute *attrs_reg_2[] = { + attrify(saturation_cap), + NULL +}; + +static struct attribute *attrs_reg_3[] = { + attrify(pixel_touch_threshold), + NULL +}; + +static struct attribute *attrs_reg_4__6[] = { + attrify(rx_feedback_cap), + attrify(low_ref_cap), + attrify(low_ref_feedback_cap), + attrify(low_ref_polarity), + attrify(high_ref_cap), + attrify(high_ref_feedback_cap), + attrify(high_ref_polarity), + NULL +}; + +static struct attribute *attrs_reg_7[] = { + attrify(cbc_cap), + attrify(cbc_polarity), + attrify(cbc_tx_carrier_selection), + NULL +}; + +static struct attribute *attrs_reg_8__9[] = { + attrify(integration_duration), + attrify(reset_duration), + NULL +}; + +static struct attribute *attrs_reg_10[] = { + attrify(noise_sensing_bursts_per_image), + NULL +}; + +static struct attribute *attrs_reg_12__13[] = { + attrify(slow_relaxation_rate), + attrify(fast_relaxation_rate), + NULL +}; + +static struct attribute *attrs_reg_14__16[] = { + attrify(rxs_on_xaxis), + attrify(curve_comp_on_txs), + attrify(sensor_rx_assignment), + attrify(sensor_tx_assignment), + NULL +}; + +static struct attribute *attrs_reg_17__19[] = { + attrify(filter_bandwidth), + attrify(disable), + attrify(burst_count), + attrify(stretch_duration), +}; + +static struct attribute *attrs_reg_20[] = { + attrify(disable_noise_mitigation), + NULL +}; + +static struct attribute *attrs_reg_21[] = { + attrify(freq_shift_noise_threshold), + NULL +}; + +static struct attribute *attrs_reg_22__26[] = { + attrify(noise_density_threshold), + attrify(medium_noise_threshold), + attrify(high_noise_threshold), + attrify(noise_density), + attrify(frame_count), + NULL +}; + +static struct attribute *attrs_reg_27[] = { + attrify(iir_filter_coef), + NULL +}; + +static struct attribute *attrs_reg_28[] = { + attrify(quiet_threshold), + NULL +}; + +static struct attribute *attrs_reg_29[] = { + attrify(cmn_filter_disable), + NULL +}; + +static struct attribute *attrs_reg_30[] = { + attrify(cmn_filter_max), + NULL +}; + +static struct attribute *attrs_reg_31[] = { + attrify(touch_hysteresis), + NULL +}; + +static struct attribute *attrs_reg_32__35[] = { + attrify(rx_low_edge_comp), + attrify(rx_high_edge_comp), + attrify(tx_low_edge_comp), + attrify(tx_high_edge_comp), + NULL +}; + +static struct attribute *attrs_reg_36[] = { + attrify(axis1_comp), + NULL + }; + +static struct attribute *attrs_reg_37[] = { + attrify(axis2_comp), + NULL + }; + +static struct attribute *attrs_reg_38__40[] = { + attrify(noise_control_1), + attrify(noise_control_2), + attrify(noise_control_3), + NULL + }; + +static struct attribute_group attrs_ctrl_regs[] = { + GROUP(attrs_reg_0), + GROUP(attrs_reg_1), + GROUP(attrs_reg_2), + GROUP(attrs_reg_3), + GROUP(attrs_reg_4__6), + GROUP(attrs_reg_7), + GROUP(attrs_reg_8__9), + GROUP(attrs_reg_10), + GROUP(attrs_reg_12__13), + GROUP(attrs_reg_14__16), + GROUP(attrs_reg_17__19), + GROUP(attrs_reg_20), + GROUP(attrs_reg_21), + GROUP(attrs_reg_22__26), + GROUP(attrs_reg_27), + GROUP(attrs_reg_28), + GROUP(attrs_reg_29), + GROUP(attrs_reg_30), + GROUP(attrs_reg_31), + GROUP(attrs_reg_32__35), + GROUP(attrs_reg_36), + GROUP(attrs_reg_37), + GROUP(attrs_reg_38__40) +}; + +bool attrs_ctrl_regs_exist[ARRAY_SIZE(attrs_ctrl_regs)]; + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ +#if F54_WATCHDOG +static enum hrtimer_restart clear_status(struct hrtimer *timer); + +static void clear_status_worker(struct work_struct *work); +#endif + +static int rmi_f54_alloc_memory(struct rmi_function_container *fc); + +static void rmi_f54_free_memory(struct rmi_function_container *fc); + +static int rmi_f54_initialize(struct rmi_function_container *fc); + +static int rmi_f54_reset(struct rmi_function_container *fc); + +static int rmi_f54_create_sysfs(struct rmi_function_container *fc); + +static int rmi_f54_init(struct rmi_function_container *fc) +{ + int retval = 0; + struct rmi_fn_54_data *f54; + + dev_info(&fc->dev, "Intializing F54."); + + retval = rmi_f54_alloc_memory(fc); + if (retval < 0) + goto error_exit; + + retval = rmi_f54_initialize(fc); + if (retval < 0) + goto error_exit; + + retval = rmi_f54_create_sysfs(fc); + if (retval < 0) + goto error_exit; + f54 = fc->data; + f54->status = IDLE; + return retval; + +error_exit: + rmi_f54_free_memory(fc); + + return retval; +} + +static int rmi_f54_alloc_memory(struct rmi_function_container *fc) +{ + struct rmi_fn_54_data *f54; + + f54 = kzalloc(sizeof(struct rmi_fn_54_data), GFP_KERNEL); + if (!f54) { + dev_err(&fc->dev, "Failed to allocate rmi_fn_54_data.\n"); + return -ENOMEM; + } + fc->data = f54; + f54->fc = fc; + + + return 0; +} + +static void rmi_f54_free_memory(struct rmi_function_container *fc) +{ + int reg_num; + struct rmi_fn_54_data *f54 = fc->data; + sysfs_remove_group(&fc->dev.kobj, &attrs_query); + for (reg_num = 0; reg_num < ARRAY_SIZE(attrs_ctrl_regs); reg_num++) + sysfs_remove_group(&fc->dev.kobj, &attrs_ctrl_regs[reg_num]); + sysfs_remove_bin_file(&fc->dev.kobj, &dev_rep_data); + if (f54) { + kfree(f54->report_data); + kfree(f54); + fc->data = NULL; + } +} + +static int rmi_f54_reset(struct rmi_function_container *fc) +{ + struct rmi_fn_54_data *data = fc->data; + struct rmi_driver *driver = fc->rmi_dev->driver; + +#if F54_WATCHDOG + hrtimer_cancel(&data->watchdog); +#endif + + mutex_lock(&data->status_mutex); + if (driver->restore_irq_mask) { + dev_dbg(&fc->dev, "Restoring interupts!\n"); + driver->restore_irq_mask(fc->rmi_dev); + } else { + dev_err(&fc->dev, "No way to restore interrupts!\n"); + } + data->status = -ECONNRESET; + mutex_unlock(&data->status_mutex); + + return 0; +} + +static void rmi_f54_remove(struct rmi_function_container *fc) +{ + struct rmi_fn_54_data *data = fc->data; + + dev_info(&fc->dev, "Removing F54."); + + #if F54_WATCHDOG + /* Stop timer */ + hrtimer_cancel(&data->watchdog); + #endif + + rmi_f54_free_memory(fc); +} + +static int rmi_f54_create_sysfs(struct rmi_function_container *fc) { + int reg_num; + int retval; + dev_dbg(&fc->dev, "Creating sysfs files."); + /* Set up sysfs device attributes. */ + + if (sysfs_create_group(&fc->dev.kobj, &attrs_query) < 0 ) { + dev_err(&fc->dev, "Failed to create query sysfs files."); + return -ENODEV; + } + for (reg_num = 0; reg_num < ARRAY_SIZE(attrs_ctrl_regs); + reg_num++) { + if (attrs_ctrl_regs_exist[reg_num]) { + if (sysfs_create_group(&fc->dev.kobj, + &attrs_ctrl_regs[reg_num]) < 0) { + dev_err(&fc->dev, + "Failed to create " + "sysfs file group for reg" + "group %d.", + reg_num); + return -ENODEV; + } + } + } + + /* Binary sysfs file to report the data back */ + retval = sysfs_create_bin_file(&fc->dev.kobj, &dev_rep_data); + if (retval < 0) { + dev_err(&fc->dev, "Failed to create sysfs file for F54 data " + "(error = %d).\n", retval); + return -ENODEV; + } + return 0; +} + + + +static int rmi_f54_initialize(struct rmi_function_container *fc) +{ + struct rmi_fn_54_data *instance_data= fc->data; + struct f54_ad_control *control; + int retval = 0; + u8 size = 0; + u16 next_loc; + u8 reg_num; + + dev_info(&fc->dev, "Intializing F54."); + +#if F54_WATCHDOG + /* Set up watchdog timer to catch unanswered get_report commands */ + hrtimer_init(&instance_data->watchdog, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + instance_data->watchdog.function = clear_status; + + /* work function to do unlocking */ + INIT_WORK(&instance_data->work, clear_status_worker); +#endif + + /* Read F54 Query Data */ + retval = rmi_read_block(fc->rmi_dev, fc->fd.query_base_addr, + (u8 *)&instance_data->query, sizeof(instance_data->query)); + if (retval < 0) { + dev_err(&fc->dev, "Could not read query registers" + " from 0x%04x\n", fc->fd.query_base_addr); + return retval; + } +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + /* Initialize the control registers */ + next_loc = fc->fd.control_base_addr; + reg_num = 0; + control = &instance_data->control; + + attrs_ctrl_regs_exist[reg_num] = true; + reg_num++; + control->reg_0 = kzalloc(sizeof(union f54_ad_control_0), GFP_KERNEL); + if (!control->reg_0) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_0->address = next_loc; + next_loc++; + + if (instance_data->query.touch_controller_family == 0 + || instance_data->query.touch_controller_family == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_1 = kzalloc(sizeof(union f54_ad_control_1), + GFP_KERNEL); + if (!control->reg_1) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_1->address = next_loc; + next_loc++; + } + reg_num++; + + attrs_ctrl_regs_exist[reg_num] = true; + reg_num++; + control->reg_2 = kzalloc(sizeof(union f54_ad_control_2), GFP_KERNEL); + if (!control->reg_2) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_2->address = next_loc += 2; + + if (instance_data->query.has_pixel_touch_threshold_adjustment == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + + control->reg_3 = kzalloc(sizeof(union f54_ad_control_3), + GFP_KERNEL); + if (!control->reg_3) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_3->address = next_loc; + next_loc++; + } + reg_num++; + + if (instance_data->query.touch_controller_family == 0 + || instance_data->query.touch_controller_family == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_4__6 = kzalloc(sizeof(union f54_ad_control_4__6), + GFP_KERNEL); + if (!control->reg_4__6) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_4__6->address = next_loc; + next_loc+=3; + } + reg_num++; + + if (instance_data->query.touch_controller_family == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_7 = kzalloc(sizeof(union f54_ad_control_7), + GFP_KERNEL); + if (!control->reg_7) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_7->address = next_loc; + next_loc++; + } + reg_num++; + + if (instance_data->query.touch_controller_family == 0 + || instance_data->query.touch_controller_family == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_8__9 = kzalloc(sizeof(union f54_ad_control_8__9), + GFP_KERNEL); + if (!control->reg_8__9) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_8__9->address = next_loc; + next_loc+=sizeof(control->reg_8__9->regs); + } + reg_num++; + + if (instance_data->query.has_interference_metric == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_10 = kzalloc(sizeof(union f54_ad_control_10), + GFP_KERNEL); + if (!control->reg_10) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_10->address = next_loc; + next_loc++; + } + reg_num++; + + /* F54 Control Register 11 is reserved */ + next_loc++; + + if (instance_data->query.has_relaxation_control == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_12__13 = kzalloc( + sizeof(union f54_ad_control_12__13), GFP_KERNEL); + if (!control->reg_12__13) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_12__13->address = next_loc; + next_loc+=sizeof(control->reg_12__13->regs); + } + reg_num++; + + if (instance_data->query.has_sensor_assignment == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_14 = kzalloc(sizeof(union f54_ad_control_14), + GFP_KERNEL); + if (!control->reg_14) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + + control->reg_15 = + kzalloc(sizeof(struct f54_ad_control_15), GFP_KERNEL); + if (!control->reg_15) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_15->length = instance_data->query.num_of_rx_electrodes; + control->reg_15->regs = + kzalloc(control->reg_15->length + * sizeof(struct f54_ad_control_15n), GFP_KERNEL); + if (!control->reg_15->regs) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + + control->reg_16 = + kzalloc(sizeof(struct f54_ad_control_16), GFP_KERNEL); + if (!control->reg_16) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_16->length = instance_data->query.num_of_tx_electrodes; + control->reg_16->regs = + kzalloc(control->reg_16->length + * sizeof(struct f54_ad_control_16n), GFP_KERNEL); + if (!control->reg_16->regs) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + + control->reg_14->address = next_loc; + next_loc++; + control->reg_15->address = next_loc; + next_loc += control->reg_15->length; + control->reg_16->address = next_loc; + next_loc += control->reg_16->length; + } + reg_num++; + + if (instance_data->query.has_sense_frequency_control == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + size = instance_data->query.number_of_sensing_frequencies; + + control->reg_17 = + kzalloc(sizeof(struct f54_ad_control_17), GFP_KERNEL); + if (!control->reg_17) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_17->length = size; + control->reg_17->regs = kzalloc(size * sizeof(struct f54_ad_control_17n), GFP_KERNEL); + if (!control->reg_17->regs) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + + control->reg_18 = + kzalloc(sizeof(struct f54_ad_control_18), GFP_KERNEL); + if (!control->reg_18) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_18->length = size; + control->reg_18->regs = kzalloc(size * sizeof(struct f54_ad_control_18n), GFP_KERNEL); + if (!control->reg_18->regs) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + + control->reg_19 = + kzalloc(sizeof(struct f54_ad_control_19), GFP_KERNEL); + if (!control->reg_19) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_19->length = size; + control->reg_19->regs = kzalloc(size * sizeof(struct f54_ad_control_19n), GFP_KERNEL); + if (!control->reg_19->regs) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + + control->reg_17->address = next_loc; + next_loc += size; + control->reg_18->address = next_loc; + next_loc += size; + control->reg_19->address = next_loc; + next_loc += size; + } + reg_num++; + + attrs_ctrl_regs_exist[reg_num] = true; + reg_num++; + control->reg_20 = kzalloc(sizeof(union f54_ad_control_20), GFP_KERNEL); + control->reg_20->address = next_loc; + next_loc++; + + if (instance_data->query.has_sense_frequency_control == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_21 = kzalloc(sizeof(union f54_ad_control_21), + GFP_KERNEL); + control->reg_21->address = next_loc; + next_loc += sizeof(control->reg_21->regs); + } + reg_num++; + + if (instance_data->query.has_sense_frequency_control == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_22__26 = kzalloc( + sizeof(union f54_ad_control_22__26), GFP_KERNEL); + control->reg_22__26->address = next_loc; + next_loc+=sizeof(control->reg_22__26->regs); + } + reg_num++; + + if (instance_data->query.has_iir_filter == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_27 = kzalloc(sizeof(union f54_ad_control_27), + GFP_KERNEL); + control->reg_27->address = next_loc; + next_loc++; + } + reg_num++; + + if (instance_data->query.has_firmware_noise_mitigation == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_28 = kzalloc(sizeof(union f54_ad_control_28), + GFP_KERNEL); + control->reg_28->address = next_loc; + next_loc += sizeof(control->reg_28->regs); + } + reg_num++; + + if (instance_data->query.has_cmn_removal == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_29 = kzalloc(sizeof(union f54_ad_control_29), + GFP_KERNEL); + control->reg_29->address = next_loc; + next_loc++; + } + reg_num++; + + if (instance_data->query.has_cmn_maximum == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_30 = kzalloc(sizeof(union f54_ad_control_30), + GFP_KERNEL); + control->reg_30->address = next_loc; + next_loc++; + } + reg_num++; + + if (instance_data->query.has_touch_hysteresis == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_31 = kzalloc(sizeof(union f54_ad_control_31), + GFP_KERNEL); + control->reg_31->address = next_loc; + next_loc++; + } + reg_num++; + + if (instance_data->query.has_interference_metric == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_32__35 = kzalloc( + sizeof(union f54_ad_control_32__35), GFP_KERNEL); + control->reg_32__35->address = next_loc; + next_loc += 8; + } + reg_num++; + + if (instance_data->query.curve_compensation_mode == 1) { + size = max(instance_data->query.num_of_rx_electrodes, + instance_data->query.num_of_tx_electrodes); + } + if (instance_data->query.curve_compensation_mode == 2) + size = instance_data->query.num_of_rx_electrodes; + if (instance_data->query.curve_compensation_mode == 1 + || instance_data->query.curve_compensation_mode == 2) { + attrs_ctrl_regs_exist[reg_num] = true; + + control->reg_36 = + kzalloc(sizeof(struct f54_ad_control_36), GFP_KERNEL); + if (!control->reg_36) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_36->length = size; + control->reg_36->regs = kzalloc(size * sizeof(struct f54_ad_control_36n), GFP_KERNEL); + if (!control->reg_36->regs) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + + control->reg_36->address = next_loc; + next_loc += size; + } + reg_num++; + + if (instance_data->query.curve_compensation_mode == 2) { + attrs_ctrl_regs_exist[reg_num] = true; + + control->reg_37 = + kzalloc(sizeof(struct f54_ad_control_37), GFP_KERNEL); + if (!control->reg_37) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_37->length = instance_data->query.num_of_tx_electrodes; + control->reg_37->regs = kzalloc(control->reg_37->length + * sizeof(struct f54_ad_control_37n), GFP_KERNEL); + if (!control->reg_37->regs) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + + control->reg_37->address = next_loc; + next_loc += control->reg_37->length; + } + reg_num++; + + if (instance_data->query.has_per_frequency_noise_control == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + + control->reg_38 = + kzalloc(sizeof(struct f54_ad_control_38), GFP_KERNEL); + if (!control->reg_38) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_38->length = instance_data->query.number_of_sensing_frequencies; + control->reg_38->regs = kzalloc(control->reg_38->length + * sizeof(struct f54_ad_control_38n), GFP_KERNEL); + if (!control->reg_38->regs) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + + control->reg_39 = + kzalloc(sizeof(struct f54_ad_control_39), GFP_KERNEL); + if (!control->reg_39) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_39->length = instance_data->query.number_of_sensing_frequencies; + control->reg_39->regs = kzalloc(control->reg_39->length + * sizeof(struct f54_ad_control_39n), GFP_KERNEL); + if (!control->reg_39->regs) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + + control->reg_40 = + kzalloc(sizeof(struct f54_ad_control_40), GFP_KERNEL); + if (!control->reg_40) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + control->reg_40->length = instance_data->query.number_of_sensing_frequencies; + control->reg_40->regs = kzalloc(control->reg_40->length + * sizeof(struct f54_ad_control_40n), GFP_KERNEL); + if (!control->reg_40->regs) { + dev_err(&fc->dev, "Failed to allocate control registers."); + return -ENOMEM; + } + + control->reg_38->address = next_loc; + next_loc += control->reg_38->length; + control->reg_39->address = next_loc; + next_loc += control->reg_39->length; + control->reg_40->address = next_loc; + next_loc += control->reg_40->length; + } + reg_num++; +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + mutex_init(&instance_data->data_mutex); + + mutex_init(&instance_data->status_mutex); + + mutex_init(&instance_data->control_mutex); + + return retval; +} + +static void set_report_size(struct rmi_fn_54_data *data) +{ + u8 rx = data->query.num_of_rx_electrodes; + u8 tx = data->query.num_of_tx_electrodes; + switch (data->report_type) { + case F54_8BIT_IMAGE: + data->report_size = rx * tx; + break; + case F54_16BIT_IMAGE: + case F54_RAW_16BIT_IMAGE: + case F54_TRUE_BASELINE: + case F54_FULL_RAW_CAP: + case F54_FULL_RAW_CAP_RX_COUPLING_COMP: + data->report_size = 2 * rx * tx; + break; + case F54_HIGH_RESISTANCE: + data->report_size = RMI_54_HIGH_RESISTANCE_SIZE; + break; + case F54_FULL_RAW_CAP_MIN_MAX: + data->report_size = RMI_54_FULL_RAW_CAP_MIN_MAX_SIZE; + break; + case F54_TX_TO_TX_SHORT: + case F54_TX_OPEN: + case F54_TX_TO_GROUND: + data->report_size = (tx + 7) / 8; + break; + case F54_RX_TO_RX1: + case F54_RX_OPENS1: + if (rx < tx) + data->report_size = 2 * rx * rx; + else + data->report_size = 2 * rx * tx; + break; + case F54_RX_TO_RX2: + case F54_RX_OPENS2: + if (rx <= tx) + data->report_size = 0; + else + data->report_size = 2 * rx * (rx - tx); + break; + default: + data->report_size = 0; + } +} + +int rmi_f54_attention(struct rmi_function_container *fc, u8 *irq_bits) +{ + struct rmi_driver *driver = fc->rmi_dev->driver; + char fifo[2]; + struct rmi_fn_54_data *data = fc->data; + int error = 0; + + set_report_size(data); + if (data->report_size == 0) { + dev_err(&fc->dev, "Invalid report type set in %s. " + "This should never happen.\n", __func__); + error = -EINVAL; + goto error_exit; + } + /* + * We need to ensure the buffer is big enough. A Buffer size of 0 means + * that the buffer has not been allocated. + */ + if (data->bufsize < data->report_size) { + mutex_lock(&data->data_mutex); + if (data->bufsize > 0) + kfree(data->report_data); + data->report_data = kzalloc(data->report_size, GFP_KERNEL); + if (!data->report_data) { + dev_err(&fc->dev, "Failed to allocate report_data.\n"); + error = -ENOMEM; + data->bufsize = 0; + mutex_unlock(&data->data_mutex); + goto error_exit; + } + data->bufsize = data->report_size; + mutex_unlock(&data->data_mutex); + } + dev_vdbg(&fc->dev, "F54 Interrupt handler is running.\nSize: %d\n", + data->report_size); + /* Write 0 to fifohi and fifolo. */ + fifo[0] = 0; + fifo[1] = 0; + error = rmi_write_block(fc->rmi_dev, fc->fd.data_base_addr + + RMI_F54_FIFO_OFFSET, fifo, sizeof(fifo)); + if (error < 0) + dev_err(&fc->dev, "Failed to write fifo to zero!\n"); + else + error = rmi_read_block(fc->rmi_dev, + fc->fd.data_base_addr + RMI_F54_REPORT_DATA_OFFSET, + data->report_data, data->report_size); + if (error < 0) + dev_err(&fc->dev, "F54 data read failed. Code: %d.\n", error); + else if (error != data->report_size) { + error = -EINVAL; + goto error_exit; + } +#if RAW_HEX + int l; + /* Debugging: Print out the file in hex. */ + pr_info("Report data (raw hex):\n"); + for (l = 0; l < data->report_size; l += 2) { + pr_info("%03d: 0x%02x%02x\n", l/2, + data->report_data[l+1], data->report_data[l]); + } +#endif +#if HUMAN_READABLE + /* Debugging: Print out file in human understandable image */ + switch (data->report_type) { + case F54_16BIT_IMAGE: + case F54_RAW_16BIT_IMAGE: + case F54_TRUE_BASELINE: + case F54_FULL_RAW_CAP: + case F54_FULL_RAW_CAP_RX_COUPLING_COMP: + pr_info("Report data (Image):\n"); + int i, j, k; + char c[2]; + short s; + k = 0; + for (i = 0; i < data->query.num_of_tx_electrodes; + i++) { + for (j = 0; j < + data->query.num_of_rx_electrodes; j++) { + c[0] = data->report_data[k]; + c[1] = data->report_data[k+1]; + memcpy(&s, &c, 2); + if (s < -64) + printk("."); + else if (s < 0) + printk("-"); + else if (s > 64) + printk("*"); + else if (s > 0) + printk("+"); + else + printk("0"); + k += 2; + } + pr_info("\n"); + } + pr_info("EOF\n"); + break; + default: + pr_info("Report type %d debug image not supported", + data->report_type); + } +#endif + error = IDLE; +error_exit: + mutex_lock(&data->status_mutex); + /* Turn back on other interupts, if it + * appears that we turned them off. */ + if (driver->restore_irq_mask) { + dev_dbg(&fc->dev, "Restoring interupts!\n"); + driver->restore_irq_mask(fc->rmi_dev); + } else { + dev_err(&fc->dev, "No way to restore interrupts!\n"); + } + data->status = error; + mutex_unlock(&data->status_mutex); + return data->status; +} + + +#if F54_WATCHDOG +static void clear_status_worker(struct work_struct *work) +{ + struct rmi_fn_54_data *data = container_of(work, + struct rmi_fn_54_data, work); + struct rmi_function_container *fc = data->fc; + struct rmi_driver *driver = fc->rmi_dev->driver; + char command; + int result; + + mutex_lock(&data->status_mutex); + if (data->status == BUSY) { + pr_info("F54 Timout Occured: Determining status.\n"); + result = rmi_read_block(fc->rmi_dev, fc->fd.command_base_addr, + &command, 1); + if (result < 0) { + dev_err(&fc->dev, "Could not read get_report register " + "from 0x%04x\n", fc->fd.command_base_addr); + data->status = -ETIMEDOUT; + } else { + if (command & GET_REPORT) { + dev_warn(&fc->dev, "Report type unsupported!"); + data->status = -EINVAL; + } else { + data->status = -ETIMEDOUT; + } + } + if (driver->restore_irq_mask) { + dev_dbg(&fc->dev, "Restoring interupts!\n"); + driver->restore_irq_mask(fc->rmi_dev); + } else { + dev_err(&fc->dev, "No way to restore interrupts!\n"); + } + } + mutex_unlock(&data->status_mutex); +} + +static enum hrtimer_restart clear_status(struct hrtimer *timer) +{ + struct rmi_fn_54_data *data = container_of(timer, + struct rmi_fn_54_data, watchdog); + schedule_work(&(data->work)); + return HRTIMER_NORESTART; +} +#endif + +/* Check if report_type is valid */ +static bool is_report_type_valid(enum f54_report_types reptype) +{ + /* Basic checks on report_type to ensure we write a valid type + * to the sensor. + * TODO: Check Query3 to see if some specific reports are + * available. This is currently listed as a reserved register. + */ + switch (reptype) { + case F54_8BIT_IMAGE: + case F54_16BIT_IMAGE: + case F54_RAW_16BIT_IMAGE: + case F54_HIGH_RESISTANCE: + case F54_TX_TO_TX_SHORT: + case F54_RX_TO_RX1: + case F54_TRUE_BASELINE: + case F54_FULL_RAW_CAP_MIN_MAX: + case F54_RX_OPENS1: + case F54_TX_OPEN: + case F54_TX_TO_GROUND: + case F54_RX_TO_RX2: + case F54_RX_OPENS2: + case F54_FULL_RAW_CAP: + case F54_FULL_RAW_CAP_RX_COUPLING_COMP: + return true; + break; + default: + return false; + } +} + +/* SYSFS file show/store functions */ +static ssize_t rmi_fn_54_report_type_show(struct device *dev, + struct device_attribute *attr, char *buf) { + struct rmi_function_container *fc; + struct rmi_fn_54_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->report_type); +} + +static ssize_t rmi_fn_54_report_type_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { + int result; + unsigned long val; + unsigned char data; + struct rmi_function_container *fc; + struct rmi_fn_54_data *instance_data; + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + /* need to convert the string data to an actual value */ + result = strict_strtoul(buf, 10, &val); + if (result) + return result; + if (!is_report_type_valid(val)) { + dev_err(dev, "%s : Report type %d is invalid.\n", + __func__, (u8) val); + return -EINVAL; + } + mutex_lock(&instance_data->status_mutex); + if (instance_data->status != BUSY) { + instance_data->report_type = (enum f54_report_types)val; + data = (char)val; + /* Write the Report Type back to the first Block + * Data registers (F54_AD_Data0). */ + result = + rmi_write_block(fc->rmi_dev, fc->fd.data_base_addr, + &data, 1); + mutex_unlock(&instance_data->status_mutex); + if (result < 0) { + dev_err(dev, "%s : Could not write report type to" + " 0x%x\n", __func__, fc->fd.data_base_addr); + return result; + } + return count; + } else { + dev_err(dev, "%s : Report type cannot be changed in the middle" + " of command.\n", __func__); + mutex_unlock(&instance_data->status_mutex); + return -EINVAL; + } +} + +static ssize_t rmi_fn_54_get_report_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { + unsigned long val; + int error, result; + struct rmi_function_container *fc; + struct rmi_fn_54_data *instance_data; + struct rmi_driver *driver; + u8 command; + fc = to_rmi_function_container(dev); + instance_data = fc->data; + driver = fc->rmi_dev->driver; + + /* need to convert the string data to an actual value */ + error = strict_strtoul(buf, 10, &val); + if (error) + return error; + /* Do nothing if not set to 1. This prevents accidental commands. */ + if (val != 1) + return count; + command = (unsigned char)GET_REPORT; + /* Basic checks on report_type to ensure we write a valid type + * to the sensor. + * TODO: Check Query3 to see if some specific reports are + * available. This is currently listed as a reserved register. + */ + if (!is_report_type_valid(instance_data->report_type)) { + dev_err(dev, "%s : Report type %d is invalid.\n", + __func__, instance_data->report_type); + return -EINVAL; + } + mutex_lock(&instance_data->status_mutex); + if (instance_data->status != IDLE) { + if (instance_data->status != BUSY) { + dev_err(dev, "F54 status is in an abnormal state: 0x%x", + instance_data->status); + } + mutex_unlock(&instance_data->status_mutex); + return count; + } + /* Store interrupts */ + /* Do not exit if we fail to turn off interupts. We are likely + * to still get useful data. The report data can, however, be + * corrupted, and there may be unexpected behavior. + */ + dev_dbg(dev, "Storing and overriding interupts\n"); + if (driver->store_irq_mask) + driver->store_irq_mask(fc->rmi_dev, + fc->irq_mask); + else + dev_err(dev, "No way to store interupts!\n"); + instance_data->status = BUSY; + + /* small delay to avoid race condition in firmare. This value is a bit + * higher than absolutely necessary. Should be removed once issue is + * resolved in firmware. */ + + mdelay(2); + + /* Write the command to the command register */ + result = rmi_write_block(fc->rmi_dev, fc->fd.command_base_addr, + &command, 1); + mutex_unlock(&instance_data->status_mutex); + if (result < 0) { + dev_err(dev, "%s : Could not write command to 0x%x\n", + __func__, fc->fd.command_base_addr); + return result; + } +#if F54_WATCHDOG + /* start watchdog timer */ + hrtimer_start(&instance_data->watchdog, ktime_set(1, 0), + HRTIMER_MODE_REL); +#endif + return count; +} + +static ssize_t rmi_fn_54_force_cal_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { + unsigned long val; + int error, result; + struct rmi_function_container *fc; + struct rmi_fn_54_data *instance_data; + struct rmi_driver *driver; + u8 command; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + driver = fc->rmi_dev->driver; + + /* need to convert the string data to an actual value */ + error = strict_strtoul(buf, 10, &val); + if (error) + return error; + /* Do nothing if not set to 1. This prevents accidental commands. */ + if (val != 1) + return count; + + command = (unsigned char)FORCE_CAL; + + if (instance_data->status == BUSY) + return -EBUSY; + /* Write the command to the command register */ + result = rmi_write_block(fc->rmi_dev, fc->fd.command_base_addr, + &command, 1); + if (result < 0) { + dev_err(dev, "%s : Could not write command to 0x%x\n", + __func__, fc->fd.command_base_addr); + return result; + } + return count; +} + +static ssize_t rmi_fn_54_status_show(struct device *dev, + struct device_attribute *attr, char *buf) { + struct rmi_function_container *fc; + struct rmi_fn_54_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%d\n", instance_data->status); +} + +simple_show_union_struct_unsigned(query, num_of_rx_electrodes) +simple_show_union_struct_unsigned(query, num_of_tx_electrodes) +simple_show_union_struct_unsigned(query, has_image16) +simple_show_union_struct_unsigned(query, has_image8) +simple_show_union_struct_unsigned(query, has_baseline) +simple_show_union_struct_unsigned(query, clock_rate) +simple_show_union_struct_unsigned(query, touch_controller_family) +simple_show_union_struct_unsigned(query, has_pixel_touch_threshold_adjustment) +simple_show_union_struct_unsigned(query, has_sensor_assignment) +simple_show_union_struct_unsigned(query, has_interference_metric) +simple_show_union_struct_unsigned(query, has_sense_frequency_control) +simple_show_union_struct_unsigned(query, has_firmware_noise_mitigation) +simple_show_union_struct_unsigned(query, has_two_byte_report_rate) +simple_show_union_struct_unsigned(query, has_one_byte_report_rate) +simple_show_union_struct_unsigned(query, has_relaxation_control) +simple_show_union_struct_unsigned(query, curve_compensation_mode) +simple_show_union_struct_unsigned(query, has_iir_filter) +simple_show_union_struct_unsigned(query, has_cmn_removal) +simple_show_union_struct_unsigned(query, has_cmn_maximum) +simple_show_union_struct_unsigned(query, has_touch_hysteresis) +simple_show_union_struct_unsigned(query, has_edge_compensation) +simple_show_union_struct_unsigned(query, has_per_frequency_noise_control) +simple_show_union_struct_unsigned(query, number_of_sensing_frequencies) + +static ssize_t rmi_fn_54_no_auto_cal_show(struct device *dev, + struct device_attribute *attr, char *buf) { + struct rmi_function_container *fc; + struct rmi_fn_54_data *data; + + fc = to_rmi_function_container(dev); + data = fc->data; + + return snprintf(buf, PAGE_SIZE, "%u\n", + data->no_auto_cal ? 1 : 0); +} + +static ssize_t rmi_fn_54_no_auto_cal_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { + int result; + unsigned long val; + unsigned char data; + struct rmi_function_container *fc; + struct rmi_fn_54_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + /* need to convert the string data to an actual value */ + result = strict_strtoul(buf, 10, &val); + + /* if an error occured, return it */ + if (result) + return result; + /* Do nothing if not 0 or 1. This prevents accidental commands. */ + if (val > 1) + return -EINVAL; + /* Read current control values */ + result = + rmi_read_block(fc->rmi_dev, fc->fd.control_base_addr, &data, 1); + + /* if the current control registers are already set as we want them, do + * nothing to them */ + if ((data & NO_AUTO_CAL_MASK) == val) + return count; + /* Write the control back to the control register (F54_AD_Ctrl0) + * Ignores everything but bit 0 */ + data = (data & ~NO_AUTO_CAL_MASK) | (val & NO_AUTO_CAL_MASK); + result = + rmi_write_block(fc->rmi_dev, fc->fd.control_base_addr, &data, 1); + if (result < 0) { + dev_err(dev, "%s : Could not write control to 0x%x\n", + __func__, fc->fd.control_base_addr); + return result; + } + /* update our internal representation iff the write succeeds */ + instance_data->no_auto_cal = (val == 1); + return count; +} + +static ssize_t rmi_fn_54_fifoindex_show(struct device *dev, + struct device_attribute *attr, char *buf) { + struct rmi_function_container *fc; + struct rmi_fn_54_data *instance_data; + struct rmi_driver *driver; + unsigned char temp_buf[2]; + int retval; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + driver = fc->rmi_dev->driver; + + /* Read fifoindex from device */ + retval = rmi_read_block(fc->rmi_dev, + fc->fd.data_base_addr + RMI_F54_FIFO_OFFSET, + temp_buf, ARRAY_SIZE(temp_buf)); + + if (retval < 0) { + dev_err(dev, "Could not read fifoindex from 0x%04x\n", + fc->fd.data_base_addr + RMI_F54_FIFO_OFFSET); + return retval; + } + batohs(&instance_data->fifoindex, temp_buf); + return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->fifoindex); +} +static ssize_t rmi_fn_54_fifoindex_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + int error; + unsigned long val; + unsigned char data[2]; + struct rmi_function_container *fc; + struct rmi_fn_54_data *instance_data; + + fc = to_rmi_function_container(dev); + instance_data = fc->data; + + /* need to convert the string data to an actual value */ + error = strict_strtoul(buf, 10, &val); + + if (error) + return error; + + instance_data->fifoindex = val; + + /* Write the FifoIndex back to the first data registers. */ + hstoba(data, (unsigned short)val); + + error = rmi_write_block(fc->rmi_dev, + fc->fd.data_base_addr + RMI_F54_FIFO_OFFSET, + data, + ARRAY_SIZE(data)); + + if (error < 0) { + dev_err(dev, "%s : Could not write fifoindex to 0x%x\n", + __func__, fc->fd.data_base_addr + RMI_F54_FIFO_OFFSET); + return error; + } + return count; +} + +/* Provide access to last report */ +#ifdef KERNEL_VERSION_ABOVE_2_6_32 +static ssize_t rmi_fn_54_data_read(struct file *data_file, struct kobject *kobj, + struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count) +#else +static ssize_t rmi_fn_54_data_read(struct kobject *kobj, + struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count) +#endif +{ + struct device *dev; + struct rmi_function_container *fc; + struct rmi_fn_54_data *instance_data; + + dev = container_of(kobj, struct device, kobj); + fc = to_rmi_function_container(dev); + instance_data = fc->data; + mutex_lock(&instance_data->data_mutex); + if (count < instance_data->report_size) { + dev_err(dev, + "%s: F54 report size too large for buffer: %d." + " Need at least: %d for Report type: %d.\n", + __func__, count, instance_data->report_size, + instance_data->report_type); + mutex_unlock(&instance_data->data_mutex); + return -EINVAL; + } + if (instance_data->report_data) { + /* Copy data from instance_data to buffer */ + memcpy(buf, instance_data->report_data, + instance_data->report_size); + mutex_unlock(&instance_data->data_mutex); + dev_dbg(dev, "%s: Presumably successful.", __func__); + return instance_data->report_size; + } else { + dev_err(dev, "%s: F54 report_data does not exist!\n", __func__); + mutex_unlock(&instance_data->data_mutex); + return -EINVAL; + } +} + +/* Repeated Register sysfs functions */ +show_repeated_union_struct_unsigned(control, reg_15, sensor_rx_assignment) +show_repeated_union_struct_unsigned(control, reg_16, sensor_tx_assignment) + +show_repeated_union_struct_unsigned(control, reg_17, filter_bandwidth) +show_repeated_union_struct_unsigned(control, reg_17, disable) + + +static ssize_t rmi_fn_54_burst_count_show(struct device *dev, + struct device_attribute *attr, + char *buf) { + struct rmi_function_container *fc; + struct rmi_fn_54_data *data; + int result, size = 0; + char *temp; + int i; + + fc = to_rmi_function_container(dev); + data = fc->data; + mutex_lock(&data->control_mutex); + /* Read current control values */ + result = rmi_read_block(fc->rmi_dev, data->control.reg_17->address, + (u8 *) data->control.reg_17->regs, + data->control.reg_17->length * sizeof(u8)); + if (result < 0) { + dev_err(dev, "%s : Could not read control at 0x%x\n" + "Data may be outdated.", __func__, + data->control.reg_17->address); + } + + result = rmi_read_block(fc->rmi_dev, data->control.reg_18->address, + (u8 *)data->control.reg_18->regs, + data->control.reg_18->length * sizeof(u8)); + if (result < 0) { + dev_err(dev, "%s : Could not read control at 0x%x\n" + "Data may be outdated.", __func__, + data->control.reg_18->address); + } + mutex_unlock(&data->control_mutex); + temp = buf; + for (i = 0; i < data->control.reg_17->length; i++) { + result = snprintf(temp, PAGE_SIZE - size, "%u ", + (1<<8) * data->control.reg_17->regs[i].burst_countb10__8 + + data->control.reg_18->regs[i].burst_countb7__0n); + size += result; + temp += result; + } + return size + snprintf(temp, PAGE_SIZE - size, "\n"); +} + +show_repeated_union_struct_unsigned(control, reg_19, stretch_duration) +show_store_repeated_union_struct_unsigned(control, reg_36, axis1_comp) +show_store_repeated_union_struct_unsigned(control, reg_37, axis2_comp) + +show_repeated_union_struct_unsigned(control, reg_38, noise_control_1) +show_repeated_union_struct_unsigned(control, reg_39, noise_control_2) +show_repeated_union_struct_unsigned(control, reg_40, noise_control_3) + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +show_store_union_struct_unsigned(control, reg_0, no_relax) +show_store_union_struct_unsigned(control, reg_0, no_scan) +show_store_union_struct_unsigned(control, reg_1, bursts_per_cluster) +show_store_union_struct_unsigned(control, reg_2, saturation_cap) +show_store_union_struct_unsigned(control, reg_3, pixel_touch_threshold) +show_store_union_struct_unsigned(control, reg_4__6, rx_feedback_cap) +show_store_union_struct_unsigned(control, reg_4__6, low_ref_cap) +show_store_union_struct_unsigned(control, reg_4__6, low_ref_feedback_cap) +show_store_union_struct_unsigned(control, reg_4__6, low_ref_polarity) +show_store_union_struct_unsigned(control, reg_4__6, high_ref_cap) +show_store_union_struct_unsigned(control, reg_4__6, high_ref_feedback_cap) +show_store_union_struct_unsigned(control, reg_4__6, high_ref_polarity) +show_store_union_struct_unsigned(control, reg_7, cbc_cap) +show_store_union_struct_unsigned(control, reg_7, cbc_polarity) +show_store_union_struct_unsigned(control, reg_7, cbc_tx_carrier_selection) +show_store_union_struct_unsigned(control, reg_8__9, integration_duration) +show_store_union_struct_unsigned(control, reg_8__9, reset_duration) +show_store_union_struct_unsigned(control, reg_10, noise_sensing_bursts_per_image) +show_store_union_struct_unsigned(control, reg_12__13, slow_relaxation_rate) +show_store_union_struct_unsigned(control, reg_12__13, fast_relaxation_rate) +show_store_union_struct_unsigned(control, reg_14, rxs_on_xaxis) +show_store_union_struct_unsigned(control, reg_14, curve_comp_on_txs) +show_store_union_struct_unsigned(control, reg_20, disable_noise_mitigation) +show_store_union_struct_unsigned(control, reg_21, freq_shift_noise_threshold) +show_store_union_struct_unsigned(control, reg_22__26, noise_density_threshold) +show_store_union_struct_unsigned(control, reg_22__26, medium_noise_threshold) +show_store_union_struct_unsigned(control, reg_22__26, high_noise_threshold) +show_store_union_struct_unsigned(control, reg_22__26, noise_density) +show_store_union_struct_unsigned(control, reg_22__26, frame_count) +show_store_union_struct_unsigned(control, reg_27, iir_filter_coef) +show_store_union_struct_unsigned(control, reg_28, quiet_threshold) +show_store_union_struct_unsigned(control, reg_29, cmn_filter_disable) +show_store_union_struct_unsigned(control, reg_30, cmn_filter_max) +show_store_union_struct_unsigned(control, reg_31, touch_hysteresis) +show_store_union_struct_unsigned(control, reg_32__35, rx_low_edge_comp) +show_store_union_struct_unsigned(control, reg_32__35, rx_high_edge_comp) +show_store_union_struct_unsigned(control, reg_32__35, tx_low_edge_comp) +show_store_union_struct_unsigned(control, reg_32__35, tx_high_edge_comp) + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ +static struct rmi_function_handler function_handler = { + .func = 0x54, + .init = rmi_f54_init, + .config = NULL, + .reset = rmi_f54_reset, + .attention = rmi_f54_attention, + .remove = rmi_f54_remove +}; + +static int __init rmi_f54_module_init(void) +{ + int error; + + error = rmi_register_function_driver(&function_handler); + if (error < 0) { + pr_err("%s: register failed!\n", __func__); + return error; + } + return 0; +} + +static void rmi_f54_module_exit(void) +{ + rmi_unregister_function_driver(&function_handler); +} + +module_init(rmi_f54_module_init); +module_exit(rmi_f54_module_exit); + +MODULE_AUTHOR("Daniel Rosenberg "); +MODULE_DESCRIPTION("RMI F54 module"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(RMI_DRIVER_VERSION); + diff --git a/drivers/input/touchscreen/rmi4/rmi_i2c.c b/drivers/input/touchscreen/rmi4/rmi_i2c.c new file mode 100755 index 000000000000..52c308fd0f40 --- /dev/null +++ b/drivers/input/touchscreen/rmi4/rmi_i2c.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2011 Synaptics Incorporated + * Copyright (c) 2011 Unixphere + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define COMMS_DEBUG 0 + +#define IRQ_DEBUG 0 + +#if COMMS_DEBUG || IRQ_DEBUG +#define DEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rmi_driver.h" +#define RMI_PAGE_SELECT_REGISTER 0xff +#define RMI_I2C_PAGE(addr) (((addr) >> 8) & 0xff) +#ifndef CONFIG_RMI4_I2C_SCL_RATE +#define CONFIG_RMI4_I2C_SCL_RATE 100000 // 100kHz +#endif + + +static char *phys_proto_name = "i2c"; + +struct rmi_i2c_data { + struct mutex page_mutex; + int page; + int enabled; + int irq; + int irq_flags; + struct rmi_phys_device *phys; +}; + +static irqreturn_t rmi_i2c_irq_thread(int irq, void *p) +{ + struct rmi_phys_device *phys = p; + struct rmi_device *rmi_dev = phys->rmi_dev; + struct rmi_driver *driver = rmi_dev->driver; + struct rmi_device_platform_data *pdata = phys->dev->platform_data; + +#if IRQ_DEBUG + dev_dbg(phys->dev, "ATTN gpio, value: %d.\n", + gpio_get_value(pdata->attn_gpio)); +#endif + if (gpio_get_value(pdata->attn_gpio) == pdata->attn_polarity) { + phys->info.attn_count++; + if (driver && driver->irq_handler && rmi_dev) + driver->irq_handler(rmi_dev, irq); + } + + return IRQ_HANDLED; +} + +/* + * rmi_set_page - Set RMI page + * @phys: The pointer to the rmi_phys_device struct + * @page: The new page address. + * + * RMI devices have 16-bit addressing, but some of the physical + * implementations (like SMBus) only have 8-bit addressing. So RMI implements + * a page address at 0xff of every page so we can reliable page addresses + * every 256 registers. + * + * The page_mutex lock must be held when this function is entered. + * + * Returns zero on success, non-zero on failure. + */ +static int rmi_set_page(struct rmi_phys_device *phys, unsigned int page) +{ + struct i2c_client *client = to_i2c_client(phys->dev); + struct rmi_i2c_data *data = phys->data; + char txbuf[2] = {RMI_PAGE_SELECT_REGISTER, page}; + int retval; + +#if COMMS_DEBUG + dev_dbg(&client->dev, "RMI4 I2C writes 3 bytes: %02x %02x\n", + txbuf[0], txbuf[1]); +#endif + phys->info.tx_count++; + phys->info.tx_bytes += sizeof(txbuf); + retval = i2c_master_normal_send(client, txbuf, sizeof(txbuf), CONFIG_RMI4_I2C_SCL_RATE); + if (retval != sizeof(txbuf)) { + phys->info.tx_errs++; + dev_err(&client->dev, + "%s: set page failed: %d.", __func__, retval); + return (retval < 0) ? retval : -EIO; + } + data->page = page; + return 0; +} + +int rmi_i2c_write_block(struct rmi_phys_device *phys, u16 addr, u8 *buf, + int len) +{ + struct i2c_client *client = to_i2c_client(phys->dev); + struct rmi_i2c_data *data = phys->data; + u8 txbuf[len + 1]; + int retval; +#if COMMS_DEBUG + int i; +#endif + + txbuf[0] = addr & 0xff; + memcpy(txbuf + 1, buf, len); + + mutex_lock(&data->page_mutex); + + if (RMI_I2C_PAGE(addr) != data->page) { + retval = rmi_set_page(phys, RMI_I2C_PAGE(addr)); + if (retval < 0) + goto exit; + } + +#if COMMS_DEBUG + dev_dbg(&client->dev, "RMI4 I2C writes %d bytes: ", sizeof(txbuf)); + for (i = 0; i < sizeof(txbuf); i++) + dev_dbg(&client->dev, "%02x ", txbuf[i]); + dev_dbg(&client->dev, "\n"); +#endif + + phys->info.tx_count++; + phys->info.tx_bytes += sizeof(txbuf); + retval = i2c_master_normal_send(client, txbuf, sizeof(txbuf), CONFIG_RMI4_I2C_SCL_RATE); + if (retval < 0) + phys->info.tx_errs++; + else + retval--; /* don't count the address byte */ + +exit: + mutex_unlock(&data->page_mutex); + return retval; +} + +static int rmi_i2c_write(struct rmi_phys_device *phys, u16 addr, u8 data) +{ + int retval = rmi_i2c_write_block(phys, addr, &data, 1); + return (retval < 0) ? retval : 0; +} + +int rmi_i2c_read_block(struct rmi_phys_device *phys, u16 addr, u8 *buf, + int len) +{ + struct i2c_client *client = to_i2c_client(phys->dev); + struct rmi_i2c_data *data = phys->data; + u8 txbuf[1] = {addr & 0xff}; + int retval; +#if COMMS_DEBUG + int i; +#endif + + mutex_lock(&data->page_mutex); + + if (RMI_I2C_PAGE(addr) != data->page) { + retval = rmi_set_page(phys, RMI_I2C_PAGE(addr)); + if (retval < 0) + goto exit; + } + +#if COMMS_DEBUG + dev_dbg(&client->dev, "RMI4 I2C writes 1 bytes: %02x\n", txbuf[0]); +#endif + phys->info.tx_count++; + phys->info.tx_bytes += sizeof(txbuf); + retval = i2c_master_normal_send(client, txbuf, sizeof(txbuf), CONFIG_RMI4_I2C_SCL_RATE); + if (retval != sizeof(txbuf)) { + phys->info.tx_errs++; + retval = (retval < 0) ? retval : -EIO; + goto exit; + } + + retval = i2c_master_normal_recv(client, buf, len, CONFIG_RMI4_I2C_SCL_RATE); + + phys->info.rx_count++; + phys->info.rx_bytes += len; + if (retval < 0) + phys->info.rx_errs++; +#if COMMS_DEBUG + else { + dev_dbg(&client->dev, "RMI4 I2C received %d bytes: ", len); + for (i = 0; i < len; i++) + dev_dbg(&client->dev, "%02x ", buf[i]); + dev_dbg(&client->dev, "\n"); + } +#endif + +exit: + mutex_unlock(&data->page_mutex); + return retval; +} + +static int rmi_i2c_read(struct rmi_phys_device *phys, u16 addr, u8 *buf) +{ + int retval = rmi_i2c_read_block(phys, addr, buf, 1); + return (retval < 0) ? retval : 0; +} + +static int acquire_attn_irq(struct rmi_i2c_data *data) +{ + return request_threaded_irq(data->irq, NULL, rmi_i2c_irq_thread, + data->irq_flags, dev_name(data->phys->dev), data->phys); +} + +static int enable_device(struct rmi_phys_device *phys) +{ + int retval = 0; + + struct rmi_i2c_data *data = phys->data; + + if (data->enabled) + return 0; + + retval = acquire_attn_irq(data); + if (retval) + goto error_exit; + + data->enabled = true; + dev_dbg(phys->dev, "Physical device enabled.\n"); + return 0; + +error_exit: + dev_err(phys->dev, "Failed to enable physical device. Code=%d.\n", + retval); + return retval; +} + +static void disable_device(struct rmi_phys_device *phys) +{ + struct rmi_i2c_data *data = phys->data; + + if (!data->enabled) + return; + + disable_irq(data->irq); + free_irq(data->irq, data->phys); + + dev_dbg(phys->dev, "Physical device disabled.\n"); + data->enabled = false; +} + +void CompleteReflash(struct rmi_phys_device *phys); + +static int __devinit rmi_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct rmi_phys_device *rmi_phys; + struct rmi_i2c_data *data; + struct rmi_device_platform_data *pdata = client->dev.platform_data; + int error; + + if (!pdata) { + dev_err(&client->dev, "no platform data\n"); + return -EINVAL; + } + pr_info("%s: Probing %s at %#02x (IRQ %d).\n", __func__, + pdata->sensor_name ? pdata->sensor_name : "-no name-", + client->addr, pdata->attn_gpio); + + error = i2c_check_functionality(client->adapter, I2C_FUNC_I2C); + if (!error) { + dev_err(&client->dev, "i2c_check_functionality error %d.\n", + error); + return error; + } + + rmi_phys = kzalloc(sizeof(struct rmi_phys_device), GFP_KERNEL); + if (!rmi_phys) + return -ENOMEM; + + data = kzalloc(sizeof(struct rmi_i2c_data), GFP_KERNEL); + if (!data) { + error = -ENOMEM; + goto err_phys; + } + + data->enabled = true; /* We plan to come up enabled. */ + data->irq = gpio_to_irq(pdata->attn_gpio); + if (pdata->level_triggered) { + data->irq_flags = IRQF_ONESHOT | + ((pdata->attn_polarity == RMI_ATTN_ACTIVE_HIGH) ? + IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW); + } else { + data->irq_flags = + (pdata->attn_polarity == RMI_ATTN_ACTIVE_HIGH) ? + IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING; + } + data->phys = rmi_phys; + + rmi_phys->data = data; + rmi_phys->dev = &client->dev; + + rmi_phys->write = rmi_i2c_write; + rmi_phys->write_block = rmi_i2c_write_block; + rmi_phys->read = rmi_i2c_read; + rmi_phys->read_block = rmi_i2c_read_block; + rmi_phys->enable_device = enable_device; + rmi_phys->disable_device = disable_device; + + rmi_phys->info.proto = phys_proto_name; + + mutex_init(&data->page_mutex); + + /* Setting the page to zero will (a) make sure the PSR is in a + * known state, and (b) make sure we can talk to the device. + */ + error = rmi_set_page(rmi_phys, 0); + if (error) { + dev_err(&client->dev, "Failed to set page select to 0.\n"); + goto err_data; + } + + if (pdata->gpio_config) { + error = pdata->gpio_config(pdata->gpio_data, true); + if (error < 0) { + dev_err(&client->dev, "failed to setup irq %d\n", + pdata->attn_gpio); + goto err_data; + } + } + + error = rmi_register_phys_device(rmi_phys); + if (error) { + dev_err(&client->dev, + "failed to register physical driver at 0x%.2X.\n", + client->addr); + goto err_gpio; + } + i2c_set_clientdata(client, rmi_phys); + + if (pdata->attn_gpio > 0) { + error = acquire_attn_irq(data); + if (error < 0) { + dev_err(&client->dev, + "request_threaded_irq failed %d\n", + pdata->attn_gpio); + goto err_unregister; + } + } + +#if defined(CONFIG_RMI4_DEV) + error = gpio_export(pdata->attn_gpio, false); + if (error) { + dev_warn(&client->dev, "%s: WARNING: Failed to " + "export ATTN gpio!\n", __func__); + error = 0; + } else { + error = gpio_export_link(&(rmi_phys->rmi_dev->dev), "attn", + pdata->attn_gpio); + if (error) { + dev_warn(&(rmi_phys->rmi_dev->dev), + "%s: WARNING: Failed to symlink ATTN gpio!\n", + __func__); + error = 0; + } else { + dev_info(&(rmi_phys->rmi_dev->dev), + "%s: Exported GPIO %d.", __func__, + pdata->attn_gpio); + } + } +#endif /* CONFIG_RMI4_DEV */ + + dev_info(&client->dev, "registered rmi i2c driver at 0x%.2X.\n", + client->addr); + //reflash the new firmware revision hhb@rock-chips.com +#ifdef CONFIG_RMI4_REFLASH_WHEN_BOOT + CompleteReflash(rmi_phys); +#endif + return 0; + +err_unregister: + rmi_unregister_phys_device(rmi_phys); +err_gpio: + if (pdata->gpio_config) + pdata->gpio_config(pdata->gpio_data, false); +err_data: + kfree(data); +err_phys: + kfree(rmi_phys); + return error; +} + +static int __devexit rmi_i2c_remove(struct i2c_client *client) +{ + struct rmi_phys_device *phys = i2c_get_clientdata(client); + struct rmi_device_platform_data *pd = client->dev.platform_data; + + disable_device(phys); + rmi_unregister_phys_device(phys); + kfree(phys->data); + kfree(phys); + + if (pd->gpio_config) + pd->gpio_config(&pd->gpio_data, false); + + return 0; +} + +static const struct i2c_device_id rmi_id[] = { + { "rmi", 0 }, + { "rmi_i2c", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rmi_id); + +static struct i2c_driver rmi_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "rmi_i2c" + }, + .id_table = rmi_id, + .probe = rmi_i2c_probe, + .remove = __devexit_p(rmi_i2c_remove), +}; + +static int __init rmi_i2c_init(void) +{ + return i2c_add_driver(&rmi_i2c_driver); +} + +static void __exit rmi_i2c_exit(void) +{ + i2c_del_driver(&rmi_i2c_driver); +} + +module_init(rmi_i2c_init); +module_exit(rmi_i2c_exit); + +MODULE_AUTHOR("Christopher Heiny "); +MODULE_DESCRIPTION("RMI I2C driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(RMI_DRIVER_VERSION); diff --git a/drivers/input/touchscreen/rmi4/rmi_reflash.c b/drivers/input/touchscreen/rmi4/rmi_reflash.c new file mode 100644 index 000000000000..c10525f9174f --- /dev/null +++ b/drivers/input/touchscreen/rmi4/rmi_reflash.c @@ -0,0 +1,670 @@ +/* + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + Copyright (c) 2011 Synaptics, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +*/ + +// SynaFirmwareImage.h contains the data for both the entire image and the config block +//#include "SynaFirmwareImage.h" +//#include "config.h" + +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include "rmi_reflash.h" + +//need +#define ASSERT 1 +#define TOUCH_CONTROLLER "s3202" +#define FW_REVISION "DS4 R3.0" + +void eraseConfigBlock(void); +void SynaInitialize(void); +void SynaReadConfigInfo(void); +void SynaReadFirmwareInfo(void); +int TouchControllerTypeCheck(void); +void SynaEnableFlashing(void); +int fimrwareRevisionCheck(void); +void SynaBootloaderLock(void); +void SynaProgramConfiguration(void); +void SynaProgramFirmware(void); +void SynaFinalizeReflash(void); +void SynaWaitForATTN(void); +void convertConfigBlockData(void); +int rmi_i2c_read_block(struct rmi_phys_device *phys, u16 addr, u8 *buf, + int len); +int rmi_i2c_write_block(struct rmi_phys_device *phys, u16 addr, u8 *buf, + int len); +/* Variables for F34 functionality */ +unsigned short SynaF34DataBase; +unsigned short SynaF34QueryBase; +unsigned short SynaF01DataBase; +unsigned short SynaF01CommandBase; +unsigned short SynaF01QueryBase; + +unsigned short SynaF34Reflash_BlockNum; +unsigned short SynaF34Reflash_BlockData; +unsigned short SynaF34ReflashQuery_BootID; +unsigned short SynaF34ReflashQuery_FlashPropertyQuery; +unsigned short SynaF34ReflashQuery_FirmwareBlockSize; +unsigned short SynaF34ReflashQuery_FirmwareBlockCount; +unsigned short SynaF34ReflashQuery_ConfigBlockSize; +unsigned short SynaF34ReflashQuery_ConfigBlockCount; + +unsigned short SynaFirmwareBlockSize; +unsigned short SynaFirmwareBlockCount; +unsigned long SynaImageSize; + +unsigned short SynaConfigBlockSize; +unsigned short SynaConfigBlockCount; +unsigned long SynaConfigImageSize; + +unsigned short SynaBootloadID; + +unsigned short SynaF34_FlashControl; + +unsigned char *SynafirmwareImgData; +unsigned char *SynaconfigImgData; +unsigned char *SynalockImgData; +unsigned int SynafirmwareImgVersion; + +unsigned char *ConfigBlock; + +unsigned char *ConfigBlockData; +struct rmi_phys_device *rmi_phys; + + + +int readRMI(u16 addr, u8 *buf, int len) { + rmi_i2c_read_block(rmi_phys, addr, buf, len); + return 0; +} + +int writeRMI(u16 addr, u8 *buf, int len) { + rmi_i2c_write_block(rmi_phys, addr, buf, len); + return 0; +} + +int waitATTN(u8 n, u16 delay) { +#if 1 + unsigned char uStatus; + do{ + readRMI((SynaF01DataBase + 1), &uStatus, 1); + }while((uStatus & 0x01) == 0); +#else + msleep(1); +#endif + return 0; +} + +/* End: Variables for F34 functionality */ + +/* CompleteReflash reflashes the entire user image, including the configuration block and firmware +*/ +void CompleteReflash(struct rmi_phys_device *phys) +{ + rmi_phys = phys; + SynaInitialize(); + + //if (TouchControllerTypeCheck()) + { + if (fimrwareRevisionCheck()) + { + printk("rmi find the current firmware revision is old, reflash now..."); + SynaReadConfigInfo(); + SynaReadFirmwareInfo(); + SynaF34_FlashControl = SynaF34DataBase + SynaFirmwareBlockSize + 2; + SynaEnableFlashing(); + SynaBootloaderLock(); + SynaProgramFirmware(); + SynaProgramConfiguration(); + SynaFinalizeReflash(); + } + } +} + +/* SynaSetup scans the Page Description Table (PDT) and sets up the necessary variables + * for the reflash process. This function is a "slim" version of the PDT scan function in + * in PDT.c, since only F34 and F01 are needed for reflash. + */ +void SynaSetup(void) +{ + unsigned char address; + unsigned char buffer[6] = {0}; + + for (address = 0xe9; address > 0xc0; address = address - 6) + { + readRMI(address, buffer, 6); + + switch (buffer[5]) + { + case 0x34: + SynaF34DataBase = buffer[3]; + SynaF34QueryBase = buffer[0]; + break; + case 0x01: + SynaF01DataBase = buffer[3]; + SynaF01CommandBase = buffer[1]; + SynaF01QueryBase = buffer[0]; + break; + } + } + + SynaF34Reflash_BlockNum = SynaF34DataBase; + SynaF34Reflash_BlockData = SynaF34DataBase + 2; + SynaF34ReflashQuery_BootID = SynaF34QueryBase; + SynaF34ReflashQuery_FlashPropertyQuery = SynaF34QueryBase + 2; + SynaF34ReflashQuery_FirmwareBlockSize = SynaF34QueryBase + 3; + SynaF34ReflashQuery_FirmwareBlockCount = SynaF34QueryBase +5; + SynaF34ReflashQuery_ConfigBlockSize = SynaF34QueryBase + 3; + SynaF34ReflashQuery_ConfigBlockCount = SynaF34QueryBase + 7; + + SynafirmwareImgData = (unsigned char *)((&SynaFirmware[0])+0x100); + SynaconfigImgData = (unsigned char *)(SynafirmwareImgData+SynaImageSize); + SynafirmwareImgVersion = (unsigned int)(SynaFirmware[7]); + ConfigBlockData = SynaconfigImgData; + switch (SynafirmwareImgVersion) + { + case 2: + SynalockImgData = (unsigned char *)((&SynaFirmware[0]) + 0xD0); + break; + case 3: + case 4: + SynalockImgData = (unsigned char *)((&SynaFirmware[0]) + 0xC0); + break; + case 5: + SynalockImgData = (unsigned char *)((&SynaFirmware[0]) + 0xB0); + default: break; + } +} + +/* SynaInitialize sets up the reflahs process + */ +void SynaInitialize(void) +{ + unsigned char uData[2]; + unsigned char uStatus = 0; + + //printk("\nInitializing Reflash Process..."); + uData[0] = 0; + writeRMI(0xff, uData, 1); // switch to page0 //hhb + + do { + readRMI(0, &uStatus, 1); + + if (uStatus & 0x80) + { + break; + } + } while (uStatus & 0x40); + SynaSetup(); + + SynafirmwareImgData = 0; + + SynaconfigImgData = 0; + + readRMI(SynaF34ReflashQuery_FirmwareBlockSize, &uData[0], 2); + + SynaFirmwareBlockSize = uData[0] | (uData[1] << 8); +} + +/* SynaReadFirmwareInfo reads the F34 query registers and retrieves the block size and count + * of the firmware section of the image to be reflashed + */ +void SynaReadFirmwareInfo(void) +{ + unsigned char uData[2]; + + printk("Read Firmware Info\n"); + + readRMI(SynaF34ReflashQuery_FirmwareBlockSize, &uData[0], 2); + SynaFirmwareBlockSize = uData[0] | (uData[1] << 8); + + readRMI(SynaF34ReflashQuery_FirmwareBlockCount, &uData[0], 2); + SynaFirmwareBlockCount = uData[0] | (uData[1] << 8); + SynaImageSize = SynaFirmwareBlockCount * SynaFirmwareBlockSize; + printk("SynaFirmwareBlockSize:%d,SynaFirmwareBlockCount:%d \n", SynaFirmwareBlockSize, SynaFirmwareBlockCount); +} + +/* SynaReadConfigInfo reads the F34 query registers and retrieves the block size and count + * of the configuration section of the image to be reflashed + */ +void SynaReadConfigInfo(void) +{ + unsigned char uData[2]; + + printk("Read Config Info\n"); + + readRMI(SynaF34ReflashQuery_ConfigBlockSize, &uData[0], 2); + SynaConfigBlockSize = uData[0] | (uData[1] << 8); + + readRMI(SynaF34ReflashQuery_ConfigBlockCount, &uData[0], 2); + SynaConfigBlockCount = uData[0] | (uData[1] << 8); + SynaConfigImageSize = SynaConfigBlockCount * SynaConfigBlockSize; + printk("SynaConfigBlockSize:%d,SynaConfigBlockCount:%d \n", SynaConfigBlockSize, SynaConfigBlockCount); +} + + +/* SynaReadBootloadID reads the F34 query registers and retrieves the bootloader ID of the firmware + */ +void SynaReadBootloadID(void) +{ + unsigned char uData[2]; + + readRMI(SynaF34ReflashQuery_BootID, &uData[0], 2); + SynaBootloadID = uData[0] + uData[1] * 0x100; +} + +/* SynaWriteBootloadID writes the bootloader ID to the F34 data register to unlock the reflash process + */ +void SynaWriteBootloadID(void) +{ + unsigned char uData[2]; + + uData[0] = SynaBootloadID % 0x100; + uData[1] = SynaBootloadID / 0x100; + + writeRMI(SynaF34Reflash_BlockData, &uData[0], 2); +} + +/* SynaEnableFlashing kicks off the reflash process + */ +void SynaEnableFlashing(void) +{ + unsigned char uData = 0; + unsigned char uStatus = 0; + + printk("Enable Reflash...\n"); + + // Reflash is enabled by first reading the bootloader ID from the firmware and write it back + SynaReadBootloadID(); + SynaWriteBootloadID(); + // Make sure Reflash is not already enabled + do { + readRMI(SynaF34_FlashControl, &uData, 1); + } while (((uData & 0x0f) != 0x00)); + // Clear ATTN + readRMI (SynaF01DataBase, &uStatus, 1); + + if ((uStatus & 0x40) == 0) + { + // Write the "Enable Flash Programming command to F34 Control register + // Wait for ATTN and then clear the ATTN. + readRMI(SynaF34_FlashControl, &uData, 1); + uData &= 0xf0; + uData |= 0x0f; + writeRMI(SynaF34_FlashControl, &uData, 1); + SynaWaitForATTN(); + readRMI((SynaF01DataBase + 1), &uStatus, 1); + + // Scan the PDT again to ensure all register offsets are correct + SynaSetup(); + + // Read the "Program Enabled" bit of the F34 Control register, and proceed only if the + // bit is set. + readRMI(SynaF34_FlashControl, &uData, 1); + + while (uData != 0x80) + { + // In practice, if uData!=0x80 happens for multiple counts, it indicates reflash + // is failed to be enabled, and program should quit + ; + } + } +} + +/* SynaWaitForATTN waits for ATTN to be asserted within a certain time threshold. + */ +void SynaWaitForATTN(void) +{ + unsigned int error; + + error = waitATTN(ASSERT, 300); +} + +/* SynaWaitATTN waits for ATTN to be asserted within a certain time threshold. + * The function also checks for the F34 "Program Enabled" bit and clear ATTN accordingly. + */ +void SynaWaitATTN(void) +{ + unsigned char uData = 0; + unsigned char uStatus = 0; + + waitATTN(ASSERT, 300); + do { + readRMI(SynaF34_FlashControl, &uData, 1); + readRMI((SynaF01DataBase + 1), &uStatus, 1); + } while (uData != 0x80); +} + +/* SynaProgramConfiguration writes the configuration section of the image block by block + */ +void SynaProgramConfiguration(void) +{ + unsigned char uData[2]; + unsigned char *puData = ConfigBlockData; + unsigned short blockNum; + + // eraseConfigBlock(); + for (blockNum = 0; blockNum < SynaConfigBlockCount; blockNum++) + { + uData[0] = blockNum & 0xff; + uData[1] = (blockNum & 0xff00) >> 8; + + //Block by blcok, write the block number and data to the corresponding F34 data registers + writeRMI(SynaF34Reflash_BlockNum, &uData[0], 2); + writeRMI(SynaF34Reflash_BlockData, puData, SynaConfigBlockSize); + puData += SynaConfigBlockSize; + + // Issue the "Write Configuration Block" command + readRMI(SynaF34_FlashControl, &uData[0], 1); + uData[0] &= 0xf0; + uData[0] |= 0x06; + writeRMI(SynaF34_FlashControl, &uData[0], 1); + SynaWaitATTN(); + printk("."); + } + printk("\n"); + readRMI(SynaF01DataBase, uData, 1); + printk("+++++++SynaProgramConfiguration++uData:%x+++++++%s:%d\n", uData[0], __func__, __LINE__); + +} + +/* SynaFinalizeReflash finalizes the reflash process + */ +void SynaFinalizeReflash(void) +{ + unsigned char uData = 0; + unsigned char uStatus = 0; + + printk("Finalizing Reflash...\n"); + + // Issue the "Reset" command to F01 command register to reset the chip + // This command will also test the new firmware image and check if its is valid + uData = 1; + writeRMI(SynaF01CommandBase, &uData, 1); + msleep(100); + //SynaWaitForATTN(); + readRMI(SynaF01DataBase, &uData, 1); + printk("+++++++++uData:%x+++++++%s:%d\n", uData, __func__, __LINE__); + // Sanity check that the reflash process is still enabled + do { + readRMI(SynaF34_FlashControl, &uStatus, 1); + } while ((uStatus & 0x0f) != 0x00); + printk("+++++++++uStatus:%x+++++++%s:%d\n", uStatus, __func__, __LINE__); + readRMI((SynaF01DataBase + 1), &uStatus, 1); + + SynaSetup(); + + uData = 0; + // Check if the "Program Enabled" bit in F01 data register is cleared + // Reflash is completed, and the image passes testing when the bit is cleared + do { + readRMI(SynaF01DataBase, &uData, 1); + } while ((uData & 0x40) != 0); + // Rescan PDT the update any changed register offsets + SynaSetup(); + printk("\nReflash Completed. Please reboot."); +} + +/* SynaFlashFirmwareWrite writes the firmware section of the image block by block + */ +void SynaFlashFirmwareWrite(void) +{ + unsigned char *puFirmwareData = (unsigned char *)(SynaFirmware+0x100); //SynafirmwareImgData; //hhb + unsigned char uData[2]; + unsigned short blockNum; + + for (blockNum = 0; blockNum < SynaFirmwareBlockCount; ++blockNum) + { + //Block by blcok, write the block number and data to the corresponding F34 data registers + uData[0] = blockNum & 0xff; + uData[1] = (blockNum & 0xff00) >> 8; + writeRMI(SynaF34Reflash_BlockNum, &uData[0], 2); + writeRMI(SynaF34Reflash_BlockData, puFirmwareData, SynaFirmwareBlockSize); + puFirmwareData += SynaFirmwareBlockSize; + // Issue the "Write Firmware Block" command + readRMI(SynaF34_FlashControl, &uData[0], 1); + uData[0] &= 0xf0; + uData[0] |= 0x02; + writeRMI(SynaF34_FlashControl, &uData[0], 1); + if(blockNum % 128 == 0) + printk("."); + SynaWaitATTN(); + } + +} + +/* SynaProgramFirmware prepares the firmware writing process + */ +void SynaProgramFirmware(void) +{ + unsigned char uData; + + printk("Program Firmware Section...\n"); + + SynaReadBootloadID(); + SynaWriteBootloadID(); + readRMI(SynaF34_FlashControl, &uData, 1); + uData &= 0xf0; + uData |= 0x03; + writeRMI(SynaF34_FlashControl, &uData, 1); + msleep(5000); + SynaWaitATTN(); + SynaFlashFirmwareWrite(); + readRMI(SynaF01DataBase, &uData, 1); + printk("+++++++SynaProgramFirmware++uData:%x+++++++%s:%d\n", uData, __func__, __LINE__); +} + +/* SynaBootloaderLock locks down the bootloader +*/ +void SynaBootloaderLock(void) +{ + unsigned short lockBlockCount; + unsigned char *puFirmwareData = SynalockImgData; + unsigned char uData[2]; + unsigned short uBlockNum; + + // Check if device is in unlocked state + readRMI((SynaF34QueryBase+ 2), &uData[0], 1); + + //Device is unlocked + if (uData[0] & 0x02) + { + printk("Device unlocked. Lock it first...\n"); + // Different bootloader version has different block count for the lockdown data + // Need to check the bootloader version from the image file being reflashed + switch (SynafirmwareImgVersion) + { + case 2: + lockBlockCount = 3; + break; + case 3: + case 4: + lockBlockCount = 4; + break; + case 5: + lockBlockCount = 5; + break; + default: + lockBlockCount = 0; + break; + } + + // Write the lockdown info block by block + // This reference code of lockdown process does not check for bootloader version + // currently programmed on the ASIC against the bootloader version of the image to + // be reflashed. Such case should not happen in practice. Reflashing cross different + // bootloader versions is not supported. + for (uBlockNum = 0; uBlockNum < lockBlockCount; ++uBlockNum) + { + uData[0] = uBlockNum & 0xff; + uData[1] = (uBlockNum & 0xff00) >> 8; + + /* Write Block Number */ + readRMI(SynaF34Reflash_BlockNum, &uData[0], 2); + + /* Write Data Block */ + writeRMI(SynaF34Reflash_BlockData, puFirmwareData, SynaFirmwareBlockSize); + + /* Move to next data block */ + puFirmwareData += SynaFirmwareBlockSize; + + /* Issue Write Lockdown Block command */ + readRMI(SynaF34_FlashControl, &uData[0], 1); + uData[0] &= 0xf0; + uData[0] |= 0x04; + writeRMI(SynaF34_FlashControl, &uData[0], 1); + + /* Wait ATTN until device is done writing the block and is ready for the next. */ + SynaWaitATTN(); + } + printk("Device locking done.\n"); + + // Enable reflash again to finish the lockdown process. + // Since this lockdown process is part of the reflash process, we are enabling + // reflash instead, rather than resetting the device to finish the unlock procedure. + SynaEnableFlashing(); + } + else printk("Device already locked.\n"); +} + +/* ConfigBlockReflash reflashes the config block only +*/ +void ConfigBlockReflash(void) +{ + unsigned char uData[2]; + + convertConfigBlockData(); + + SynaInitialize(); + + SynaReadConfigInfo(); + + SynaReadFirmwareInfo(); + + SynaF34_FlashControl = SynaF34DataBase + SynaFirmwareBlockSize + 2; + + SynaEnableFlashing(); + + SynaBootloaderLock(); + + // Check if device is in unlocked state + readRMI((SynaF34QueryBase + 2), &uData[0], 1); + + //Device is unlocked + if (uData[0] & 0x02) + { + SynaFinalizeReflash(); + return; + // Do not reflash config block if not locked. + } + + eraseConfigBlock(); + SynaconfigImgData = (unsigned char *)ConfigBlock; + + SynaProgramConfiguration(); + + SynaFinalizeReflash(); +} + +/* eraseConfigBlock erases the config block +*/ +void eraseConfigBlock(void) +{ + unsigned char uData; + + // Erase of config block is done by first entering into bootloader mode + SynaReadBootloadID(); + SynaWriteBootloadID(); + + // Command 7 to erase config block + readRMI(SynaF34_FlashControl, &uData, 1); + uData &= 0xf0; + uData |= 0x07; + writeRMI(SynaF34_FlashControl, &uData, 1); + + SynaWaitATTN(); +} + +// This function is intended to convert the config data struct output by DS4 (read config.h) into an array that +// the reflash code uses (read SynaFirmwareImage.h) +// DS4 will output the array format in the next release and this function will not be necessary +void convertConfigBlockData(void) +{ +#if 0 + int i = 0; + char value[32]; //hhb + for (i = 0; value[i]!=NULL; i++) + { + ConfigBlock[i] = value[i].Value; + } +#endif +} + +// This function is to check the touch controller type of the touch controller matches with the firmware image +int TouchControllerTypeCheck(void) +{ + unsigned char uData[4]; + char buffer[4]; + + char controllerType[20]; + + int ID; + //int revision; + + readRMI((SynaF01QueryBase + 43), &uData[0], 1); + if ((uData[0] & 0x0f) > 0) + { + readRMI((SynaF01QueryBase + 44), &uData[0], 1); + if (uData[0] & 0x01) + { + readRMI((SynaF01QueryBase + 17), &uData[0], 2); + + ID = (int)(uData[1] & (uData[0] << 8)); + sprintf(buffer, "%d", ID); + if (strstr(controllerType, TOUCH_CONTROLLER) != 0) + return true; + else + return false; + } + else + return false; + } + else + return false; +} + +int fimrwareRevisionCheck(void) +{ + unsigned char uData[10]; + readRMI((SynaF01QueryBase + 11), uData, 10); + return strcmp(uData, FW_REVISION); +} + diff --git a/drivers/input/touchscreen/rmi4/rmi_reflash.h b/drivers/input/touchscreen/rmi4/rmi_reflash.h new file mode 100644 index 000000000000..131baf198c22 --- /dev/null +++ b/drivers/input/touchscreen/rmi4/rmi_reflash.h @@ -0,0 +1,2916 @@ + +unsigned char SynaFirmware[46592] = { + 0x9F, 0x45, 0x60, 0x37, 0x00, 0x00, 0x00, 0x05, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x53, 0x33, 0x32, 0x30, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x49, 0x32, 0x43, 0x00, 0x0B, 0x00, 0xFF, 0x00, 0x0C, 0x0D, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x49, 0x32, 0x43, 0x00, 0x0B, 0x00, 0xFF, 0x00, 0x0C, 0x0D, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2A, 0x89, 0x34, 0x06, 0x57, 0x8E, 0xAF, 0x99, 0x1D, 0x93, 0xE1, 0x46, 0x6E, 0x54, 0x4E, 0xBF, + 0x61, 0x8E, 0x56, 0x70, 0x30, 0x3F, 0x97, 0xC2, 0x8D, 0xD5, 0x9B, 0xB3, 0xCB, 0x3A, 0xB2, 0xAC, + 0xCD, 0x8D, 0xF3, 0xF5, 0x66, 0x6C, 0xDB, 0xB5, 0x5C, 0xDA, 0xC3, 0xB0, 0xA0, 0x8D, 0x53, 0xA1, + 0xD2, 0x5F, 0xBA, 0xB8, 0x02, 0xF1, 0x51, 0xA1, 0xC5, 0x23, 0xAF, 0x6E, 0x8B, 0x2D, 0x5E, 0x08, + 0xBD, 0x91, 0xEC, 0x65, 0xBA, 0x7E, 0x40, 0x2E, 0x89, 0xEF, 0xA2, 0x8B, 0x37, 0x46, 0xC4, 0x1E, + 0xDB, 0x20, 0x93, 0x98, 0x9B, 0xA3, 0x60, 0x34, 0x66, 0x6A, 0x69, 0xC2, 0x4B, 0x67, 0xFE, 0x79, + 0x14, 0x15, 0x01, 0x83, 0x5C, 0xB4, 0xFB, 0x4D, 0x75, 0x63, 0xC4, 0x05, 0x16, 0x74, 0xCF, 0x65, + 0x6E, 0xCC, 0xDC, 0xFE, 0x1A, 0xD0, 0xF6, 0x28, 0x4F, 0xE6, 0xD8, 0x2D, 0x90, 0xAA, 0x78, 0x1D, + 0xD1, 0xDA, 0x89, 0x9C, 0x39, 0xF3, 0x1C, 0x4A, 0x6C, 0xD2, 0x99, 0xEA, 0x6C, 0xBE, 0x57, 0x53, + 0x39, 0x92, 0x43, 0x4B, 0x4E, 0x17, 0x79, 0x0C, 0x3A, 0x20, 0xAA, 0xF8, 0xCE, 0x46, 0xD8, 0xEE, + 0x28, 0x68, 0x11, 0x9B, 0xA0, 0xCA, 0x61, 0xC0, 0x46, 0x78, 0xE4, 0x6F, 0x73, 0xC7, 0x31, 0x14, + 0x63, 0xE7, 0xEB, 0xC7, 0xB0, 0x8C, 0x96, 0xAD, 0x69, 0x0C, 0xFF, 0xFC, 0x0E, 0xAF, 0x0B, 0x1B, + 0x19, 0x80, 0xFC, 0xE1, 0xBE, 0xFC, 0xC2, 0xBC, 0xC6, 0x9B, 0x55, 0xBC, 0xBA, 0x91, 0xFE, 0x84, + 0x90, 0x4F, 0xE9, 0xE8, 0x6E, 0xDA, 0x1F, 0x65, 0x49, 0x7C, 0x5A, 0xE0, 0x06, 0x0D, 0x49, 0xB7, + 0x92, 0x0F, 0x52, 0x01, 0x03, 0xC0, 0x88, 0x27, 0x48, 0xA0, 0x78, 0x83, 0x84, 0x40, 0x9B, 0xB0, + 0x50, 0xAE, 0x0B, 0x29, 0xFC, 0x47, 0x22, 0xFC, 0x7A, 0x7B, 0xEA, 0xBC, 0x75, 0x5C, 0xC5, 0x7D, + 0x10, 0xAC, 0xE1, 0x27, 0x3F, 0x59, 0x96, 0xE8, 0x9E, 0x0F, 0x04, 0x29, 0x25, 0xAC, 0x4A, 0x14, + 0x7E, 0x14, 0x1D, 0xA5, 0x85, 0xDD, 0x1C, 0x40, 0xDA, 0xD2, 0x7E, 0x6D, 0x45, 0xE0, 0x0A, 0xEB, + 0xF7, 0x88, 0x02, 0x7D, 0x97, 0x68, 0x14, 0x12, 0x45, 0x73, 0x1C, 0xD2, 0x56, 0x52, 0xD0, 0x60, + 0x4E, 0x24, 0xA5, 0x61, 0x27, 0xC5, 0x34, 0x43, 0xEE, 0xDA, 0xA7, 0x83, 0xD5, 0x8A, 0xF2, 0x85, + 0xCE, 0x7B, 0xC6, 0x9C, 0x15, 0xDE, 0x67, 0x9D, 0xC4, 0xC1, 0x9C, 0x00, 0xC7, 0xFF, 0x8E, 0x67, + 0xEF, 0xDC, 0x9F, 0xF0, 0x43, 0xC9, 0x29, 0xD5, 0x9A, 0x13, 0x5B, 0xE6, 0xA4, 0x65, 0x76, 0x9A, + 0xB7, 0xA1, 0x9B, 0x54, 0xC4, 0x69, 0x58, 0x1F, 0xC2, 0x28, 0x90, 0x11, 0xD1, 0x58, 0x50, 0x8B, + 0xC6, 0x2D, 0x9D, 0x26, 0x90, 0xA2, 0x2F, 0xD5, 0x89, 0x31, 0x7F, 0x6C, 0x8A, 0xB7, 0x66, 0x78, + 0x6D, 0x69, 0xBB, 0x2E, 0x21, 0xA0, 0xE7, 0x34, 0x85, 0xC4, 0xF6, 0xC3, 0x4B, 0x45, 0x9A, 0x58, + 0xF9, 0x5D, 0x14, 0x4F, 0x78, 0xE0, 0x2A, 0x4D, 0xC2, 0xD8, 0x09, 0x0F, 0x9A, 0xB9, 0xB0, 0x00, + 0x48, 0x6A, 0x9D, 0x20, 0x0D, 0x6A, 0xF1, 0x52, 0xEF, 0xCC, 0xC6, 0x17, 0x5C, 0x85, 0x29, 0x4B, + 0x14, 0xD8, 0xA7, 0xA1, 0xDD, 0x96, 0x4C, 0x5A, 0x19, 0xB1, 0xAF, 0xB4, 0x0E, 0x13, 0x47, 0x08, + 0xE1, 0xD0, 0x48, 0x09, 0x16, 0x73, 0xE9, 0x23, 0xBB, 0xDE, 0xBF, 0x67, 0x6F, 0x7C, 0xA7, 0xA2, + 0xE7, 0x5B, 0xF5, 0xC4, 0x86, 0xF0, 0xB0, 0x11, 0x79, 0x13, 0x2A, 0xB2, 0xED, 0xCA, 0x06, 0x4C, + 0x37, 0xFB, 0xB5, 0xE6, 0xAA, 0x5C, 0x6D, 0x31, 0x0D, 0x95, 0xCD, 0x19, 0xEA, 0xEC, 0x26, 0x2E, + 0x4F, 0xE6, 0x69, 0x0D, 0x0D, 0x4A, 0x36, 0xAA, 0xD5, 0x69, 0xF0, 0xF4, 0x83, 0x78, 0x6A, 0xB1, + 0x35, 0x95, 0xCF, 0x19, 0xBD, 0xCD, 0x3C, 0xAA, 0x47, 0x7D, 0xBD, 0xFD, 0x5B, 0xAE, 0xF6, 0x43, + 0x31, 0xEB, 0x5D, 0x05, 0x9F, 0xE4, 0x42, 0xF5, 0xBA, 0xC4, 0xAF, 0x2A, 0x7D, 0x0E, 0xA7, 0x9E, + 0xE4, 0xD6, 0xAA, 0x53, 0x97, 0x2A, 0xB4, 0x1A, 0x06, 0xCB, 0xE7, 0x05, 0x3B, 0x62, 0xF1, 0x17, + 0x3B, 0x1E, 0x62, 0xCC, 0xE9, 0xFA, 0x32, 0x4F, 0xCC, 0x32, 0x58, 0x89, 0x42, 0x52, 0x32, 0x34, + 0x8A, 0xE7, 0x88, 0x22, 0x43, 0x40, 0x6E, 0x20, 0xFB, 0x72, 0xD0, 0xCE, 0xD1, 0xED, 0x74, 0x38, + 0x12, 0xE7, 0x37, 0x3F, 0x4A, 0x5D, 0x12, 0x8D, 0x9F, 0x23, 0x94, 0x93, 0x93, 0x9C, 0xDF, 0xB3, + 0x21, 0x4B, 0xBF, 0x33, 0x58, 0xBF, 0x94, 0x51, 0x7C, 0x7F, 0xD8, 0x47, 0x98, 0xC8, 0x73, 0x1E, + 0x81, 0x37, 0x1C, 0x5A, 0x3A, 0x78, 0xC3, 0x99, 0xBE, 0x2D, 0x76, 0x9A, 0x9E, 0xD1, 0x22, 0x62, + 0xF7, 0x09, 0x0E, 0xC6, 0xEF, 0xC5, 0x50, 0x10, 0xF5, 0x26, 0x84, 0xA3, 0xD6, 0x3A, 0x34, 0xEC, + 0x97, 0xC8, 0xC0, 0x90, 0x2B, 0xF8, 0xBF, 0x84, 0x88, 0xE1, 0xEC, 0x85, 0x31, 0x9A, 0xBC, 0x1F, + 0xBC, 0xAD, 0x79, 0x6F, 0xEB, 0x15, 0x77, 0xDB, 0x2C, 0xAD, 0x93, 0xE1, 0x8C, 0x22, 0x9B, 0xE5, + 0x19, 0x20, 0xB6, 0xC3, 0x7D, 0xB2, 0x31, 0xE0, 0x9A, 0x85, 0xD6, 0xD7, 0xFD, 0x1C, 0xBA, 0x59, + 0xFA, 0x0F, 0x69, 0x4B, 0x9B, 0x6B, 0x9E, 0x0C, 0x34, 0xC1, 0xF5, 0xFC, 0x5C, 0x60, 0x58, 0x4A, + 0xBB, 0xB7, 0xE2, 0x41, 0x44, 0x85, 0x1A, 0x78, 0x58, 0xE3, 0x49, 0x06, 0x6D, 0x5F, 0xA4, 0x6A, + 0x93, 0xC7, 0x85, 0x72, 0x19, 0xEB, 0x20, 0xCA, 0xF7, 0x44, 0x12, 0x53, 0xB8, 0x99, 0xCC, 0xB3, + 0x03, 0x02, 0x36, 0xB0, 0x3E, 0xE4, 0xDB, 0x79, 0x9F, 0x39, 0xAA, 0x3E, 0xDF, 0x84, 0x64, 0xA9, + 0x08, 0xBF, 0x52, 0x59, 0x54, 0xBD, 0x08, 0x63, 0x52, 0x88, 0x55, 0x45, 0x8C, 0x9A, 0x5A, 0x69, + 0xAA, 0x88, 0xF1, 0x43, 0x0D, 0xE9, 0xD8, 0x08, 0x7B, 0xC9, 0xE2, 0xA3, 0x4C, 0x2D, 0xC3, 0xA9, + 0x24, 0x7D, 0xC3, 0xDB, 0x2C, 0xE0, 0x0B, 0x72, 0x19, 0xA7, 0xCF, 0x64, 0x58, 0x44, 0x91, 0xD9, + 0xA1, 0x39, 0x76, 0x29, 0x01, 0xC7, 0x1A, 0x77, 0x92, 0x66, 0x68, 0xF7, 0x7E, 0xCD, 0x67, 0x52, + 0x56, 0x19, 0xD8, 0x6C, 0x92, 0x36, 0x33, 0x1A, 0xD5, 0xCC, 0x56, 0x7F, 0xA2, 0x76, 0x00, 0x29, + 0xFD, 0x41, 0xF1, 0x6A, 0xA4, 0xA7, 0x56, 0x1D, 0x14, 0x37, 0xB6, 0x67, 0x42, 0x9E, 0xAA, 0x28, + 0x31, 0xFB, 0x63, 0x82, 0x2D, 0x37, 0x29, 0xB8, 0xEC, 0xDE, 0xF4, 0x28, 0x15, 0x99, 0xF7, 0x5E, + 0x26, 0xCF, 0x1A, 0x12, 0x9E, 0xFC, 0x1C, 0x44, 0x86, 0x3C, 0x80, 0x71, 0x46, 0x77, 0x9C, 0xB2, + 0x53, 0x02, 0x66, 0x81, 0xAD, 0x35, 0x74, 0x59, 0xC8, 0xB3, 0xFE, 0xF0, 0xB2, 0x5A, 0x62, 0x25, + 0x41, 0xF2, 0xCE, 0x69, 0xE3, 0xBD, 0x7B, 0xB5, 0x80, 0x0D, 0x0D, 0xF1, 0x5F, 0xDC, 0xB6, 0xC4, + 0xE9, 0xEF, 0x24, 0x18, 0xAD, 0x1C, 0x74, 0x2A, 0x80, 0x66, 0x42, 0x75, 0x2A, 0xB0, 0xF3, 0x33, + 0xD9, 0x0F, 0x96, 0x89, 0xC9, 0x43, 0xFD, 0x64, 0xE1, 0x92, 0x52, 0xBC, 0xF1, 0xFF, 0xAB, 0xE3, + 0x53, 0x82, 0x55, 0x0A, 0x90, 0x17, 0xDF, 0x46, 0x3D, 0xFD, 0x34, 0xE2, 0xA4, 0xF7, 0x48, 0x59, + 0x19, 0x83, 0xC9, 0x37, 0x65, 0xD0, 0xEB, 0x4C, 0x51, 0xE5, 0x47, 0x04, 0x28, 0x49, 0xB9, 0x38, + 0x4C, 0xEF, 0xD0, 0x41, 0xFE, 0x0B, 0x0E, 0xCA, 0x39, 0x33, 0xE6, 0xDC, 0x74, 0xE8, 0x1E, 0x57, + 0x6F, 0x00, 0xE4, 0xE7, 0xA9, 0x4F, 0xAE, 0x74, 0x7F, 0x87, 0x04, 0x8C, 0xCC, 0x29, 0x97, 0xED, + 0xE6, 0x74, 0x07, 0xAF, 0x25, 0x9C, 0x91, 0x9D, 0xC6, 0xCD, 0x8F, 0xEA, 0x8D, 0xFE, 0xEB, 0xE1, + 0x0E, 0x6D, 0xE6, 0x5E, 0xC2, 0x1A, 0xA3, 0x43, 0x90, 0xD5, 0x1E, 0xC1, 0xE8, 0x17, 0x81, 0x8C, + 0xF6, 0xF7, 0xB8, 0xBC, 0x3F, 0x6E, 0x96, 0xC5, 0x19, 0x6A, 0x5F, 0xBA, 0xBF, 0xA2, 0xAE, 0x88, + 0x21, 0x0E, 0xAE, 0xB7, 0x14, 0xAB, 0xCB, 0x02, 0xFB, 0x50, 0xEF, 0x80, 0x87, 0x32, 0x8C, 0x0C, + 0x86, 0x1A, 0xC1, 0x79, 0xC6, 0xA5, 0x56, 0xA5, 0x66, 0xC6, 0xE2, 0x94, 0xCD, 0x82, 0x5B, 0xE4, + 0x3D, 0x33, 0x04, 0x7B, 0x4D, 0x2F, 0xA5, 0x93, 0x8F, 0x4E, 0xF1, 0xDE, 0xD3, 0x9D, 0xCA, 0x89, + 0x96, 0x74, 0x65, 0xC3, 0x71, 0xAA, 0xFC, 0xE0, 0x94, 0x8B, 0x30, 0x65, 0x20, 0x0C, 0x54, 0x07, + 0xD2, 0x2F, 0x92, 0x47, 0xA3, 0x62, 0x39, 0xB6, 0xF4, 0x44, 0x55, 0xDD, 0x75, 0x52, 0x35, 0x4F, + 0x70, 0x3B, 0xE7, 0x11, 0x28, 0xB7, 0x91, 0x36, 0x61, 0xFE, 0x57, 0x81, 0x4C, 0xB3, 0xCB, 0xEB, + 0x99, 0x40, 0x90, 0xE4, 0xE7, 0xF5, 0x35, 0xD0, 0x15, 0x7B, 0x49, 0xAD, 0xA9, 0xB7, 0xAE, 0x09, + 0x69, 0x14, 0x5C, 0x28, 0x29, 0x3C, 0xA6, 0x42, 0xE6, 0x53, 0xCF, 0xC5, 0xB9, 0x23, 0x36, 0x29, + 0x84, 0x8B, 0x1B, 0x87, 0x74, 0x15, 0x8C, 0x68, 0x44, 0x7D, 0xF7, 0x81, 0x44, 0x52, 0xA5, 0x80, + 0x2B, 0x54, 0x5B, 0x95, 0x91, 0x10, 0xD3, 0xAB, 0xED, 0x86, 0x8A, 0xC7, 0x81, 0xF3, 0xD9, 0x67, + 0xFE, 0xC6, 0xA7, 0x88, 0x67, 0x98, 0xD8, 0xC3, 0x46, 0x9E, 0x4F, 0x87, 0x9B, 0xFE, 0x70, 0xD4, + 0xCB, 0x3A, 0x16, 0x91, 0xBC, 0x09, 0xB1, 0x0A, 0x44, 0x0D, 0x68, 0xBE, 0x85, 0x1E, 0x4E, 0x4F, + 0xAC, 0xBA, 0x24, 0xB1, 0x0D, 0x1C, 0x84, 0x04, 0x0E, 0xAD, 0x8C, 0x39, 0x3D, 0x01, 0x9B, 0x52, + 0xA4, 0x11, 0x9B, 0xF4, 0xDF, 0xA7, 0x95, 0x69, 0xCF, 0x4F, 0x06, 0x42, 0xCF, 0xAF, 0xD7, 0xA8, + 0xCC, 0x28, 0xD5, 0x9D, 0x10, 0xF1, 0x9E, 0x63, 0x6C, 0x82, 0x85, 0xD0, 0xB1, 0x0C, 0xDE, 0xB6, + 0x38, 0xA1, 0x09, 0xC5, 0xCF, 0x2C, 0xB6, 0x6E, 0x22, 0x4C, 0xC8, 0x2A, 0x75, 0x4F, 0xCD, 0xDF, + 0xED, 0xCD, 0x18, 0x45, 0x16, 0x97, 0xDF, 0xDA, 0x79, 0x91, 0xAF, 0x17, 0xF2, 0x57, 0xAE, 0x87, + 0xDE, 0x6B, 0xBE, 0x8D, 0x3B, 0x89, 0x5A, 0xB4, 0xDD, 0x10, 0x08, 0x3D, 0xE8, 0x60, 0xA2, 0x33, + 0x7C, 0x2A, 0x68, 0xC4, 0x9A, 0xED, 0x06, 0x6D, 0xD8, 0x71, 0x19, 0xC7, 0xEA, 0x5C, 0x32, 0xE9, + 0x4B, 0x86, 0x14, 0xA8, 0xC2, 0xB2, 0x40, 0x79, 0xD5, 0xBB, 0x3A, 0x34, 0x8C, 0x8C, 0x30, 0x46, + 0x86, 0xB8, 0x9D, 0x2B, 0x03, 0x1A, 0x77, 0xE3, 0xC4, 0xE8, 0x54, 0x21, 0x01, 0x89, 0x4E, 0x80, + 0xDD, 0xD2, 0x25, 0xED, 0xB5, 0xD9, 0xCD, 0xD4, 0x49, 0x65, 0xCF, 0x2C, 0xE1, 0x50, 0xDC, 0xD8, + 0x45, 0x9C, 0x85, 0x69, 0xEE, 0x07, 0x22, 0x0D, 0x35, 0xF1, 0x1D, 0xB8, 0x4D, 0xD8, 0x2C, 0xAD, + 0x0F, 0x7C, 0xB0, 0x1A, 0x71, 0x80, 0x2C, 0x79, 0x07, 0x83, 0x68, 0x4A, 0x21, 0x5F, 0xC2, 0xE9, + 0x0B, 0x9E, 0x44, 0x73, 0x21, 0x70, 0x96, 0x5C, 0xFA, 0xEC, 0xFD, 0x4D, 0x74, 0xA3, 0x5D, 0x21, + 0xA6, 0x26, 0x1F, 0x58, 0xD5, 0x3B, 0x34, 0xF2, 0xAA, 0xD7, 0x97, 0xDA, 0xD4, 0x43, 0xDA, 0xA7, + 0x48, 0xDD, 0x51, 0x8D, 0x85, 0x81, 0xB0, 0xA1, 0x06, 0xF4, 0x85, 0x60, 0x5D, 0x5D, 0x9A, 0xF3, + 0x20, 0x89, 0x37, 0xDA, 0x66, 0x40, 0xA5, 0x84, 0xDF, 0x3E, 0x77, 0x0E, 0x6F, 0xFE, 0xC4, 0xA1, + 0xE7, 0x24, 0xA0, 0x27, 0x50, 0x43, 0x70, 0x74, 0x05, 0x35, 0x34, 0xB2, 0xEF, 0xC5, 0x41, 0x46, + 0x17, 0x95, 0x41, 0xDE, 0x1E, 0x00, 0x53, 0xB0, 0x58, 0x8C, 0xF4, 0xB0, 0xF0, 0x2F, 0x2E, 0x45, + 0x78, 0x5A, 0x8D, 0xB7, 0x99, 0x0F, 0xE4, 0xF5, 0x64, 0x60, 0x28, 0x48, 0xF9, 0x11, 0xEA, 0xDD, + 0xA4, 0xC1, 0x8D, 0x2B, 0x55, 0x13, 0x6D, 0x6D, 0x23, 0x6B, 0xA7, 0xE1, 0xF8, 0x6E, 0xC5, 0xFA, + 0x7C, 0xE5, 0x9B, 0x41, 0x10, 0x44, 0xBB, 0xAE, 0x7D, 0xED, 0x62, 0xF8, 0x5D, 0x6F, 0x7E, 0x1F, + 0x07, 0xC7, 0x20, 0x50, 0xA3, 0x2D, 0x55, 0x11, 0x78, 0x3C, 0x2B, 0x6C, 0x72, 0x13, 0x0F, 0xE7, + 0x3F, 0xC7, 0x63, 0x9A, 0xB1, 0xC2, 0x44, 0x87, 0x19, 0xC0, 0xEA, 0x29, 0x71, 0xA1, 0xFB, 0x1D, + 0x29, 0xD3, 0x69, 0x9D, 0xF1, 0x3B, 0x6B, 0x15, 0x97, 0x59, 0x73, 0x31, 0x19, 0x5D, 0x97, 0xBE, + 0xB5, 0x03, 0x6F, 0xB2, 0xF0, 0x64, 0x10, 0x13, 0x4F, 0x35, 0x21, 0xCE, 0xCD, 0x7B, 0x65, 0x83, + 0x2A, 0xF2, 0xC8, 0xA4, 0x05, 0x84, 0x4C, 0x62, 0xA5, 0xD8, 0x23, 0xB2, 0x28, 0xDC, 0x14, 0x91, + 0x10, 0xAF, 0xF8, 0x52, 0xD3, 0x85, 0x07, 0xBE, 0x49, 0x9B, 0xE5, 0x02, 0xBF, 0x2D, 0xEC, 0xF7, + 0xE1, 0xDC, 0x93, 0x7E, 0x50, 0x78, 0x6B, 0x13, 0xB1, 0xDB, 0x80, 0x26, 0xA8, 0xE9, 0x7D, 0x23, + 0x12, 0xEF, 0xB4, 0xC3, 0xBE, 0x82, 0x0F, 0xBD, 0xD4, 0x49, 0x80, 0xEC, 0x64, 0x5D, 0xF8, 0xED, + 0x2B, 0xAC, 0x28, 0x1F, 0xBE, 0x4B, 0xAF, 0x85, 0xEB, 0xB5, 0x24, 0x06, 0xCA, 0xF5, 0xD4, 0x5F, + 0x89, 0x72, 0x9E, 0x98, 0x43, 0x72, 0x6D, 0x04, 0xCA, 0xE5, 0xDB, 0x4F, 0xB5, 0x5C, 0x43, 0xA9, + 0xF9, 0xD7, 0xAB, 0xEB, 0x2A, 0x63, 0x7E, 0x0D, 0x63, 0x2D, 0xA8, 0xA4, 0x62, 0xDE, 0xD3, 0x35, + 0x4F, 0xB9, 0x87, 0xB2, 0x9C, 0xB7, 0x48, 0xA4, 0x49, 0x87, 0xAD, 0xF2, 0xB9, 0x57, 0x27, 0xBC, + 0x97, 0xBC, 0x35, 0xA5, 0xE4, 0x51, 0xA2, 0x8C, 0xF0, 0xCA, 0x82, 0x79, 0x47, 0xD2, 0x70, 0xD4, + 0x64, 0x6B, 0x62, 0x6D, 0xBA, 0xA3, 0x4A, 0x99, 0x5B, 0xC1, 0x91, 0x5E, 0x0A, 0xFE, 0x6C, 0x1F, + 0xD9, 0x0A, 0x8D, 0x8A, 0x09, 0xA1, 0x1A, 0x5C, 0xFD, 0x93, 0xE4, 0xB9, 0xDB, 0xB7, 0x0F, 0xC7, + 0x2E, 0x03, 0x89, 0xC7, 0x74, 0x89, 0xD5, 0xD7, 0x1F, 0x7A, 0x62, 0xD8, 0x87, 0x9E, 0xF3, 0x2D, + 0x4A, 0xC7, 0x72, 0x09, 0xCF, 0xB8, 0x45, 0x7A, 0x27, 0xF6, 0x57, 0x6B, 0xF2, 0xCE, 0xFA, 0x7B, + 0xBF, 0xA0, 0xE4, 0xDC, 0x79, 0x48, 0x90, 0x2B, 0xA0, 0x39, 0x68, 0xB3, 0x4F, 0x79, 0x87, 0x1A, + 0xB4, 0x8E, 0x12, 0xB7, 0x40, 0x18, 0x5C, 0x3F, 0x99, 0x1D, 0xF3, 0x41, 0x2C, 0xB8, 0xD5, 0x61, + 0x6C, 0x39, 0x20, 0x15, 0xDC, 0xE6, 0xA1, 0x23, 0x41, 0xF2, 0xCE, 0x17, 0xE9, 0xE1, 0xD0, 0xEB, + 0x04, 0x81, 0xC6, 0x60, 0xA9, 0xAD, 0x9B, 0xDD, 0x66, 0x3C, 0xE5, 0x70, 0xAA, 0x28, 0xA2, 0x8B, + 0x2F, 0xF3, 0xB9, 0xB4, 0xC9, 0x8D, 0x00, 0x65, 0x65, 0x8E, 0x40, 0x5A, 0xB4, 0x6A, 0xB9, 0x48, + 0x33, 0x79, 0x31, 0xCC, 0xA4, 0x0D, 0x8C, 0x38, 0x56, 0xE0, 0x16, 0x00, 0x40, 0x65, 0x2D, 0x84, + 0xDE, 0x10, 0xE3, 0x43, 0x3B, 0x2C, 0x37, 0x5D, 0x38, 0x05, 0x26, 0x5D, 0x3C, 0xC7, 0x04, 0xE1, + 0x0B, 0xC9, 0xA8, 0xC3, 0x14, 0xF8, 0x02, 0x50, 0x40, 0x86, 0xCA, 0x57, 0xB3, 0xED, 0x05, 0xD1, + 0xC4, 0x8F, 0x6D, 0x1D, 0xD0, 0xD4, 0xBA, 0xAF, 0xC8, 0x6B, 0xE5, 0xBA, 0x63, 0xE5, 0x65, 0x52, + 0x03, 0xF1, 0xE1, 0x52, 0xB8, 0xC1, 0x21, 0xB8, 0x9B, 0xA6, 0x56, 0xEE, 0xDA, 0x18, 0x05, 0xC8, + 0x42, 0xAA, 0xB9, 0xC4, 0x08, 0x78, 0xD4, 0xFE, 0x48, 0xE4, 0xD7, 0x08, 0x39, 0x91, 0x7A, 0x21, + 0x5B, 0x46, 0x0F, 0x9A, 0x3F, 0xC8, 0x5C, 0xF2, 0xAD, 0x40, 0xED, 0xEE, 0x29, 0xA3, 0x97, 0x0D, + 0xEE, 0x89, 0x35, 0xE4, 0xBB, 0xCD, 0x9F, 0xEF, 0x39, 0x1D, 0x11, 0x6F, 0xDC, 0x56, 0x22, 0x4B, + 0x0F, 0x6F, 0xA7, 0x19, 0xE5, 0xDD, 0xD0, 0x48, 0x10, 0xB2, 0xDA, 0xEB, 0x26, 0x0C, 0x8E, 0x56, + 0x4B, 0x1F, 0x35, 0xD8, 0x0F, 0x79, 0x8D, 0xB6, 0x06, 0x49, 0x95, 0x7F, 0x12, 0xAA, 0x00, 0xBF, + 0xB9, 0x40, 0xA4, 0x2B, 0xCB, 0x16, 0xC3, 0x85, 0xB2, 0x64, 0xF0, 0x59, 0x12, 0x94, 0xB0, 0xA9, + 0x02, 0xDC, 0x31, 0x9A, 0xB8, 0xC4, 0xB2, 0x9B, 0x05, 0x86, 0xFF, 0xD7, 0x48, 0xB9, 0x7B, 0x3E, + 0x85, 0xF5, 0x3C, 0xD9, 0x87, 0xCE, 0xDA, 0x97, 0xFE, 0x56, 0x52, 0x28, 0x23, 0x16, 0x88, 0xB4, + 0xF5, 0xC9, 0xF4, 0xBA, 0x2B, 0x95, 0x61, 0x7A, 0xF2, 0xF7, 0x31, 0x95, 0xCD, 0xA0, 0x90, 0x8A, + 0x3B, 0xBD, 0x71, 0x71, 0xD2, 0x19, 0x59, 0x7E, 0x82, 0x7A, 0x78, 0x17, 0xF3, 0x81, 0x7B, 0x72, + 0x1F, 0x4C, 0xDD, 0xF7, 0x0A, 0x99, 0x4A, 0x3D, 0x35, 0xB4, 0x96, 0x35, 0xFB, 0xB1, 0xF6, 0x6E, + 0x21, 0x2A, 0xB6, 0xEE, 0x4E, 0xDA, 0x6C, 0xA6, 0xDB, 0x2C, 0xBF, 0x09, 0xAA, 0xC0, 0x78, 0x9A, + 0xB1, 0x23, 0x1A, 0xBC, 0xF6, 0x59, 0x06, 0xC6, 0xE3, 0x1A, 0x71, 0xD5, 0x0A, 0xF0, 0xC1, 0x4D, + 0x8E, 0x12, 0x10, 0x0E, 0x21, 0xE0, 0xE2, 0x14, 0xB0, 0x65, 0x09, 0xC2, 0xE5, 0xDD, 0xFC, 0x43, + 0x3E, 0x6C, 0xBF, 0x75, 0xAD, 0x93, 0xAE, 0x06, 0x2F, 0x3B, 0x7D, 0x8E, 0xE9, 0x1C, 0x74, 0x5A, + 0xF2, 0x3C, 0xFF, 0x6A, 0x49, 0xCD, 0x2A, 0x9D, 0xBA, 0x40, 0xB3, 0x45, 0x6B, 0x93, 0xEA, 0xD1, + 0xD7, 0xED, 0x2D, 0x81, 0x55, 0xE6, 0xC4, 0x1C, 0xD0, 0x63, 0xC5, 0x6B, 0x26, 0x1A, 0x67, 0xA7, + 0x6E, 0x3B, 0x48, 0x4A, 0x28, 0xA8, 0x73, 0xE4, 0xC2, 0xAF, 0xD7, 0x9A, 0x16, 0x70, 0x63, 0x71, + 0x7A, 0xB7, 0xE2, 0x25, 0x3F, 0x7D, 0x6D, 0x71, 0xFC, 0x7A, 0x33, 0x99, 0xFB, 0xEC, 0x0F, 0x5C, + 0x63, 0xD4, 0xD2, 0x89, 0xCF, 0x05, 0xBF, 0xBB, 0x61, 0x01, 0xC0, 0xD1, 0xC0, 0xA9, 0x91, 0x24, + 0x8E, 0xB9, 0x36, 0xDB, 0xD2, 0x34, 0x1D, 0x58, 0x94, 0xE8, 0xBA, 0x57, 0x1F, 0xB0, 0x75, 0x86, + 0xD7, 0x06, 0xC5, 0xDA, 0x01, 0x3D, 0x26, 0x0E, 0x33, 0xE2, 0xDB, 0x24, 0x86, 0x2A, 0xD8, 0x7D, + 0x36, 0x00, 0x6C, 0xB4, 0x02, 0x82, 0xA2, 0x7B, 0x92, 0x20, 0x26, 0xB7, 0x6B, 0x9A, 0x08, 0x40, + 0xC0, 0x93, 0x8C, 0x50, 0x27, 0xA8, 0x73, 0xFB, 0xA9, 0x78, 0x4E, 0x77, 0x50, 0x2A, 0x52, 0xBB, + 0xCE, 0x5B, 0xC2, 0x08, 0x75, 0x81, 0x97, 0xC0, 0xBF, 0x8E, 0x7E, 0x8F, 0x5A, 0xB1, 0xE5, 0xEC, + 0x44, 0xEA, 0x5F, 0x77, 0x4D, 0x8D, 0x4B, 0x35, 0xCE, 0x9F, 0x70, 0xEB, 0xA5, 0x1D, 0xDD, 0xE5, + 0xF6, 0x52, 0xE5, 0x51, 0x38, 0x0E, 0xB8, 0xA2, 0x8C, 0xE1, 0xE3, 0xAF, 0xE9, 0xAC, 0x46, 0x5F, + 0xAF, 0x1F, 0x2C, 0x56, 0xC5, 0xA0, 0xB1, 0xEF, 0x80, 0x2F, 0x5E, 0xE4, 0xE8, 0x49, 0x57, 0x52, + 0x27, 0xE6, 0x1B, 0x62, 0x52, 0xCD, 0x0B, 0x84, 0x7B, 0xD9, 0x8B, 0x0E, 0x28, 0x7A, 0x06, 0x01, + 0x59, 0x56, 0xB1, 0x89, 0xFD, 0x94, 0x0F, 0x9E, 0x2F, 0x36, 0x9F, 0x9F, 0x55, 0xA1, 0xE1, 0xFC, + 0x0F, 0x09, 0xD3, 0xE6, 0x73, 0xCC, 0x01, 0xF8, 0xA6, 0x5C, 0x25, 0xAF, 0x6A, 0x5F, 0x7F, 0x81, + 0x51, 0x9D, 0x01, 0x8A, 0xB5, 0x9F, 0xF7, 0x81, 0x63, 0x23, 0x96, 0xEE, 0x88, 0x77, 0xD2, 0xD0, + 0x8F, 0x74, 0xA2, 0x0B, 0x65, 0x64, 0x47, 0xFF, 0xB1, 0xA4, 0x1C, 0x27, 0x39, 0x85, 0x88, 0xD3, + 0xCD, 0x7D, 0xEB, 0x1C, 0x14, 0xFC, 0xC2, 0x7E, 0x0F, 0x21, 0x53, 0x20, 0xB9, 0x01, 0xD6, 0xCB, + 0xB0, 0x3B, 0xA5, 0x59, 0xAC, 0xF9, 0xEB, 0x71, 0x74, 0xF7, 0xA0, 0x72, 0xA4, 0xC9, 0x19, 0x86, + 0x25, 0x71, 0x59, 0x16, 0x7F, 0x2A, 0xEC, 0xDB, 0x10, 0x36, 0xE4, 0xE5, 0xCD, 0x0A, 0x3F, 0x18, + 0xFC, 0x28, 0xF5, 0xE0, 0x60, 0x0F, 0x18, 0x06, 0xEE, 0x8F, 0x28, 0x8C, 0x24, 0x22, 0x57, 0xCF, + 0xDC, 0x35, 0x2B, 0xA9, 0xBB, 0x18, 0x2E, 0x19, 0xDE, 0x4A, 0xCF, 0xBF, 0x70, 0xDB, 0x55, 0x25, + 0x73, 0xF7, 0x42, 0xFB, 0xEC, 0xA7, 0xCE, 0x47, 0xDF, 0x4A, 0x7F, 0x26, 0xBF, 0x5A, 0xDC, 0x97, + 0xB4, 0x12, 0x47, 0x6A, 0x7C, 0xD5, 0xA8, 0x8E, 0x1C, 0x57, 0xE0, 0x8F, 0xCC, 0x6E, 0xEA, 0x99, + 0x78, 0xC4, 0xAB, 0xAA, 0xA9, 0xC0, 0x83, 0x88, 0xCC, 0x64, 0x05, 0xD3, 0x9A, 0x2F, 0x5F, 0xDD, + 0x06, 0xA7, 0x3B, 0x55, 0xA5, 0x9C, 0xB5, 0x25, 0x3E, 0x25, 0x68, 0x72, 0xD5, 0xF5, 0x76, 0x7F, + 0x9B, 0xD2, 0x24, 0x22, 0xF1, 0xCB, 0x07, 0xC3, 0xE7, 0xAB, 0x8D, 0xBC, 0x26, 0x5A, 0x6F, 0x6C, + 0x32, 0x50, 0xBB, 0x91, 0xC4, 0xA8, 0x65, 0xB4, 0xBE, 0xA4, 0x3A, 0xEC, 0x88, 0xEE, 0xEB, 0x69, + 0x52, 0xFD, 0x7F, 0xA4, 0x51, 0x19, 0xF2, 0x1B, 0x52, 0x06, 0xF0, 0xC1, 0xB8, 0xF4, 0xE7, 0xD9, + 0x2A, 0x7F, 0xCD, 0x7F, 0x6E, 0x5A, 0x44, 0xD7, 0x41, 0x86, 0xBE, 0xD2, 0x67, 0x05, 0x50, 0x83, + 0x0B, 0x0D, 0xCE, 0xCD, 0xD6, 0xB7, 0x42, 0xD3, 0xD6, 0x69, 0x89, 0x68, 0xCB, 0xC4, 0x61, 0xA2, + 0x67, 0x3C, 0x82, 0x79, 0x3B, 0x4D, 0x0F, 0xA8, 0x11, 0x57, 0x14, 0xC7, 0x10, 0xA6, 0x72, 0x95, + 0x80, 0xEB, 0x23, 0x3F, 0x19, 0x26, 0x06, 0x7B, 0xBC, 0x68, 0x67, 0x9F, 0x2F, 0x57, 0x63, 0x82, + 0xD2, 0x91, 0xE4, 0x2C, 0x8D, 0x7C, 0x5E, 0xDA, 0xEB, 0xD2, 0xAB, 0xB9, 0xE3, 0x3F, 0x82, 0x0E, + 0x0E, 0x66, 0x56, 0x05, 0xDA, 0xB8, 0xDC, 0x2B, 0xB0, 0xD2, 0xF5, 0x47, 0xE1, 0x27, 0x12, 0xF2, + 0xBF, 0x87, 0x3C, 0xC4, 0x84, 0xB2, 0xB6, 0x70, 0x63, 0xB6, 0xC3, 0x1A, 0x67, 0x26, 0xB4, 0xAC, + 0x4C, 0xD8, 0x53, 0x1A, 0x47, 0x27, 0x9A, 0x0B, 0x29, 0x81, 0x7F, 0x60, 0x6B, 0x94, 0x95, 0x53, + 0xAB, 0xF0, 0x04, 0x9F, 0x96, 0x15, 0x75, 0x9D, 0x6A, 0x1D, 0x46, 0xF7, 0x31, 0xB7, 0xD4, 0x55, + 0xE0, 0xC1, 0x36, 0x63, 0xE5, 0xB3, 0xE5, 0x9A, 0xBA, 0xA2, 0x72, 0x2E, 0x13, 0xB5, 0xCB, 0x65, + 0x78, 0xC4, 0x91, 0x86, 0x54, 0xCF, 0x80, 0xE8, 0xFC, 0xD4, 0x2A, 0xA5, 0x04, 0xE7, 0xFC, 0x7D, + 0x35, 0xD8, 0x27, 0x8B, 0xEB, 0x94, 0xD6, 0x32, 0x9B, 0xC8, 0xA0, 0x3F, 0x17, 0x95, 0x1E, 0xF8, + 0x3D, 0xDE, 0x0A, 0xBF, 0xCE, 0xEE, 0x48, 0x97, 0x32, 0x2F, 0x7D, 0xE2, 0x61, 0x99, 0x66, 0x04, + 0x34, 0xB1, 0xB5, 0x9D, 0x9B, 0xB1, 0xF8, 0xCD, 0x52, 0x6E, 0x2F, 0xBD, 0xDC, 0x2B, 0x4A, 0x30, + 0xE0, 0x83, 0xE8, 0x65, 0xDD, 0x02, 0xCF, 0x02, 0xC9, 0xE3, 0x59, 0x3D, 0x98, 0x7E, 0xC7, 0x5B, + 0x59, 0x5A, 0x6E, 0x0F, 0xF4, 0x25, 0x4C, 0x23, 0xD7, 0x1E, 0xBE, 0xB9, 0x45, 0xCB, 0xF9, 0x65, + 0xDE, 0xB3, 0x08, 0x50, 0x70, 0x8D, 0x3E, 0x87, 0x58, 0x52, 0x16, 0x2A, 0xFA, 0xBC, 0x97, 0x7D, + 0xC2, 0xC7, 0xD6, 0x51, 0x22, 0xAA, 0xBE, 0xDC, 0x77, 0x74, 0x61, 0x42, 0xF2, 0xF1, 0x9A, 0x5C, + 0x74, 0x34, 0xD5, 0x1A, 0x77, 0x17, 0xD3, 0x70, 0x97, 0xED, 0xF1, 0x75, 0x9F, 0x54, 0x65, 0x66, + 0x4C, 0xAA, 0x11, 0xC2, 0x4B, 0xF4, 0x2F, 0x8A, 0x97, 0xCA, 0xA4, 0x36, 0x55, 0xC6, 0x22, 0x94, + 0xFD, 0x7F, 0xB4, 0xC7, 0x18, 0xC3, 0x3C, 0x2C, 0xED, 0x15, 0x49, 0x0C, 0xB9, 0x6A, 0xF2, 0xF4, + 0xE5, 0xA3, 0xDF, 0x16, 0x43, 0xB4, 0x24, 0x4C, 0xB8, 0x08, 0xCC, 0xA0, 0x35, 0x20, 0x5D, 0x8D, + 0xEA, 0xC2, 0xE1, 0x66, 0xEC, 0x3F, 0x1E, 0x80, 0x86, 0x4F, 0xD1, 0x82, 0x45, 0xC0, 0x97, 0xCE, + 0x38, 0x34, 0x40, 0x45, 0x70, 0x1D, 0x78, 0x56, 0x33, 0x0D, 0x11, 0x45, 0xEB, 0x94, 0x29, 0x0C, + 0x5D, 0xC2, 0xFE, 0x5B, 0x30, 0x47, 0x04, 0xE0, 0xE4, 0x01, 0x09, 0x51, 0xB2, 0x31, 0x05, 0x10, + 0x07, 0x73, 0xBC, 0x3E, 0x8C, 0x34, 0x65, 0x9B, 0x58, 0x6C, 0xE0, 0xF3, 0x3D, 0x2F, 0x5D, 0x81, + 0x76, 0x95, 0x85, 0x4C, 0xB0, 0xD3, 0x03, 0x8F, 0x61, 0x49, 0x0F, 0x60, 0x23, 0x90, 0xF0, 0x2A, + 0x85, 0xB1, 0x15, 0xD7, 0xB3, 0xBC, 0xBA, 0x31, 0xD2, 0x58, 0x5F, 0x63, 0x3F, 0x14, 0xFF, 0x6D, + 0xC2, 0x0C, 0x1F, 0x62, 0x41, 0x9C, 0xFB, 0x2A, 0xB0, 0xBC, 0xF3, 0xFC, 0x2D, 0x0A, 0x36, 0x26, + 0x45, 0x28, 0x73, 0xCD, 0x54, 0x41, 0x71, 0xE5, 0xC9, 0xCB, 0x40, 0x1B, 0x6F, 0x66, 0x46, 0xE4, + 0x1A, 0xA8, 0x00, 0xC5, 0x23, 0x33, 0xAC, 0xAA, 0x5F, 0xA9, 0x8B, 0x73, 0x29, 0xF1, 0x32, 0xCE, + 0xCF, 0x8F, 0xB6, 0x51, 0x6B, 0xA5, 0xEE, 0xA5, 0x3F, 0xC7, 0xA6, 0x1C, 0xD8, 0x75, 0x39, 0xDA, + 0x46, 0xAB, 0xBC, 0x9C, 0x44, 0x82, 0x08, 0x7E, 0xE1, 0x61, 0x62, 0xC5, 0x5F, 0x9A, 0xB7, 0x26, + 0xCD, 0x15, 0xAC, 0x1B, 0xC0, 0x1F, 0x1A, 0xCA, 0x9A, 0x14, 0x13, 0x68, 0xD1, 0x39, 0x54, 0x6F, + 0x47, 0x3F, 0x79, 0xE2, 0x2E, 0x29, 0xCF, 0xAD, 0x94, 0x78, 0x21, 0xCD, 0x57, 0xEB, 0xB7, 0x3D, + 0x7B, 0x29, 0xA1, 0x82, 0x03, 0x58, 0x2B, 0xEF, 0x7E, 0x5B, 0x09, 0x05, 0xA0, 0x31, 0xB8, 0x34, + 0xBF, 0xBC, 0x20, 0x41, 0x51, 0x6F, 0x49, 0x4E, 0xC8, 0xA2, 0xCD, 0x31, 0xBB, 0xC4, 0xBE, 0x4F, + 0x9F, 0xE4, 0xD1, 0xD5, 0x18, 0x58, 0x96, 0xDA, 0x7A, 0x03, 0x6B, 0xD1, 0xCA, 0x66, 0x0F, 0x3A, + 0x61, 0x12, 0x6D, 0xC4, 0xC8, 0xD3, 0x02, 0xE6, 0x1B, 0x6A, 0xDB, 0xB3, 0x2C, 0xF0, 0xFB, 0xC2, + 0xF8, 0x8F, 0xB3, 0x77, 0x8C, 0x0B, 0x2D, 0x3C, 0x69, 0x72, 0x05, 0x07, 0x37, 0x50, 0x8F, 0x5C, + 0xCF, 0x18, 0xC8, 0xAC, 0x4B, 0x04, 0x95, 0xD6, 0xA6, 0xB5, 0x0E, 0x70, 0xD4, 0x1A, 0xA8, 0xB5, + 0xE1, 0x2C, 0x62, 0x08, 0x68, 0x68, 0x23, 0xE9, 0x48, 0xED, 0xA7, 0x1A, 0x5B, 0x34, 0x0A, 0xE4, + 0x44, 0x6B, 0x2B, 0x32, 0x6D, 0x9E, 0x86, 0x3C, 0xC2, 0xE8, 0xA3, 0x5A, 0xD0, 0x76, 0x1E, 0x62, + 0x21, 0x6B, 0x57, 0x73, 0x21, 0x32, 0xB3, 0x42, 0xEA, 0x9A, 0x46, 0xB8, 0x83, 0xF6, 0x24, 0x50, + 0x7D, 0x1D, 0xFE, 0x23, 0xEE, 0x0B, 0x54, 0xCB, 0x73, 0x7C, 0x14, 0x1D, 0xEA, 0xA6, 0xDF, 0xF6, + 0xBF, 0xAA, 0xC5, 0xA7, 0xEC, 0xF6, 0x67, 0x4B, 0xFC, 0x89, 0x24, 0xDE, 0x3A, 0x15, 0x9E, 0xC9, + 0xDF, 0x08, 0x7B, 0x4F, 0x81, 0x46, 0x47, 0x05, 0x75, 0xDD, 0x6F, 0xE2, 0xA6, 0x1A, 0x26, 0xE1, + 0x72, 0x66, 0x63, 0x78, 0x58, 0x87, 0xFB, 0x65, 0x25, 0xA3, 0x24, 0x64, 0x23, 0x6D, 0xA1, 0xC6, + 0x95, 0x78, 0x92, 0x7F, 0x1C, 0xAF, 0x45, 0x50, 0x80, 0x8A, 0x32, 0xE7, 0x0C, 0x03, 0xC1, 0xF9, + 0xF6, 0xB6, 0xB3, 0xFD, 0x4D, 0x64, 0x32, 0xE4, 0x65, 0x8C, 0xDC, 0x30, 0x07, 0xBD, 0x4A, 0xEB, + 0x05, 0x08, 0x04, 0xBB, 0xA4, 0xF1, 0x7A, 0x6B, 0xBA, 0x81, 0x4F, 0xB0, 0xFB, 0x3E, 0x10, 0x16, + 0x32, 0x6A, 0x8E, 0x5E, 0x1B, 0xEC, 0x23, 0x7B, 0x47, 0xE9, 0x4A, 0xE6, 0xAC, 0x23, 0xE2, 0xF8, + 0x50, 0x7C, 0x87, 0x89, 0xC4, 0xAD, 0x16, 0x50, 0xB6, 0x8A, 0x6E, 0xB0, 0xE2, 0x39, 0x97, 0xF5, + 0x17, 0x2E, 0xEB, 0x88, 0x37, 0x93, 0x66, 0xD9, 0xA5, 0x49, 0xD2, 0x2B, 0x95, 0x27, 0x92, 0x0A, + 0x83, 0x50, 0x61, 0x64, 0x11, 0x71, 0xE1, 0x47, 0xDC, 0x32, 0x5D, 0x85, 0x84, 0x64, 0x3E, 0x7A, + 0xE7, 0x9C, 0x83, 0x20, 0x07, 0x93, 0xBB, 0xA8, 0x9C, 0xD2, 0xF3, 0xAD, 0x27, 0x1E, 0x07, 0x78, + 0xB6, 0xD8, 0xBB, 0x22, 0xEC, 0xF9, 0x54, 0x36, 0xE6, 0xC4, 0x03, 0x1A, 0x09, 0x25, 0x60, 0xD8, + 0x39, 0x1A, 0x34, 0x5C, 0x38, 0x2A, 0xAD, 0x55, 0x3C, 0x4F, 0x18, 0x85, 0x60, 0xF1, 0x18, 0x3A, + 0xBB, 0x15, 0x54, 0x93, 0x5B, 0x4C, 0xD5, 0x15, 0x4B, 0x61, 0x7B, 0x52, 0xE6, 0x6B, 0xCB, 0x78, + 0x2E, 0x01, 0x03, 0xCF, 0x9F, 0x7C, 0xCD, 0xF9, 0x31, 0xA4, 0xCC, 0xE0, 0xE0, 0x57, 0x30, 0x96, + 0x02, 0xD1, 0xA1, 0x4A, 0xA6, 0x77, 0x32, 0x12, 0xFC, 0x4C, 0x40, 0x50, 0xBF, 0x78, 0x03, 0x53, + 0x51, 0xF6, 0x09, 0xCA, 0xF2, 0x0B, 0x8B, 0x03, 0xDD, 0x49, 0x74, 0x7C, 0x00, 0x45, 0x5C, 0x46, + 0x2D, 0x17, 0x3B, 0x9D, 0x89, 0xB9, 0x3C, 0x48, 0x47, 0xBC, 0x98, 0x37, 0x76, 0x13, 0x22, 0x00, + 0x4F, 0x63, 0xB4, 0xA0, 0x7C, 0x3C, 0x5E, 0x64, 0xBB, 0xCB, 0xBF, 0xBC, 0x08, 0x50, 0x67, 0x5D, + 0xAC, 0x34, 0xDE, 0xCF, 0xD4, 0x8B, 0xBD, 0x3C, 0x21, 0x2D, 0xC7, 0x74, 0x92, 0xCD, 0x4C, 0x61, + 0x0F, 0x62, 0x20, 0xA8, 0xFB, 0x79, 0x83, 0x63, 0xE3, 0x00, 0xBE, 0x77, 0x2E, 0x77, 0x80, 0x4C, + 0xB0, 0x85, 0x8B, 0x42, 0x92, 0x5D, 0xF1, 0x66, 0xAA, 0x3B, 0x1F, 0x45, 0x4B, 0xCE, 0x58, 0x49, + 0x66, 0x38, 0xA6, 0x76, 0xF7, 0x41, 0x7F, 0x3E, 0x12, 0xD7, 0xF1, 0x9E, 0xB7, 0x11, 0xE2, 0x3C, + 0xCB, 0xC9, 0x5A, 0x99, 0x28, 0x9E, 0x8B, 0x3E, 0xDA, 0xDC, 0x28, 0xDE, 0xD1, 0x52, 0x6F, 0x34, + 0x1A, 0x10, 0xE1, 0xCD, 0xF9, 0xC0, 0x3F, 0x05, 0x28, 0x19, 0x30, 0x3E, 0xFF, 0x2B, 0xEF, 0x3C, + 0x94, 0xF0, 0x26, 0x2E, 0x83, 0x76, 0x51, 0x8F, 0x6B, 0x11, 0x08, 0xB0, 0x72, 0x66, 0x8F, 0xD6, + 0x57, 0x7A, 0x85, 0x1F, 0x12, 0xB6, 0x68, 0x4E, 0x4C, 0xDE, 0xA1, 0xED, 0x7D, 0x42, 0x7B, 0xEC, + 0x34, 0x46, 0x1D, 0x36, 0x8C, 0x48, 0xF6, 0x01, 0x16, 0xBD, 0x7E, 0x6D, 0x62, 0x2B, 0x83, 0xD3, + 0x18, 0x1F, 0x83, 0x66, 0x74, 0x2E, 0x6D, 0xB1, 0x28, 0xC0, 0x7F, 0x05, 0x97, 0x0D, 0xE8, 0x2F, + 0xE4, 0x61, 0x9E, 0x78, 0xF4, 0xEA, 0x29, 0x60, 0x15, 0x64, 0x3A, 0x77, 0x92, 0x48, 0x36, 0xBA, + 0x56, 0xDF, 0xB8, 0xCE, 0x71, 0x0D, 0x2D, 0x0B, 0x4C, 0x27, 0x7B, 0x7E, 0xD5, 0x06, 0xC2, 0x77, + 0x28, 0x51, 0x61, 0xB5, 0xAB, 0xCC, 0x3E, 0x84, 0xB8, 0xB3, 0xD1, 0x26, 0x52, 0x7C, 0xDC, 0xEE, + 0xDC, 0xE1, 0x59, 0x62, 0x83, 0xD7, 0xD6, 0xA7, 0x9B, 0xDA, 0x6E, 0x30, 0x76, 0x4D, 0xA3, 0x15, + 0x22, 0x09, 0x14, 0xC0, 0x74, 0xF8, 0x01, 0x47, 0x47, 0x0C, 0x70, 0x1C, 0xCD, 0xC9, 0xDB, 0x29, + 0x91, 0xBB, 0x7B, 0xD0, 0x2A, 0x79, 0xFF, 0xF9, 0x46, 0xA0, 0x15, 0x7D, 0x95, 0x64, 0xC6, 0x7C, + 0xA4, 0xC8, 0xC0, 0xAB, 0x07, 0xF7, 0x00, 0x42, 0xEA, 0xCF, 0x3D, 0x6B, 0x39, 0xBE, 0x7F, 0x72, + 0xCB, 0x78, 0x81, 0x15, 0x7E, 0x8C, 0xDF, 0xCF, 0x51, 0x0C, 0x45, 0xFD, 0x45, 0x6F, 0x2D, 0x63, + 0xF1, 0x8B, 0x38, 0xD2, 0x8B, 0x87, 0x38, 0x28, 0x86, 0xE7, 0x38, 0x94, 0xAB, 0x9F, 0x8E, 0x6F, + 0x0F, 0xF7, 0xB0, 0x53, 0x42, 0x1E, 0x1A, 0x82, 0xB5, 0x21, 0xA2, 0x1B, 0x7F, 0x33, 0x79, 0x2D, + 0xD4, 0x8C, 0x34, 0x76, 0x37, 0x33, 0x92, 0x4F, 0xE3, 0x08, 0x01, 0x84, 0x1E, 0x45, 0x2A, 0xF4, + 0x67, 0x76, 0x8D, 0x68, 0xC0, 0xB7, 0xF9, 0x24, 0x4A, 0x7A, 0x97, 0x2F, 0x4D, 0xA3, 0x94, 0xDF, + 0x73, 0x4F, 0x61, 0xCF, 0x46, 0xF7, 0x81, 0x14, 0x7C, 0x37, 0x4A, 0x3D, 0xE0, 0x5B, 0x0F, 0x3C, + 0xC5, 0x58, 0xA2, 0x3B, 0x8C, 0x16, 0xCD, 0x6D, 0xFC, 0xE5, 0xF6, 0xEE, 0x0C, 0xAB, 0xDA, 0x49, + 0xDA, 0xC4, 0xBF, 0x2E, 0x26, 0x38, 0x3C, 0xDD, 0x56, 0xA6, 0x80, 0xFB, 0x18, 0x7E, 0xB9, 0x17, + 0x63, 0x93, 0x9F, 0x34, 0xCF, 0x71, 0x5E, 0xD2, 0xEF, 0xB6, 0xF0, 0x72, 0x2D, 0xA4, 0xA7, 0x50, + 0x3D, 0x9E, 0xE9, 0x1B, 0x89, 0x56, 0x9F, 0xFF, 0x11, 0x24, 0x6C, 0xC6, 0x14, 0xF2, 0x64, 0x53, + 0x96, 0x60, 0x15, 0x2F, 0x01, 0x08, 0xB1, 0x97, 0xA0, 0x4C, 0x70, 0x91, 0x1A, 0x7F, 0x73, 0xE7, + 0x9C, 0xE6, 0xDA, 0x1C, 0x14, 0x3F, 0xD6, 0x85, 0x71, 0xCE, 0xF8, 0xD5, 0x0E, 0x91, 0xCC, 0x0D, + 0x58, 0x75, 0x6B, 0x8E, 0xF8, 0xD2, 0x81, 0xFE, 0xE1, 0x6E, 0xC8, 0x4F, 0x14, 0x91, 0x76, 0xEC, + 0x19, 0xEC, 0xD6, 0xBD, 0x68, 0x54, 0x25, 0xD0, 0x58, 0x40, 0xBC, 0x28, 0xC9, 0x0D, 0xFE, 0x6E, + 0x6C, 0x2D, 0xBA, 0xF2, 0x27, 0xCB, 0x5A, 0xC6, 0x8E, 0x85, 0xB0, 0x90, 0xC0, 0xC0, 0x63, 0xE1, + 0x46, 0x17, 0xE6, 0xC6, 0xB6, 0xDA, 0x7E, 0x5B, 0x02, 0x7B, 0xC1, 0xE7, 0xE3, 0xAA, 0x1D, 0xA1, + 0x0C, 0xD6, 0x41, 0x02, 0x71, 0x94, 0x5E, 0x87, 0xA1, 0x4E, 0x14, 0x92, 0xEC, 0xBF, 0x1F, 0x56, + 0x0F, 0x8F, 0x95, 0x0D, 0xCA, 0x61, 0xEE, 0x9F, 0xEE, 0x04, 0x4F, 0xFE, 0x73, 0xD0, 0xB1, 0x4A, + 0x55, 0x7C, 0x57, 0xD2, 0x23, 0xD9, 0x1D, 0x7C, 0x88, 0x06, 0xA8, 0x9A, 0xF1, 0x89, 0xB4, 0x36, + 0xD6, 0x71, 0x83, 0x19, 0x08, 0xBA, 0x57, 0x97, 0x40, 0xF7, 0x2F, 0xBB, 0x5D, 0xD7, 0xAD, 0x4A, + 0x93, 0x4F, 0x81, 0xDA, 0xEB, 0x2B, 0xA8, 0x56, 0x43, 0x4A, 0xA2, 0xAD, 0x1B, 0xC3, 0x5C, 0xA0, + 0x0B, 0xE1, 0x50, 0x5C, 0xEE, 0x61, 0x3E, 0xEC, 0x38, 0x68, 0x1B, 0xDC, 0xEC, 0x8B, 0x55, 0xB9, + 0x74, 0xD4, 0x8D, 0x97, 0x2E, 0x43, 0xD2, 0xF3, 0x4D, 0x38, 0xF9, 0x1B, 0xF2, 0x23, 0xC9, 0x93, + 0x90, 0x1F, 0x86, 0xA7, 0xDC, 0x72, 0x67, 0x79, 0xAC, 0x4C, 0x07, 0x25, 0xA4, 0x83, 0x7E, 0x86, + 0x29, 0xBF, 0x84, 0xFC, 0xB8, 0xC7, 0xD8, 0x7F, 0x85, 0x90, 0xD4, 0xE7, 0xA1, 0x9D, 0xBC, 0x53, + 0x1E, 0x8F, 0x02, 0x3E, 0xC1, 0x6E, 0x93, 0x3D, 0x66, 0xF1, 0xD7, 0x8C, 0xE6, 0x9A, 0x46, 0xE9, + 0x93, 0x3F, 0xFF, 0x21, 0x20, 0xBE, 0xB7, 0x5F, 0x01, 0xE5, 0x43, 0x9F, 0x5E, 0x22, 0x74, 0x9E, + 0x59, 0xAF, 0xD0, 0x01, 0x76, 0x8D, 0x27, 0x16, 0x72, 0x53, 0xF1, 0x76, 0x96, 0x5D, 0x9C, 0xD6, + 0x39, 0x26, 0xD4, 0x85, 0x30, 0xD7, 0x51, 0xD3, 0xB1, 0x6C, 0x3D, 0xC2, 0xD5, 0xFF, 0x82, 0x4B, + 0x46, 0xAB, 0x03, 0x91, 0x63, 0x5C, 0xEB, 0x35, 0x07, 0x4B, 0x61, 0x19, 0x90, 0x1E, 0x3F, 0x62, + 0x82, 0x80, 0xAE, 0xC1, 0xE5, 0xA9, 0x1A, 0x66, 0xF3, 0x56, 0xB0, 0x2E, 0xB8, 0x43, 0x81, 0xF5, + 0xA4, 0xCA, 0xA0, 0x91, 0xFD, 0x65, 0x4B, 0x87, 0xB1, 0xC5, 0xF6, 0x03, 0xE0, 0x1D, 0x15, 0x16, + 0x08, 0x6B, 0x8C, 0x3E, 0xFD, 0x43, 0x82, 0xB5, 0x01, 0x47, 0x66, 0x32, 0x33, 0x3E, 0x45, 0xD1, + 0x79, 0xAF, 0x84, 0x80, 0xB7, 0xA1, 0xC4, 0x2E, 0x27, 0x21, 0x09, 0x08, 0x38, 0x1F, 0x26, 0xD4, + 0xCC, 0x4E, 0x12, 0xE7, 0xD6, 0x59, 0xAE, 0x04, 0x29, 0x38, 0xA6, 0x69, 0x37, 0x32, 0x50, 0xB0, + 0xBB, 0xB6, 0xB6, 0x7C, 0x71, 0x92, 0x8A, 0xFE, 0xAE, 0x1F, 0x10, 0x7C, 0xE3, 0xA8, 0x5F, 0xD3, + 0xBF, 0x7D, 0xE3, 0xB2, 0x40, 0x44, 0x32, 0x9F, 0xD9, 0x62, 0xF0, 0xA4, 0x7A, 0x0B, 0x5D, 0x19, + 0x0F, 0x01, 0x05, 0x99, 0xC7, 0xD1, 0x7E, 0xED, 0x1E, 0xF2, 0xA9, 0x80, 0xBC, 0xC7, 0x70, 0x81, + 0x77, 0x1D, 0x1B, 0xAB, 0x4C, 0xCE, 0xE7, 0xF6, 0xD3, 0x72, 0x8F, 0xC4, 0x8E, 0x8F, 0x5D, 0x97, + 0x99, 0xB0, 0xCA, 0xB3, 0x08, 0x38, 0x2A, 0x72, 0xB7, 0xFD, 0xC2, 0x09, 0x6E, 0x50, 0xF8, 0xBE, + 0xA2, 0xA8, 0x88, 0x38, 0x53, 0xC7, 0xA5, 0x71, 0x12, 0x68, 0x3B, 0x49, 0x89, 0xFA, 0x98, 0x45, + 0x61, 0xC1, 0x3C, 0x26, 0xC5, 0x54, 0x08, 0xD4, 0x00, 0xE8, 0xDC, 0x77, 0xF2, 0x02, 0x9A, 0xE6, + 0x4E, 0xA6, 0x92, 0x96, 0xE1, 0x87, 0x99, 0x43, 0x87, 0xFF, 0x0C, 0xCF, 0xDD, 0x2C, 0xBB, 0x9E, + 0xF8, 0x43, 0xE1, 0xD7, 0xAA, 0x7F, 0x19, 0xC2, 0xF1, 0x95, 0x64, 0x18, 0xCD, 0x19, 0xA3, 0x85, + 0x81, 0x24, 0x7F, 0x64, 0x90, 0x24, 0xC6, 0x1F, 0x8E, 0x7B, 0x69, 0x93, 0x33, 0x95, 0xB3, 0x97, + 0x9E, 0x27, 0xD3, 0xB5, 0x36, 0x6E, 0x4D, 0xBC, 0x11, 0xB3, 0x5D, 0x6C, 0xD7, 0x7A, 0x6F, 0x42, + 0x8B, 0x4C, 0x6F, 0xCF, 0xC5, 0x68, 0x7F, 0xEF, 0x95, 0xFE, 0xE3, 0x46, 0x59, 0xB4, 0x22, 0x91, + 0xD3, 0x5E, 0x55, 0xD9, 0x75, 0xE4, 0x23, 0x40, 0x4C, 0xB0, 0x9D, 0x6F, 0x0A, 0xBA, 0x76, 0x72, + 0x8C, 0x86, 0xEE, 0xD5, 0xE9, 0x50, 0xA6, 0x82, 0x3B, 0x15, 0xFA, 0xA7, 0xCB, 0x0E, 0x96, 0xFF, + 0xD3, 0x45, 0xFB, 0x75, 0x14, 0xC0, 0xFB, 0x23, 0xE6, 0x7E, 0x1F, 0xF7, 0x32, 0xDD, 0xE9, 0xEB, + 0x62, 0x89, 0x69, 0xF8, 0x06, 0x4F, 0xCE, 0x98, 0x9E, 0x9E, 0xE5, 0x40, 0xE1, 0xE5, 0x5E, 0x60, + 0x2A, 0xB2, 0xD3, 0xC8, 0xF9, 0x28, 0xF5, 0x32, 0x78, 0xC7, 0x8D, 0x2E, 0xD8, 0xA1, 0x82, 0xF3, + 0xED, 0x0A, 0xFE, 0xEB, 0xAC, 0x6F, 0xFE, 0xB6, 0x1A, 0x29, 0xE7, 0x51, 0x4A, 0x3E, 0x03, 0xEF, + 0x7B, 0x30, 0x49, 0x94, 0x0B, 0xC2, 0xE9, 0x1D, 0x6E, 0xE3, 0x6E, 0x07, 0xE7, 0xCA, 0xB3, 0xEE, + 0x8F, 0x72, 0x78, 0xFC, 0x9B, 0xA0, 0xB8, 0x74, 0xCC, 0xC3, 0x04, 0x01, 0x00, 0xA5, 0xAC, 0x56, + 0x59, 0xCE, 0x00, 0xAD, 0xFF, 0x32, 0xD2, 0x79, 0x5D, 0x81, 0x82, 0x3E, 0xDD, 0x33, 0x67, 0x37, + 0x37, 0x50, 0x3B, 0xD7, 0x87, 0x6A, 0x54, 0x34, 0x9E, 0x7F, 0x2C, 0x0C, 0x0B, 0x02, 0xA3, 0xDD, + 0xFD, 0x13, 0x87, 0x12, 0xBC, 0xC2, 0xAF, 0x19, 0xEB, 0xC0, 0x52, 0x49, 0xC4, 0x97, 0xBC, 0x7E, + 0x2C, 0x51, 0x6D, 0x72, 0xB7, 0xD3, 0xA3, 0x48, 0x15, 0x8B, 0x75, 0x14, 0x9A, 0x90, 0xA9, 0xD4, + 0xD4, 0x38, 0x00, 0xC0, 0x6B, 0x1B, 0x69, 0xCD, 0xF8, 0x9D, 0xC5, 0xC6, 0x45, 0x2D, 0xAE, 0x13, + 0x93, 0x50, 0x24, 0xBB, 0x27, 0x21, 0x47, 0xA1, 0x41, 0xBB, 0x20, 0x7C, 0xDF, 0x1B, 0x32, 0x68, + 0xE1, 0x4E, 0xC4, 0x04, 0x3F, 0x31, 0x0F, 0xC8, 0x10, 0x71, 0xD2, 0xCE, 0xAD, 0x1C, 0x19, 0x89, + 0x7B, 0x09, 0xB1, 0x36, 0x69, 0x38, 0xDB, 0xFE, 0x52, 0x76, 0x57, 0xAA, 0x3D, 0x21, 0x44, 0x2A, + 0x9F, 0x3A, 0xFD, 0xEB, 0x52, 0xBA, 0x08, 0x34, 0x66, 0x39, 0xE4, 0x8B, 0x97, 0x09, 0xDC, 0xA4, + 0x4D, 0xE7, 0x15, 0xBB, 0x0A, 0xC8, 0xE8, 0x15, 0xDB, 0x96, 0x02, 0x1C, 0xA8, 0x06, 0xE4, 0xD1, + 0x6D, 0x17, 0x1C, 0xCF, 0x2C, 0x19, 0x7A, 0x9C, 0x59, 0x34, 0xF9, 0x10, 0xBF, 0x88, 0xFF, 0x31, + 0xB4, 0x7D, 0x59, 0x5D, 0x69, 0x06, 0x46, 0x60, 0x57, 0xA2, 0xEA, 0xFE, 0x2D, 0xBF, 0x25, 0x69, + 0x7A, 0xA8, 0xB0, 0x46, 0x0A, 0x7D, 0x86, 0x81, 0xD6, 0x46, 0x0B, 0x2D, 0xB7, 0xD2, 0xEE, 0xD4, + 0x57, 0x27, 0xD1, 0x6C, 0x9E, 0x46, 0xCB, 0xA1, 0x36, 0x18, 0x6D, 0xC2, 0x01, 0x8C, 0xC0, 0x81, + 0x89, 0x85, 0xD6, 0xB9, 0x03, 0x6D, 0xCA, 0xE5, 0x5A, 0xE6, 0xBA, 0x15, 0x5E, 0xA6, 0x2F, 0x99, + 0x6B, 0xA1, 0x7D, 0x44, 0x56, 0x90, 0x26, 0xB9, 0x53, 0x46, 0x4C, 0x5F, 0xF9, 0x43, 0x69, 0x2E, + 0x41, 0x43, 0x12, 0x66, 0x77, 0xF3, 0x5E, 0x1A, 0x79, 0xAD, 0xE8, 0xB1, 0x14, 0x54, 0x37, 0x04, + 0x27, 0x9E, 0xC8, 0x13, 0x10, 0x3F, 0x21, 0xE7, 0x97, 0x97, 0xA5, 0xBB, 0xC4, 0x0C, 0x5E, 0x85, + 0x03, 0xEC, 0x23, 0x74, 0x32, 0xE8, 0x61, 0x93, 0x66, 0xCB, 0x98, 0x61, 0x8E, 0x5E, 0x7E, 0x4E, + 0xE3, 0x3E, 0x9A, 0xC1, 0x4A, 0xAF, 0xBA, 0x93, 0xC2, 0x7E, 0x65, 0xFF, 0x94, 0x38, 0x1E, 0x74, + 0x15, 0xA8, 0x8A, 0xE3, 0x44, 0x6B, 0x6F, 0x29, 0x0B, 0xF2, 0xAF, 0x9F, 0x31, 0x69, 0x7A, 0x0C, + 0x65, 0x36, 0xEE, 0xF6, 0xD6, 0x5E, 0x2C, 0x8E, 0x5E, 0x03, 0x6C, 0xB4, 0xBB, 0xF2, 0xDB, 0xFF, + 0xFA, 0x1F, 0x94, 0x1C, 0x7A, 0xF2, 0x23, 0x01, 0xB2, 0xF5, 0x53, 0xD6, 0xDB, 0xA4, 0x6A, 0x2B, + 0x97, 0x77, 0x95, 0xB6, 0x37, 0x51, 0xFE, 0xF3, 0xAA, 0xE2, 0x0C, 0xF4, 0x19, 0x1F, 0x27, 0x37, + 0x2B, 0x00, 0xB8, 0xC8, 0x18, 0xC8, 0x35, 0xAE, 0xE6, 0x65, 0xB1, 0x45, 0x9B, 0x24, 0xEE, 0xAF, + 0xDF, 0x93, 0xD3, 0xDE, 0xBE, 0x29, 0xD6, 0x64, 0x90, 0xF7, 0x77, 0x47, 0x1E, 0x0B, 0xBE, 0x19, + 0x19, 0x3E, 0x98, 0x2B, 0xBA, 0x78, 0x28, 0x20, 0x8F, 0xBA, 0xE0, 0x20, 0x96, 0x29, 0x9C, 0x59, + 0x5A, 0x7A, 0x39, 0x19, 0x54, 0xF1, 0x9D, 0xC4, 0xE4, 0x6C, 0xE4, 0x9E, 0x6D, 0x8B, 0x7A, 0x4E, + 0x4D, 0x88, 0xA3, 0x6D, 0x81, 0x13, 0x76, 0x49, 0x4C, 0xF1, 0x29, 0xD7, 0x51, 0x74, 0x09, 0x98, + 0x73, 0xD6, 0xB1, 0xD0, 0x04, 0x5B, 0x26, 0xA7, 0xDF, 0x29, 0xB9, 0x1C, 0xDB, 0x92, 0x0B, 0x8C, + 0x3D, 0x7F, 0xD8, 0x86, 0x17, 0x77, 0x4A, 0xBF, 0xDA, 0x2F, 0x42, 0x7C, 0x65, 0x31, 0x92, 0x93, + 0xF2, 0x55, 0x96, 0x13, 0x8C, 0x52, 0x9C, 0x0E, 0x7D, 0x94, 0xAD, 0x80, 0x19, 0x21, 0x3B, 0x2B, + 0x0E, 0x36, 0x7B, 0x67, 0x6B, 0xF9, 0xB8, 0x5B, 0x63, 0x34, 0x85, 0xB7, 0xF4, 0xEC, 0xBD, 0xC1, + 0x74, 0xDC, 0xCB, 0x06, 0xEE, 0x95, 0x40, 0xF4, 0x20, 0x22, 0xBF, 0xBE, 0x9F, 0xD5, 0xF4, 0xFD, + 0xBD, 0xC0, 0x37, 0x22, 0xDF, 0xDA, 0xDF, 0x2C, 0x35, 0xD2, 0xBA, 0xB4, 0x02, 0x39, 0x0B, 0x5B, + 0xFB, 0xFA, 0x94, 0x55, 0x0D, 0x6C, 0x9A, 0x2B, 0xCB, 0xF1, 0x2C, 0x35, 0x15, 0x6C, 0x72, 0x85, + 0x66, 0x9D, 0x3E, 0x0B, 0x64, 0x95, 0x6C, 0xF7, 0xB4, 0x0D, 0x4F, 0x9A, 0x71, 0xF1, 0x98, 0x95, + 0xF6, 0x80, 0x41, 0x49, 0xE7, 0xDF, 0xC7, 0x64, 0x1A, 0xB2, 0x52, 0x81, 0x47, 0x3B, 0xF4, 0x2E, + 0x2A, 0xAD, 0xD8, 0xBF, 0x78, 0x95, 0x2F, 0xE9, 0x69, 0xFB, 0xBC, 0x4A, 0x6C, 0x6E, 0xED, 0x3D, + 0x96, 0xF1, 0x9A, 0x31, 0x5D, 0x26, 0xB4, 0x1D, 0xBA, 0x28, 0x55, 0x47, 0x35, 0xAB, 0xDC, 0x77, + 0x68, 0x24, 0x8A, 0x04, 0xF0, 0x32, 0x4B, 0x62, 0xAB, 0xB8, 0x55, 0xA9, 0x14, 0x77, 0x09, 0xE2, + 0xF8, 0x99, 0xCF, 0x65, 0x0A, 0xC2, 0xC9, 0x94, 0x6F, 0xCA, 0x16, 0xAD, 0xF8, 0x05, 0x9F, 0x87, + 0x62, 0x5A, 0x17, 0xF8, 0x60, 0xBB, 0x6F, 0x84, 0x16, 0x02, 0xDD, 0x25, 0xD5, 0xD4, 0xE4, 0x4C, + 0x22, 0x9A, 0x33, 0xC9, 0x44, 0xC5, 0x47, 0xF5, 0xBF, 0x7D, 0xA8, 0xCC, 0x5C, 0xA0, 0x66, 0x5F, + 0x40, 0xA4, 0xBB, 0x85, 0x22, 0xBF, 0xB2, 0x28, 0x96, 0x5D, 0xF7, 0x50, 0x34, 0xF3, 0x52, 0xFE, + 0x9E, 0xE7, 0x99, 0x37, 0xD7, 0x99, 0xBC, 0x4A, 0x40, 0x42, 0x0C, 0xAE, 0x11, 0x73, 0x85, 0xFC, + 0x9A, 0x36, 0xF0, 0x68, 0xA5, 0x18, 0xA1, 0xEC, 0xE7, 0xC9, 0x18, 0x74, 0x25, 0xDC, 0x57, 0x4D, + 0x17, 0x3F, 0x48, 0x83, 0x70, 0x54, 0x35, 0xD1, 0x70, 0x57, 0x91, 0x16, 0x79, 0x49, 0x31, 0x74, + 0x0B, 0x79, 0x93, 0xDA, 0x77, 0x44, 0x3E, 0x79, 0xBA, 0xB2, 0x5A, 0x58, 0xAD, 0x74, 0x85, 0x41, + 0x2C, 0xDA, 0xB7, 0x84, 0xA3, 0x80, 0x32, 0xB8, 0x84, 0xE2, 0x81, 0x35, 0x72, 0x46, 0x96, 0x95, + 0x1E, 0x38, 0xEF, 0xE4, 0x3E, 0xA4, 0x77, 0x9C, 0x96, 0x53, 0x72, 0x94, 0x48, 0x29, 0xE5, 0xC6, + 0xA3, 0xF5, 0x14, 0xB5, 0xB5, 0xDD, 0xF9, 0x41, 0xE8, 0x6A, 0xD7, 0xB4, 0xEB, 0x67, 0x56, 0x51, + 0xA8, 0xC2, 0x10, 0x70, 0x2B, 0xB3, 0x43, 0x30, 0xA4, 0x1C, 0x54, 0x16, 0xCB, 0xFF, 0x6D, 0x17, + 0xA6, 0x21, 0x2D, 0xFB, 0x30, 0x87, 0xFB, 0xB5, 0xAD, 0x60, 0xFA, 0x29, 0x26, 0xF7, 0xC4, 0xD2, + 0x99, 0xF3, 0x89, 0x82, 0x95, 0x94, 0xA9, 0x3D, 0x49, 0x6A, 0x98, 0x0C, 0xAF, 0x3A, 0x02, 0x05, + 0x34, 0xC2, 0x9F, 0x50, 0x9D, 0x9C, 0x3D, 0xD2, 0x8D, 0x59, 0xAD, 0xCA, 0xA6, 0x71, 0x26, 0x88, + 0x1D, 0x0E, 0xA2, 0xBC, 0x72, 0xF8, 0x22, 0x74, 0x1E, 0x01, 0xEF, 0xAD, 0x0E, 0x05, 0xB0, 0xF2, + 0x00, 0xC5, 0xE5, 0xD2, 0x6A, 0xBF, 0xBF, 0xB4, 0xE6, 0x07, 0xF7, 0xF6, 0xF2, 0xF8, 0x35, 0x2E, + 0xD9, 0x34, 0x20, 0x25, 0x39, 0x47, 0xBC, 0x33, 0x9E, 0x6A, 0x56, 0x97, 0x68, 0x1D, 0x8E, 0xD5, + 0x4D, 0x61, 0xC5, 0x07, 0x5B, 0x3E, 0xAC, 0xC2, 0xC8, 0xA3, 0x21, 0x18, 0xD6, 0x3B, 0xBE, 0x48, + 0x89, 0x91, 0x4F, 0xF1, 0x8F, 0x84, 0x77, 0xDB, 0xD1, 0x53, 0x36, 0xF8, 0x01, 0x80, 0xBF, 0x90, + 0x6D, 0xA1, 0x4F, 0x70, 0x34, 0xC4, 0xCA, 0x8A, 0x27, 0x09, 0xF8, 0x3D, 0x13, 0x55, 0x28, 0x9B, + 0x23, 0x8F, 0x19, 0xF2, 0x39, 0xCC, 0x92, 0x64, 0xBA, 0x6A, 0x78, 0x31, 0x8C, 0x56, 0x7E, 0x3D, + 0xA0, 0x4B, 0x52, 0x05, 0xB4, 0xCE, 0x04, 0xF2, 0xA7, 0x4C, 0xD0, 0x4D, 0x99, 0xB7, 0x6B, 0x20, + 0x30, 0x16, 0x61, 0xB4, 0x39, 0xC1, 0xC0, 0x00, 0xD1, 0xB6, 0xC9, 0x67, 0x79, 0x1C, 0x0C, 0xAB, + 0xDF, 0xD7, 0xEB, 0x12, 0xD3, 0xE8, 0xD6, 0x70, 0x88, 0xCB, 0xDF, 0x60, 0xC9, 0xCE, 0x81, 0x47, + 0x8F, 0xB0, 0x78, 0x33, 0x78, 0x0F, 0x99, 0x90, 0xC6, 0x9A, 0x7C, 0xAB, 0x67, 0x29, 0x20, 0x88, + 0x62, 0x26, 0x4D, 0x18, 0x8A, 0xE1, 0xDD, 0xC0, 0x3E, 0x50, 0xB1, 0xB9, 0x2F, 0x5E, 0x02, 0x83, + 0xB6, 0x8C, 0x73, 0x96, 0xE1, 0x0E, 0xA2, 0x26, 0xCD, 0x98, 0x01, 0x90, 0xED, 0x1D, 0x28, 0x2E, + 0x92, 0xF2, 0x40, 0xCC, 0x7C, 0x66, 0x25, 0xC5, 0x55, 0x01, 0x0B, 0x7E, 0x03, 0x5A, 0x94, 0x91, + 0xD8, 0x18, 0x59, 0x8B, 0x05, 0x49, 0x30, 0xAE, 0x0D, 0xB0, 0xAB, 0xAA, 0x66, 0x90, 0xA4, 0x3E, + 0xD0, 0x0E, 0xDC, 0xA0, 0x97, 0x10, 0xAD, 0xBE, 0xF2, 0xD7, 0xDD, 0x40, 0x27, 0x96, 0x83, 0xD7, + 0x38, 0x7E, 0xD0, 0xFB, 0x53, 0xD0, 0x13, 0xAE, 0x61, 0xC8, 0xEB, 0x6F, 0x8C, 0x48, 0xEE, 0x50, + 0x72, 0x6B, 0x56, 0x05, 0xD6, 0x3B, 0xBC, 0x55, 0xF0, 0x79, 0xF2, 0xD8, 0x4D, 0x11, 0x09, 0x8C, + 0xC1, 0xD6, 0x54, 0xF9, 0xB2, 0xDE, 0xCE, 0x3A, 0x38, 0x08, 0xAB, 0xBF, 0xC9, 0xE1, 0x20, 0x62, + 0x97, 0x9D, 0x51, 0x1F, 0xA7, 0x32, 0xB6, 0x55, 0xF4, 0xDB, 0x2E, 0x7B, 0x85, 0xB1, 0xFF, 0x04, + 0xA7, 0xB6, 0x6F, 0xEA, 0x94, 0xF9, 0x87, 0xC9, 0x13, 0xEE, 0x68, 0x32, 0xD3, 0x68, 0x22, 0xBB, + 0x24, 0xC5, 0x80, 0x20, 0x56, 0xCB, 0x07, 0xAB, 0x78, 0xD0, 0x42, 0x5C, 0x9B, 0x70, 0xF5, 0x01, + 0xBF, 0x28, 0x94, 0xA6, 0x16, 0xB2, 0xE8, 0xF1, 0xF3, 0x68, 0x7B, 0x0A, 0xDA, 0xFF, 0x58, 0x94, + 0x1D, 0x78, 0x3A, 0x19, 0x7B, 0x39, 0x54, 0xAA, 0xDA, 0x7D, 0x9E, 0x14, 0x3F, 0x9B, 0x82, 0x6E, + 0x1B, 0xD3, 0xC3, 0xA7, 0x01, 0x9E, 0x22, 0x46, 0x0B, 0x99, 0x5A, 0x42, 0x29, 0xD3, 0xA2, 0xD6, + 0x89, 0x7A, 0x45, 0xAD, 0x8A, 0x2E, 0x0A, 0xFA, 0x09, 0x7F, 0x22, 0x84, 0x6E, 0xBC, 0x7C, 0x7D, + 0x32, 0x80, 0xB7, 0x06, 0x2C, 0x48, 0xF1, 0xA7, 0xEE, 0xF8, 0xC3, 0x83, 0x9C, 0xC1, 0x0E, 0xBB, + 0x85, 0x27, 0x2F, 0xFE, 0x1B, 0xC6, 0x47, 0xEB, 0x85, 0xD8, 0x3B, 0x09, 0x3C, 0xBB, 0x1C, 0x11, + 0x50, 0xA1, 0xE7, 0x16, 0x28, 0xA6, 0xDA, 0xE9, 0xF2, 0xAF, 0x26, 0x48, 0xC7, 0xC8, 0x75, 0x7B, + 0x8A, 0xA6, 0xA3, 0xCC, 0x7B, 0xCA, 0x60, 0x8F, 0xCA, 0x2A, 0xFA, 0xB9, 0xB0, 0xCC, 0xBD, 0x20, + 0x61, 0x67, 0x9D, 0x83, 0x6A, 0xB5, 0xFC, 0xE7, 0xA0, 0x52, 0x87, 0xB3, 0xFC, 0x7A, 0x2E, 0xC5, + 0xDD, 0x04, 0xD3, 0x8B, 0x3C, 0x55, 0x7D, 0x10, 0xCF, 0xC6, 0x21, 0xCF, 0x7D, 0x9A, 0x7E, 0xDE, + 0xB9, 0x04, 0x09, 0x27, 0xB7, 0x77, 0x23, 0xF1, 0x55, 0x92, 0x84, 0xA8, 0x7C, 0xA4, 0x6B, 0xE4, + 0x53, 0x91, 0xD1, 0xC7, 0xED, 0xCA, 0xAB, 0x8E, 0x3A, 0xD8, 0x71, 0xEC, 0x32, 0x3F, 0x95, 0xBB, + 0x01, 0xB9, 0xBF, 0x2B, 0xBC, 0x7F, 0xD3, 0x6E, 0xE0, 0x96, 0x2C, 0x47, 0xD1, 0x92, 0x5D, 0xAD, + 0x35, 0x99, 0x72, 0x4D, 0x1B, 0x7B, 0x33, 0x4E, 0x21, 0x3E, 0x7A, 0x8C, 0x71, 0x62, 0x0E, 0x2A, + 0x6E, 0xAD, 0xA6, 0xD6, 0xBB, 0x1E, 0x04, 0x58, 0x0E, 0x68, 0xCB, 0x4B, 0xF4, 0xD2, 0x90, 0xAD, + 0x3E, 0x14, 0x13, 0xA2, 0xC0, 0x54, 0xDF, 0x46, 0x7E, 0x43, 0xDE, 0x23, 0x5A, 0x2A, 0x0E, 0xB0, + 0x47, 0x18, 0x3C, 0x7C, 0xEE, 0xBE, 0xAE, 0xD0, 0x06, 0x2A, 0x8B, 0xCB, 0xCA, 0xDB, 0xAE, 0x43, + 0x1F, 0x79, 0x4E, 0x79, 0xAD, 0x4D, 0x44, 0xBE, 0x99, 0xC3, 0x82, 0x97, 0x1C, 0x21, 0xF1, 0x25, + 0xDE, 0x15, 0xEB, 0x1E, 0x20, 0xAF, 0x4E, 0x74, 0xD2, 0x9D, 0xB3, 0x62, 0x20, 0x62, 0xC5, 0xBA, + 0x54, 0x8E, 0xCC, 0x51, 0x99, 0xEE, 0xAE, 0xFE, 0x2D, 0xD5, 0x5B, 0xE6, 0xD6, 0xBA, 0x45, 0x18, + 0xDC, 0xB4, 0x73, 0x22, 0x3C, 0x5D, 0xF6, 0x90, 0x1E, 0xE8, 0x4F, 0x37, 0xBD, 0x04, 0x69, 0x85, + 0xDB, 0xA8, 0x2A, 0x39, 0x95, 0x3B, 0x1C, 0x2E, 0xE2, 0x18, 0xE7, 0xAF, 0x4C, 0x7A, 0xED, 0xCD, + 0xEC, 0x61, 0xE3, 0xFC, 0x94, 0xD8, 0xAA, 0x0A, 0xE0, 0xA0, 0x76, 0xFC, 0xFD, 0xF6, 0xDC, 0x1B, + 0xBA, 0xE0, 0xE5, 0xD7, 0xE4, 0x34, 0xDE, 0x63, 0xCE, 0x85, 0xEC, 0x57, 0x1E, 0xFC, 0x71, 0x5C, + 0xB0, 0x64, 0xE5, 0xA7, 0x21, 0x50, 0x69, 0x13, 0x27, 0x1D, 0xBE, 0x1E, 0x07, 0xF3, 0x49, 0xF1, + 0xEE, 0xBA, 0x9A, 0xB8, 0x17, 0x6E, 0x95, 0x2F, 0x89, 0xD8, 0xB9, 0x87, 0x1A, 0xCE, 0x6D, 0xF6, + 0xF2, 0xC1, 0xFB, 0x42, 0x6C, 0x1D, 0x2D, 0x5C, 0xE0, 0xA2, 0x69, 0x52, 0xF8, 0x2F, 0xD2, 0x75, + 0xDC, 0x1A, 0xC4, 0xC3, 0x53, 0x8E, 0x30, 0x80, 0x97, 0xE9, 0xAD, 0xF1, 0xD5, 0x69, 0xB9, 0x3A, + 0xD3, 0x63, 0x14, 0xBF, 0x93, 0x82, 0x10, 0x6E, 0x6F, 0x68, 0xE4, 0x16, 0x8E, 0x01, 0x1D, 0x0F, + 0xB8, 0x05, 0xD4, 0xAF, 0x06, 0xB1, 0xBA, 0x4A, 0x2A, 0xC5, 0x8E, 0x51, 0x82, 0x49, 0x06, 0x06, + 0xD4, 0xB9, 0x96, 0x6F, 0x3E, 0xAB, 0xAE, 0x2C, 0x2F, 0x65, 0x15, 0x13, 0xED, 0x3A, 0xAA, 0x2C, + 0x38, 0x2D, 0x0B, 0x05, 0xF9, 0xFE, 0x78, 0x2D, 0x6A, 0xBC, 0xCF, 0xE3, 0xC6, 0x42, 0x87, 0xB9, + 0x55, 0xF4, 0x38, 0x1E, 0x4B, 0x5E, 0x85, 0xBB, 0x00, 0xEE, 0xE1, 0x6E, 0xAE, 0x89, 0xA8, 0x5E, + 0x56, 0x19, 0xE4, 0xB0, 0xFD, 0x47, 0xD3, 0xD1, 0x0B, 0xC1, 0x6A, 0xA8, 0x62, 0x01, 0x05, 0x27, + 0x6A, 0xDB, 0x4E, 0xBF, 0xDE, 0xE2, 0xA8, 0x6F, 0x16, 0x20, 0xAC, 0xDD, 0x65, 0xA8, 0x60, 0x17, + 0xB7, 0x49, 0xF1, 0xBA, 0x47, 0x80, 0x4A, 0xBA, 0xD5, 0xEE, 0xA3, 0x28, 0xDF, 0xC7, 0x69, 0x44, + 0x7E, 0x41, 0xF6, 0xC4, 0x32, 0xE3, 0xD8, 0x8C, 0xA0, 0xF7, 0xD5, 0xC6, 0x09, 0xDB, 0xA9, 0x71, + 0x08, 0x44, 0x77, 0x56, 0xE1, 0xBE, 0xB8, 0x84, 0x0D, 0xB8, 0xE6, 0xE5, 0x20, 0x01, 0x85, 0xA5, + 0x9A, 0xCF, 0x5E, 0x5D, 0xEF, 0x49, 0x2F, 0x90, 0x44, 0xF2, 0x3A, 0x2A, 0xB6, 0xDA, 0xB0, 0xF0, + 0x55, 0x35, 0x95, 0x41, 0x7C, 0xFF, 0xD5, 0xFD, 0xE3, 0x15, 0xD9, 0xEB, 0xCB, 0x4C, 0x8E, 0x30, + 0x12, 0xCA, 0x58, 0xF5, 0xAE, 0x63, 0x1A, 0x5B, 0x68, 0x62, 0x80, 0x1B, 0x32, 0x11, 0xDB, 0xBE, + 0x8D, 0x5C, 0x4B, 0xFE, 0x08, 0x56, 0x36, 0x6C, 0x19, 0xA6, 0x74, 0x43, 0xA8, 0x1F, 0x7A, 0x33, + 0xE1, 0xDD, 0x49, 0x85, 0xEE, 0x8F, 0xDB, 0xD5, 0x53, 0x78, 0x8D, 0x00, 0x49, 0x48, 0xD1, 0x76, + 0x26, 0x05, 0x9B, 0xA2, 0x97, 0x16, 0xD3, 0x11, 0xD6, 0x3F, 0x78, 0x9D, 0xE6, 0x73, 0x0E, 0x61, + 0xCE, 0x90, 0x0E, 0xC6, 0xFD, 0xB1, 0x2E, 0xBD, 0x21, 0x6C, 0x7C, 0x8A, 0x8D, 0xD3, 0x27, 0xEA, + 0xC5, 0x92, 0xC1, 0xA0, 0x71, 0x0F, 0x82, 0x75, 0xFA, 0xE4, 0x94, 0x17, 0x2A, 0x19, 0x20, 0x07, + 0x4D, 0xD8, 0x5F, 0xF8, 0xED, 0xBD, 0x66, 0x92, 0xED, 0x5B, 0x98, 0x2B, 0xCC, 0x6B, 0x53, 0x6A, + 0xD1, 0x51, 0x4C, 0x52, 0x33, 0x90, 0xFA, 0xB3, 0xB8, 0xAA, 0xBB, 0x15, 0xEA, 0xAB, 0x61, 0xD9, + 0x72, 0x91, 0x1A, 0xAA, 0xFD, 0x5D, 0x3D, 0x50, 0xA7, 0xC5, 0x1F, 0x3A, 0x97, 0xD0, 0x52, 0xF6, + 0x02, 0xF6, 0x52, 0x44, 0xDB, 0xB6, 0x82, 0xAB, 0x15, 0x40, 0xF2, 0xF2, 0x7D, 0x1E, 0x8D, 0xE4, + 0xE3, 0xBB, 0x9E, 0x83, 0x22, 0xD5, 0x00, 0xB0, 0x10, 0x3D, 0xEE, 0x80, 0x3C, 0x0A, 0xA2, 0xB3, + 0x6D, 0x6F, 0x79, 0xBB, 0x74, 0x65, 0x7F, 0x19, 0x66, 0x2F, 0xDA, 0xAD, 0xA4, 0x97, 0x2B, 0x15, + 0x6D, 0x17, 0x6E, 0x50, 0x34, 0x6B, 0x76, 0x92, 0xE3, 0x0E, 0x72, 0xF8, 0x7A, 0xF9, 0x53, 0xFA, + 0xD4, 0x92, 0x57, 0xE9, 0x66, 0xAF, 0xF7, 0xF4, 0xE1, 0x3D, 0xC2, 0xE0, 0x7B, 0x78, 0x8C, 0x50, + 0xCC, 0x14, 0x0D, 0x06, 0x8B, 0x87, 0x3A, 0xF6, 0x5D, 0xBD, 0x15, 0x11, 0x77, 0xF9, 0xB4, 0x4A, + 0x3D, 0x33, 0x2A, 0x4E, 0xBE, 0xC7, 0x54, 0xCF, 0x71, 0x20, 0x4C, 0xC1, 0xFE, 0xB0, 0x47, 0x1B, + 0x2C, 0x1F, 0x39, 0x20, 0x9A, 0xC8, 0x56, 0xB4, 0xB7, 0x14, 0x59, 0xDD, 0x65, 0xDA, 0x08, 0x2C, + 0xC4, 0x23, 0xCB, 0x86, 0xD6, 0x66, 0xF8, 0x39, 0x96, 0x92, 0x8A, 0xE9, 0xCF, 0x93, 0x11, 0xA4, + 0x76, 0x5D, 0x0C, 0x0B, 0xAF, 0x2A, 0xDB, 0x1F, 0xBC, 0xDC, 0xCF, 0xE4, 0x72, 0x65, 0x02, 0xEF, + 0x50, 0xAB, 0x5D, 0xEB, 0x3F, 0xB0, 0x33, 0x11, 0xA2, 0x47, 0x5A, 0xB7, 0x76, 0x7E, 0x16, 0x02, + 0x15, 0x7F, 0x1E, 0x4A, 0x24, 0xA7, 0x48, 0x97, 0x9F, 0x89, 0x7F, 0xF7, 0xB4, 0x7F, 0x3C, 0x0E, + 0x17, 0x9D, 0xE4, 0xE3, 0x03, 0x28, 0x4F, 0xDD, 0x37, 0x85, 0x52, 0x73, 0x74, 0x3E, 0xCD, 0x77, + 0x4F, 0x69, 0x48, 0x72, 0x5B, 0x71, 0xA9, 0xB8, 0x5E, 0xDD, 0x0C, 0xF5, 0x36, 0xEF, 0xEA, 0xA7, + 0x96, 0x84, 0x07, 0xD4, 0xB6, 0xC9, 0xFC, 0x2A, 0xD5, 0xD6, 0x7E, 0xE5, 0xB7, 0x1C, 0xAB, 0x88, + 0xB4, 0x3A, 0xEC, 0x4C, 0xB1, 0xBD, 0x15, 0x06, 0xFA, 0xA9, 0x88, 0x2D, 0x1B, 0x23, 0x4E, 0x5F, + 0x57, 0x52, 0xF4, 0x67, 0x8F, 0x4F, 0xD1, 0xF9, 0x45, 0xE0, 0xE9, 0xD1, 0x1E, 0xFA, 0x9A, 0xC3, + 0xB9, 0x01, 0x1A, 0x92, 0xBE, 0xAC, 0xE7, 0x30, 0x7F, 0xC9, 0x5E, 0x8E, 0xEE, 0x81, 0x6B, 0xD3, + 0x03, 0x25, 0x31, 0xDF, 0xBC, 0x09, 0x70, 0x78, 0xEE, 0xB2, 0xFA, 0x4C, 0xA7, 0x9B, 0xE9, 0xDD, + 0x8F, 0xBD, 0xE8, 0x6D, 0x24, 0x6D, 0xDB, 0x38, 0x36, 0xEF, 0x6C, 0xFE, 0x78, 0xFE, 0x21, 0x52, + 0x1F, 0xF1, 0x3A, 0x85, 0x0C, 0x84, 0x99, 0xFB, 0x1E, 0x9F, 0x06, 0xDE, 0xF6, 0x6D, 0x35, 0xB1, + 0x51, 0x06, 0x48, 0xA3, 0xD6, 0xF2, 0x65, 0x6E, 0x15, 0x3C, 0x7F, 0x66, 0xCC, 0xC8, 0x81, 0xB5, + 0xDF, 0x9F, 0x95, 0x18, 0x25, 0xB5, 0xBE, 0x28, 0x75, 0x76, 0x94, 0xC1, 0xA1, 0x68, 0xEB, 0xA1, + 0xC7, 0xF5, 0xC0, 0x1A, 0x71, 0x99, 0xEF, 0x36, 0x70, 0x45, 0x9E, 0x40, 0xF2, 0x9D, 0xE8, 0x0D, + 0x6A, 0xC4, 0x91, 0x62, 0x7B, 0x70, 0x76, 0x3D, 0x8C, 0xB3, 0x58, 0xB3, 0x1E, 0x45, 0x05, 0x85, + 0x8C, 0xBD, 0xF9, 0xE5, 0x70, 0xCA, 0x76, 0x42, 0xDB, 0x9D, 0xCF, 0xA4, 0x6A, 0x17, 0x30, 0xAD, + 0x86, 0x03, 0xF0, 0x3B, 0xF5, 0x68, 0xCD, 0x46, 0xED, 0x4A, 0xBD, 0x9B, 0xF7, 0x86, 0xED, 0xE2, + 0xCB, 0x21, 0xA2, 0x8F, 0x9A, 0x47, 0xBB, 0x64, 0x7F, 0xB2, 0xA3, 0x52, 0x81, 0x59, 0xE9, 0x83, + 0xF6, 0xE4, 0x80, 0xB2, 0x7C, 0xB3, 0x37, 0x9E, 0xE6, 0x2C, 0x1E, 0x4E, 0xE0, 0x72, 0xC8, 0x32, + 0x76, 0xF7, 0xB3, 0x11, 0x75, 0x0A, 0x1B, 0xAC, 0xDE, 0x0E, 0x69, 0x1B, 0xF9, 0x8A, 0x76, 0x72, + 0xE2, 0x19, 0x04, 0x2E, 0x1B, 0xC8, 0xB3, 0x6F, 0xB1, 0xB2, 0xE1, 0xA0, 0xA9, 0x3F, 0x90, 0x48, + 0x9D, 0x45, 0xC8, 0x5A, 0x06, 0x0A, 0x3A, 0x87, 0xA2, 0xD3, 0xEB, 0x20, 0x53, 0x4B, 0x1B, 0x89, + 0x1E, 0x8E, 0x6A, 0xCA, 0x09, 0x19, 0x83, 0x0E, 0x30, 0xE1, 0x03, 0x59, 0x77, 0x4A, 0xE0, 0xAC, + 0xF3, 0xC0, 0x2D, 0x6E, 0x06, 0x59, 0x72, 0xB9, 0x53, 0x05, 0x70, 0xA9, 0xDC, 0xDC, 0x76, 0x8C, + 0x17, 0x2B, 0xE6, 0x25, 0x92, 0xC8, 0x36, 0xFB, 0xB4, 0x6E, 0xA4, 0x10, 0x02, 0x90, 0x5E, 0xA8, + 0x12, 0xAD, 0xF9, 0xDD, 0x27, 0xC0, 0x5E, 0x40, 0xAC, 0xB0, 0xA2, 0x09, 0x41, 0x9B, 0x5B, 0x1A, + 0x85, 0x06, 0xA6, 0x63, 0x61, 0xCC, 0x3B, 0xAE, 0xB3, 0xD0, 0x54, 0xA0, 0xE6, 0x8E, 0xE8, 0x8A, + 0x56, 0xFC, 0xBE, 0x40, 0x99, 0x33, 0x8F, 0x0F, 0x2C, 0xBF, 0x97, 0x96, 0xFD, 0x93, 0xF4, 0xDD, + 0x2D, 0x28, 0x5B, 0x81, 0x2A, 0x7B, 0x4D, 0xA6, 0x9F, 0xF8, 0x63, 0xC2, 0xC1, 0xA9, 0x06, 0x3E, + 0xF9, 0x8B, 0x0F, 0xE2, 0xCF, 0x13, 0x22, 0x49, 0x81, 0x36, 0xC2, 0x09, 0x62, 0x21, 0xBD, 0x21, + 0x41, 0xE9, 0xE6, 0xD3, 0x75, 0x79, 0x36, 0x53, 0xD4, 0xD5, 0xA8, 0x17, 0xF8, 0x7B, 0xEF, 0x04, + 0xBE, 0x41, 0x57, 0xEB, 0x16, 0xD7, 0x99, 0x83, 0xFE, 0xD1, 0xA7, 0xF2, 0xE6, 0x60, 0x00, 0x00, + 0xCC, 0xD0, 0x30, 0x00, 0x03, 0x38, 0x14, 0xA9, 0xAD, 0x5A, 0x52, 0x62, 0x18, 0xAF, 0xA4, 0xC3, + 0x09, 0xC0, 0xCE, 0x06, 0x5E, 0xE1, 0xA0, 0x9D, 0xF5, 0x73, 0x36, 0x20, 0xEA, 0x1D, 0xFD, 0x00, + 0xA5, 0x02, 0xCB, 0x4C, 0x1A, 0xCB, 0x43, 0xB5, 0x89, 0xD7, 0x8E, 0x0A, 0x04, 0x9D, 0x4C, 0x9E, + 0xBE, 0xBC, 0xC4, 0x07, 0x79, 0xCD, 0x71, 0xE8, 0xAA, 0x81, 0x35, 0xF2, 0x28, 0xAC, 0x10, 0x57, + 0x19, 0xA5, 0xFE, 0xFC, 0x82, 0xF2, 0x0B, 0x48, 0x34, 0x89, 0xB3, 0xDE, 0x9D, 0xD0, 0x96, 0x9B, + 0x77, 0xBD, 0xB7, 0xDE, 0xBA, 0x3F, 0x08, 0x02, 0x13, 0x3B, 0xAD, 0x9B, 0x1D, 0x64, 0xAD, 0xE9, + 0x05, 0xCD, 0x11, 0x5F, 0xDC, 0xE7, 0xA3, 0xCA, 0x19, 0xD7, 0x1B, 0x9C, 0xCB, 0x20, 0x3A, 0xC3, + 0xEB, 0xEF, 0x1A, 0xB4, 0x6B, 0xB9, 0x12, 0x65, 0xB4, 0x22, 0x85, 0x61, 0xD2, 0x61, 0x83, 0x23, + 0x86, 0x9C, 0xB1, 0x45, 0xAD, 0x8F, 0x15, 0x2D, 0xCA, 0x0B, 0xDE, 0x15, 0xFE, 0x91, 0x03, 0x96, + 0x8F, 0x35, 0xB7, 0x1A, 0xB8, 0xFC, 0xE4, 0x7F, 0x4C, 0xE9, 0x6C, 0xAE, 0x7E, 0x27, 0xED, 0x15, + 0x9A, 0x47, 0x0C, 0xEE, 0x13, 0xC5, 0xCA, 0xF8, 0xDD, 0x3A, 0xC8, 0x44, 0xC4, 0xF7, 0x39, 0xEE, + 0xEF, 0xBD, 0xAD, 0x52, 0x24, 0xFB, 0x43, 0xF4, 0x37, 0x3A, 0xD4, 0x2E, 0xF3, 0xCB, 0x80, 0xF4, + 0xC2, 0x2A, 0x69, 0xA4, 0x98, 0x8F, 0x94, 0xF5, 0x59, 0x5F, 0x81, 0xCF, 0xE4, 0x10, 0x0A, 0x95, + 0x7F, 0x50, 0x5B, 0x90, 0x86, 0x3F, 0xC9, 0xA5, 0x2C, 0x5D, 0x87, 0x77, 0xCE, 0xC9, 0x34, 0x0B, + 0x46, 0xC5, 0xE7, 0xD7, 0x9F, 0x6C, 0xCE, 0x73, 0xE2, 0xEA, 0x70, 0x9E, 0xDF, 0x58, 0x2A, 0x10, + 0xF7, 0x62, 0x86, 0x67, 0xC1, 0xDD, 0xAC, 0x6E, 0xD1, 0x2C, 0x14, 0x62, 0x58, 0xB9, 0xA3, 0x79, + 0x17, 0xF5, 0xE2, 0xA3, 0x87, 0x2D, 0x6A, 0x19, 0xE1, 0xD3, 0xE6, 0x0A, 0x69, 0xB0, 0x10, 0x7A, + 0x7F, 0xD4, 0xE9, 0x23, 0xB4, 0x6F, 0xD1, 0x09, 0x64, 0x6F, 0x61, 0x16, 0x3A, 0xB1, 0xB5, 0xFF, + 0x30, 0xBD, 0xA9, 0x9C, 0xA1, 0x8E, 0xC3, 0x4E, 0x6C, 0xD2, 0x7C, 0x74, 0xA0, 0x61, 0xC4, 0x28, + 0x14, 0x15, 0xA4, 0x45, 0xE9, 0x50, 0x31, 0x9C, 0x26, 0xD1, 0xC9, 0xFA, 0x93, 0xFE, 0x20, 0x28, + 0x03, 0x00, 0x15, 0x50, 0x5A, 0xFA, 0xE0, 0x61, 0x0A, 0x4E, 0x58, 0xEF, 0x2E, 0xB5, 0xF4, 0x28, + 0xE3, 0x74, 0x3B, 0x28, 0x3F, 0x43, 0x74, 0x60, 0x6C, 0x12, 0xE4, 0x40, 0x25, 0x0C, 0xDF, 0x1C, + 0xB9, 0xD5, 0xF1, 0x38, 0xED, 0x2A, 0xB7, 0x7E, 0x11, 0x5C, 0x35, 0x63, 0xC0, 0x58, 0x52, 0x2A, + 0xCA, 0xBD, 0x39, 0xBC, 0xDC, 0x37, 0xA0, 0xD9, 0x39, 0xC6, 0xA7, 0x0F, 0xAB, 0xC4, 0x69, 0xBF, + 0x90, 0x14, 0x49, 0x98, 0x93, 0x21, 0x81, 0x2D, 0x6A, 0xCE, 0x93, 0xC4, 0xBA, 0x4D, 0x5B, 0x83, + 0xC6, 0xB6, 0x5B, 0xD2, 0xEF, 0xF6, 0x71, 0xFA, 0xF5, 0x72, 0xE2, 0xF9, 0xCA, 0xD9, 0x1A, 0xC2, + 0x54, 0x6F, 0xBE, 0x2C, 0x83, 0x49, 0xA6, 0x5B, 0xD9, 0xF0, 0x09, 0x59, 0x0E, 0x16, 0xB7, 0x3C, + 0x8C, 0xBE, 0xCD, 0x3D, 0x1B, 0x9B, 0xB9, 0x30, 0x8C, 0xF5, 0xE2, 0x7D, 0x2F, 0xF0, 0x5E, 0x7B, + 0x25, 0x96, 0xD4, 0xDB, 0x50, 0x85, 0x47, 0x4C, 0xA4, 0x25, 0x90, 0x8D, 0xE8, 0xEA, 0x56, 0x83, + 0xDD, 0x16, 0x79, 0x9E, 0x12, 0x2B, 0x4D, 0x3A, 0x64, 0x06, 0x03, 0xE7, 0x9C, 0x73, 0x70, 0xB6, + 0x3A, 0xE1, 0xDB, 0x8C, 0x9A, 0x6C, 0x35, 0x81, 0x04, 0x90, 0x0E, 0xAC, 0xBF, 0xF8, 0x0F, 0xFB, + 0xC7, 0x2D, 0xAC, 0x60, 0xFB, 0xB8, 0xD0, 0x08, 0xE2, 0x0E, 0xCA, 0x93, 0x81, 0x82, 0xAD, 0x62, + 0x5C, 0x48, 0x8D, 0x1F, 0x23, 0x60, 0x46, 0xC7, 0x38, 0x30, 0x4C, 0x8F, 0x15, 0x9C, 0x9C, 0x79, + 0x11, 0x40, 0xCC, 0x7A, 0x9B, 0xB6, 0x96, 0xE1, 0x38, 0xD0, 0x57, 0xEF, 0x7C, 0xA6, 0x7D, 0xFE, + 0x9F, 0xBA, 0x4B, 0xA6, 0xBF, 0x9A, 0x89, 0x6F, 0x20, 0x7C, 0x35, 0x98, 0x86, 0x02, 0x7E, 0x85, + 0x8F, 0x81, 0x55, 0x65, 0x36, 0xA5, 0x3B, 0xF7, 0x30, 0x0C, 0x66, 0x14, 0x2C, 0x22, 0xC4, 0x6E, + 0x9D, 0xE4, 0xD6, 0xFE, 0x23, 0x4B, 0x76, 0x7D, 0xBD, 0xDC, 0xE3, 0xCA, 0xD4, 0x73, 0x4C, 0xD1, + 0x80, 0xD0, 0x81, 0x59, 0x44, 0x6C, 0x10, 0x93, 0x4F, 0x05, 0x78, 0x41, 0x8C, 0x24, 0x90, 0x5B, + 0x0C, 0xF7, 0xC5, 0xD3, 0x2C, 0x02, 0xBA, 0xE1, 0x43, 0x48, 0x04, 0x61, 0x2F, 0xF9, 0xFB, 0xD1, + 0x07, 0xDA, 0x57, 0x75, 0xA5, 0xCD, 0xF7, 0x36, 0x58, 0x3C, 0x35, 0x88, 0x4A, 0xB0, 0xF8, 0x80, + 0xA1, 0x16, 0x9D, 0x53, 0x46, 0x18, 0x00, 0x67, 0xFE, 0xB2, 0x30, 0x37, 0x7E, 0xF3, 0x49, 0x0B, + 0xAB, 0x4D, 0x86, 0xEA, 0xE4, 0x3C, 0x77, 0xAE, 0xCA, 0xC1, 0x5D, 0x59, 0xD1, 0xC0, 0x7A, 0x94, + 0x81, 0x54, 0xC2, 0xAB, 0x0A, 0x02, 0xC3, 0xD5, 0xBA, 0x5C, 0xCE, 0x4E, 0x64, 0xA3, 0x77, 0x6B, + 0xDC, 0xFE, 0x38, 0x0C, 0x0A, 0xBC, 0x1E, 0xB3, 0x64, 0x60, 0x33, 0x77, 0x0F, 0x58, 0xFC, 0xB3, + 0xC0, 0x5D, 0xF9, 0x64, 0x45, 0xF4, 0x03, 0xE4, 0xFE, 0x24, 0x62, 0x34, 0x69, 0x57, 0x1D, 0xB9, + 0x91, 0xC6, 0x0D, 0x9F, 0xE4, 0x88, 0x4E, 0xC1, 0xF1, 0x55, 0x5F, 0x0F, 0xDC, 0xC5, 0x7A, 0xFA, + 0x06, 0x87, 0x36, 0x17, 0xB1, 0x67, 0x65, 0x63, 0xDA, 0xB9, 0x44, 0xE9, 0xD0, 0x71, 0x9C, 0x1F, + 0xF4, 0xAA, 0x4D, 0xE3, 0x00, 0xB8, 0x3C, 0x3A, 0xFA, 0xAE, 0xFC, 0xB1, 0xB9, 0x6B, 0xC9, 0x74, + 0xE3, 0xC2, 0x25, 0x97, 0x5B, 0x4D, 0x20, 0x2A, 0x69, 0x64, 0x4A, 0x15, 0xC6, 0x9F, 0xF7, 0x28, + 0x32, 0xDE, 0x78, 0x4F, 0x30, 0x08, 0x40, 0xB1, 0x73, 0xE0, 0x51, 0xB6, 0x0D, 0xF0, 0xC7, 0xE7, + 0xE6, 0x15, 0xBA, 0xD2, 0x2D, 0xF9, 0x1D, 0x0C, 0x50, 0xF9, 0x73, 0x60, 0x7C, 0xDB, 0x06, 0x79, + 0x3B, 0x05, 0x54, 0x0F, 0xA0, 0xDD, 0x90, 0xDC, 0xCE, 0x17, 0x49, 0xF5, 0x07, 0xD7, 0xAD, 0x2A, + 0x9D, 0x7E, 0x8F, 0x6A, 0x38, 0x50, 0xA6, 0x04, 0xCC, 0xB2, 0x40, 0xCF, 0x7E, 0xD1, 0xE0, 0xD0, + 0x8D, 0x3B, 0xF2, 0x5A, 0xBA, 0xBA, 0xB8, 0x9D, 0xC4, 0xE4, 0x83, 0x53, 0x4C, 0x4B, 0xA2, 0x0A, + 0x07, 0x1B, 0x46, 0xDE, 0x67, 0xA4, 0xE3, 0xD1, 0x18, 0x16, 0x84, 0x4E, 0x78, 0xF0, 0xDC, 0xB6, + 0x55, 0x87, 0xE3, 0x76, 0x5E, 0x4A, 0xBE, 0xF6, 0xB9, 0x41, 0x5F, 0x82, 0xBB, 0xC8, 0x82, 0xCC, + 0xAA, 0xFD, 0x1B, 0xA4, 0x82, 0x0E, 0x25, 0x3E, 0x44, 0x8F, 0x9D, 0x89, 0xDC, 0x9F, 0xEA, 0x9F, + 0x6E, 0xE6, 0xB3, 0xE5, 0x72, 0x46, 0xBE, 0xB0, 0x7E, 0x00, 0xD8, 0x91, 0xB6, 0x31, 0x17, 0x7E, + 0xFE, 0xD5, 0x25, 0x94, 0x25, 0xA6, 0xAA, 0x46, 0x4B, 0x91, 0xAA, 0x74, 0x3B, 0x67, 0x72, 0xA1, + 0x92, 0xA8, 0x8D, 0x5C, 0xD4, 0x29, 0xBF, 0x8D, 0xFB, 0x41, 0x0C, 0x4B, 0xCE, 0x44, 0x23, 0xF7, + 0x73, 0xE9, 0x1E, 0x40, 0x7B, 0xFC, 0x42, 0x31, 0x1C, 0xA7, 0x48, 0x93, 0x94, 0x81, 0xA3, 0x0C, + 0x6B, 0xE2, 0x60, 0x41, 0xE0, 0x88, 0x79, 0xD4, 0x69, 0x44, 0xDF, 0x5C, 0x5F, 0xBB, 0x40, 0x26, + 0x65, 0x10, 0x3B, 0xC5, 0x14, 0x72, 0x16, 0xD1, 0x06, 0x4F, 0x17, 0xCD, 0x70, 0x85, 0xD9, 0xEB, + 0x3D, 0x64, 0xAA, 0xF0, 0xDB, 0xA0, 0x5A, 0xD6, 0x8C, 0xA3, 0x97, 0xC9, 0xA5, 0x29, 0xB1, 0x0F, + 0x6C, 0x93, 0x2D, 0x82, 0x3A, 0xB0, 0x41, 0x05, 0xF2, 0xF7, 0x5C, 0x3D, 0x44, 0x16, 0x5C, 0xAB, + 0xFC, 0xE1, 0x9E, 0x64, 0x89, 0xC5, 0x6E, 0x8B, 0x5B, 0xE0, 0x5F, 0x88, 0xFC, 0x5D, 0x14, 0x9E, + 0x35, 0x81, 0xCA, 0x01, 0xD4, 0x98, 0x8A, 0xB1, 0x71, 0x00, 0xF7, 0x27, 0xC6, 0x8C, 0x6D, 0x33, + 0x0D, 0x0C, 0x24, 0xA2, 0x9E, 0xC5, 0x9F, 0x02, 0xE0, 0x2A, 0x32, 0xD0, 0xDB, 0x80, 0x28, 0xE1, + 0xA1, 0xC6, 0xD0, 0xC0, 0x10, 0x81, 0x2A, 0x03, 0xE9, 0xC0, 0xF5, 0xD7, 0xDF, 0x2F, 0xB7, 0xCE, + 0x2C, 0xCF, 0x09, 0x72, 0x1E, 0x35, 0x3F, 0xB5, 0xAD, 0x7B, 0xAB, 0x89, 0x84, 0xE2, 0x83, 0x24, + 0x2C, 0xDB, 0x5D, 0x1D, 0x1B, 0x77, 0x05, 0x0A, 0xFE, 0x08, 0x06, 0x8A, 0x87, 0x55, 0x9E, 0xBC, + 0xD6, 0x08, 0x71, 0xCC, 0x05, 0xD1, 0x6E, 0x6D, 0x9F, 0x8B, 0xEE, 0x29, 0x59, 0x81, 0x73, 0x0B, + 0xC1, 0xFA, 0x4C, 0xCE, 0x30, 0x78, 0xCF, 0xE2, 0xD9, 0xFB, 0x19, 0xC4, 0x4D, 0x3D, 0x11, 0x71, + 0x84, 0xC9, 0x73, 0x4B, 0x4B, 0x17, 0x91, 0x7F, 0xDE, 0x6F, 0x00, 0x2E, 0x25, 0x09, 0x87, 0xD6, + 0xDF, 0x62, 0x15, 0x58, 0xF4, 0xAF, 0x8B, 0xBB, 0x0D, 0xDD, 0xA7, 0x50, 0xE3, 0x56, 0xED, 0x48, + 0xA1, 0x2A, 0x5C, 0x5F, 0x90, 0x0E, 0x2D, 0xF4, 0xED, 0xF1, 0x8D, 0x08, 0xBC, 0x69, 0xFE, 0x59, + 0xB3, 0x04, 0x7A, 0x7E, 0xEC, 0xEC, 0xFF, 0xD3, 0x58, 0x33, 0x45, 0x06, 0x93, 0x58, 0x48, 0x10, + 0x0F, 0x7A, 0xC6, 0x59, 0xE4, 0x04, 0xE9, 0x17, 0x49, 0x58, 0xF5, 0x71, 0xBA, 0x96, 0x34, 0x46, + 0xB1, 0x6E, 0x11, 0xF4, 0xF4, 0xFB, 0xDF, 0xC7, 0x60, 0x8C, 0x21, 0xC5, 0x77, 0x68, 0x2F, 0x96, + 0xEA, 0x75, 0x9A, 0xFC, 0x27, 0xD7, 0xEC, 0xC7, 0x78, 0x15, 0xD7, 0x31, 0xEF, 0x31, 0x8F, 0x82, + 0x02, 0x41, 0x64, 0x11, 0xE3, 0x0A, 0xA1, 0xB7, 0x7B, 0x27, 0x2C, 0x1F, 0x0E, 0x9F, 0x1F, 0x07, + 0xF0, 0xEC, 0x9B, 0xDF, 0x75, 0x0D, 0xF6, 0x79, 0x79, 0x73, 0xDB, 0xBD, 0x70, 0xE2, 0x8B, 0xC2, + 0x20, 0xE4, 0x89, 0xAE, 0x4F, 0x41, 0x89, 0x5D, 0x8A, 0x34, 0x8D, 0xEB, 0x54, 0x92, 0xE5, 0x02, + 0x53, 0x86, 0xBD, 0x4A, 0x56, 0xC1, 0x9E, 0xCE, 0x74, 0x82, 0xA8, 0x98, 0x7B, 0xD0, 0x96, 0x17, + 0x2B, 0x08, 0xAA, 0xE1, 0x05, 0x6D, 0x4B, 0xBB, 0x94, 0x39, 0xE4, 0x1A, 0x30, 0xA4, 0x44, 0x7B, + 0x15, 0xEB, 0x0F, 0x4A, 0x49, 0xC9, 0xCC, 0x32, 0xFA, 0xF2, 0x8C, 0x5A, 0x45, 0xF5, 0x70, 0xC2, + 0x70, 0x00, 0x79, 0x71, 0x3C, 0xF9, 0xE0, 0x32, 0xCA, 0x8E, 0x6A, 0x3B, 0x0F, 0x21, 0x59, 0x32, + 0x6F, 0x81, 0x6C, 0x7C, 0xAB, 0x5B, 0xE3, 0x6D, 0x59, 0x35, 0xAC, 0x6D, 0xE4, 0xB4, 0x4A, 0xD7, + 0xB3, 0x14, 0xD8, 0xA0, 0x4E, 0xBF, 0x05, 0xFE, 0x36, 0xF2, 0x25, 0xA5, 0xCB, 0x9E, 0xFF, 0xA3, + 0xA9, 0xF2, 0x1C, 0xE7, 0x56, 0x27, 0x45, 0xFE, 0xF9, 0x29, 0xDD, 0x6B, 0xC2, 0x13, 0xC9, 0x55, + 0x30, 0x40, 0x38, 0xFD, 0x56, 0x84, 0xAC, 0xA9, 0x95, 0xDB, 0xAA, 0x92, 0x67, 0x5A, 0x26, 0x07, + 0xD2, 0x44, 0xED, 0x2B, 0xF4, 0x34, 0xE2, 0x6E, 0x17, 0x0F, 0x53, 0xB0, 0xD4, 0x28, 0x4E, 0x37, + 0xB7, 0xB8, 0x6F, 0x82, 0xB3, 0x5F, 0x38, 0xB3, 0x15, 0x59, 0x76, 0xE4, 0x81, 0xDC, 0x52, 0xB3, + 0xF4, 0xED, 0x5F, 0xF6, 0x17, 0x08, 0x64, 0x12, 0x41, 0xB8, 0xAF, 0x72, 0xC1, 0x31, 0xEF, 0x75, + 0x02, 0xA2, 0x70, 0x9E, 0x60, 0x7A, 0x5A, 0xD8, 0xB0, 0xB9, 0xA4, 0xA8, 0x0F, 0x8E, 0x61, 0x09, + 0x42, 0xA3, 0x11, 0x10, 0x46, 0x62, 0x2B, 0x8B, 0x5E, 0x27, 0x05, 0xC6, 0x8C, 0x9D, 0x49, 0x91, + 0x26, 0x06, 0x67, 0xEF, 0x6C, 0xDA, 0x78, 0x64, 0x1A, 0x74, 0xBA, 0xC4, 0x95, 0x50, 0xFE, 0xE0, + 0x61, 0xBA, 0xF1, 0x05, 0xFD, 0x39, 0x88, 0xDD, 0x11, 0x40, 0xAD, 0xA2, 0xC7, 0x49, 0xEA, 0x4C, + 0xE3, 0xF3, 0x65, 0xF9, 0xB1, 0x57, 0x37, 0x3B, 0x05, 0x20, 0xD8, 0xD7, 0x75, 0x61, 0x65, 0x71, + 0x5C, 0xB3, 0x24, 0xF1, 0x90, 0x92, 0x44, 0x00, 0x93, 0xC4, 0x16, 0x04, 0x66, 0x88, 0x30, 0x10, + 0xAC, 0xEA, 0x9D, 0x20, 0x06, 0xB7, 0x12, 0x3B, 0xA6, 0x2C, 0x3F, 0x0C, 0x30, 0xE9, 0xA7, 0x69, + 0xD6, 0xF7, 0xEE, 0x27, 0xA9, 0x20, 0xFF, 0xD6, 0x2D, 0x3F, 0x0D, 0xD6, 0xEC, 0xDE, 0x1C, 0xA0, + 0x70, 0xFA, 0x7A, 0x75, 0x19, 0xA6, 0x83, 0x85, 0xC3, 0x6B, 0x6E, 0xF7, 0x30, 0xA6, 0x54, 0x32, + 0x0A, 0xC7, 0xC1, 0x0E, 0x2C, 0xD2, 0x17, 0xB3, 0x97, 0xCE, 0x0C, 0x37, 0xDD, 0x91, 0xFF, 0xE8, + 0x83, 0x51, 0x94, 0xD6, 0x65, 0x69, 0x1B, 0xD4, 0x44, 0x09, 0x25, 0x99, 0xFB, 0x9D, 0x78, 0xD5, + 0x8D, 0x3D, 0xB7, 0xBD, 0x07, 0x23, 0xB1, 0xDF, 0xB1, 0xFF, 0x86, 0x29, 0xA1, 0xF4, 0x8D, 0x6C, + 0xBF, 0xE3, 0xA6, 0x25, 0x2A, 0xCE, 0xD8, 0xE5, 0x79, 0x81, 0xEE, 0x98, 0x9E, 0xCE, 0x0A, 0xE7, + 0x53, 0x12, 0xD0, 0x92, 0x0F, 0xA6, 0xF8, 0xCF, 0xEA, 0x4D, 0x8C, 0x7B, 0x18, 0xA7, 0x53, 0xED, + 0x63, 0xB2, 0x5B, 0x2D, 0x9E, 0x65, 0x5C, 0x0A, 0x7C, 0x7B, 0xB9, 0x8E, 0xD0, 0x73, 0x5F, 0x29, + 0xDC, 0xD5, 0xFB, 0x12, 0xE7, 0x18, 0xDD, 0x33, 0x74, 0x4C, 0x95, 0x2A, 0xDB, 0xA0, 0xE2, 0xC6, + 0x2B, 0x6A, 0xBF, 0xE1, 0x84, 0xA3, 0x24, 0xE0, 0xF4, 0x33, 0x75, 0x4B, 0xA9, 0x82, 0xBD, 0xCF, + 0xD7, 0x12, 0xF6, 0x0F, 0x10, 0x1E, 0xF5, 0x64, 0xDE, 0xA3, 0x2C, 0x6D, 0x10, 0xCA, 0x4B, 0x1C, + 0x9F, 0x1C, 0x41, 0xE5, 0xCF, 0x47, 0x40, 0x20, 0xA6, 0x94, 0xA7, 0x36, 0xDD, 0x60, 0xE6, 0x47, + 0xFC, 0x86, 0xA6, 0x0C, 0x79, 0x66, 0x8D, 0x4D, 0xBA, 0x15, 0x17, 0xF3, 0x96, 0x44, 0x76, 0x6E, + 0x5A, 0x61, 0xC8, 0x5A, 0x5C, 0x25, 0x4A, 0xEC, 0x1D, 0xCE, 0x3F, 0x2F, 0x8D, 0x4D, 0xC2, 0xB2, + 0x62, 0xE4, 0xD7, 0xF8, 0x41, 0x4B, 0x43, 0xAB, 0x1A, 0x22, 0x4E, 0xB3, 0xBC, 0xAA, 0xCE, 0x99, + 0x0B, 0x8D, 0x11, 0x19, 0x12, 0x9D, 0x0E, 0xBE, 0x2C, 0x94, 0x3F, 0xB1, 0xBE, 0x7E, 0xD2, 0xE1, + 0xC9, 0xBE, 0x33, 0x3D, 0xCB, 0xCD, 0x56, 0xCD, 0xB8, 0xB4, 0x5C, 0xD4, 0xA0, 0x3B, 0x7C, 0x3C, + 0x2C, 0x8B, 0x8E, 0x43, 0x3C, 0x15, 0x9E, 0xF4, 0xF2, 0xB6, 0x26, 0xA1, 0xB7, 0xBE, 0xC9, 0x7F, + 0x43, 0x8A, 0xFA, 0x0E, 0x2F, 0x49, 0x7C, 0xCF, 0x2E, 0x98, 0x5E, 0x76, 0x71, 0xC6, 0x1A, 0x2D, + 0xA8, 0xDB, 0x57, 0x96, 0x10, 0xFE, 0xD5, 0x0C, 0xBB, 0x15, 0x5D, 0x04, 0x0B, 0x79, 0x5D, 0x3E, + 0x6B, 0xC5, 0x1A, 0xD9, 0x0B, 0xAD, 0x0C, 0x3D, 0x3E, 0x7E, 0x57, 0x98, 0xDE, 0x23, 0x36, 0x5F, + 0x92, 0xBA, 0x31, 0x28, 0xE8, 0x3B, 0xBE, 0x7F, 0x6A, 0xA6, 0x16, 0x2C, 0x55, 0x2A, 0xBC, 0x2E, + 0x5D, 0xF4, 0xCB, 0x7B, 0x21, 0x71, 0x77, 0x15, 0xEF, 0xAC, 0xE4, 0x28, 0x3F, 0x75, 0x81, 0xD5, + 0x88, 0xF0, 0x37, 0x78, 0xBD, 0xB3, 0x26, 0x26, 0x64, 0x91, 0x2A, 0x8D, 0x20, 0xFE, 0x20, 0xA7, + 0x23, 0xB6, 0xA4, 0xFA, 0xA7, 0x09, 0x41, 0xB2, 0x66, 0x2F, 0x9D, 0xE4, 0xFD, 0x29, 0x69, 0x45, + 0x03, 0x0C, 0x86, 0x3E, 0x3A, 0x95, 0x93, 0x97, 0x31, 0x4C, 0x39, 0x61, 0xB2, 0xDF, 0x01, 0xDB, + 0x79, 0xA6, 0x64, 0xC9, 0x59, 0x7D, 0x92, 0x02, 0x46, 0x76, 0x58, 0x17, 0x44, 0xC3, 0x8C, 0x68, + 0x5B, 0xD3, 0x1E, 0x7A, 0x0F, 0x48, 0x7D, 0x03, 0xF5, 0x96, 0x27, 0xB3, 0xC0, 0x61, 0x20, 0x12, + 0xDC, 0x97, 0x9F, 0xEC, 0x7B, 0xA6, 0x39, 0x10, 0x44, 0x8B, 0x61, 0xE5, 0xF5, 0xDE, 0x53, 0x53, + 0x33, 0x92, 0xBF, 0x22, 0x72, 0x28, 0x54, 0x4B, 0x92, 0x38, 0xA3, 0x5F, 0x08, 0x0C, 0xB6, 0x8D, + 0xF3, 0x14, 0x87, 0xCF, 0xB6, 0xF9, 0x5D, 0x8D, 0x47, 0x21, 0xB5, 0xA5, 0x6F, 0x9C, 0x82, 0xED, + 0xC7, 0x7B, 0xAD, 0xCD, 0x7D, 0xE3, 0x68, 0xD8, 0x7B, 0xA4, 0x8D, 0x27, 0xB5, 0x16, 0x3B, 0xA0, + 0x78, 0x43, 0x81, 0xEF, 0xB7, 0x42, 0xA2, 0xFC, 0xBB, 0x47, 0x0A, 0x75, 0xB6, 0xE5, 0x16, 0x6D, + 0xD5, 0x45, 0x41, 0x0B, 0x66, 0x82, 0xBB, 0x8C, 0xBA, 0x90, 0xCA, 0x0B, 0x25, 0x0A, 0x8C, 0xA7, + 0x62, 0x05, 0x03, 0x3B, 0xD3, 0xBF, 0xF3, 0x54, 0x94, 0x0F, 0x3A, 0x50, 0x0D, 0xEF, 0x70, 0x23, + 0xF6, 0x23, 0x27, 0xE3, 0xD7, 0xA1, 0xAC, 0x40, 0xE4, 0x3F, 0xCD, 0x0E, 0x27, 0xCA, 0x2D, 0xE0, + 0x47, 0x16, 0x78, 0xDE, 0xA9, 0x07, 0x1D, 0x2D, 0x89, 0xC3, 0xE7, 0x0C, 0x4B, 0x6C, 0x10, 0x5D, + 0xDF, 0x37, 0x63, 0xE7, 0xB5, 0x06, 0xEC, 0x03, 0x6E, 0x02, 0x80, 0x24, 0x69, 0xDA, 0x20, 0xD7, + 0x7D, 0x4C, 0x49, 0xF6, 0x14, 0x21, 0x63, 0xC9, 0x60, 0x50, 0x35, 0x83, 0x9D, 0xFC, 0x71, 0x37, + 0xCF, 0x06, 0xF6, 0x98, 0x4A, 0x9D, 0xF7, 0x3E, 0xB5, 0xFD, 0x6E, 0x0E, 0x0E, 0xC8, 0x92, 0xC3, + 0x6B, 0x59, 0x89, 0x65, 0x9A, 0x70, 0x0A, 0x03, 0x14, 0xB0, 0xB4, 0xA0, 0x6D, 0x90, 0x6E, 0x90, + 0xC9, 0x37, 0x7B, 0x62, 0x13, 0x34, 0x9F, 0x77, 0x4E, 0x39, 0xCE, 0xAC, 0xCA, 0x10, 0xAD, 0xAA, + 0x3D, 0xBD, 0x0F, 0x4A, 0xC0, 0xF6, 0x52, 0x6A, 0x4C, 0xC1, 0x60, 0x07, 0x2E, 0xFE, 0xBD, 0xAE, + 0x86, 0x75, 0x9C, 0xFB, 0xDE, 0x8A, 0x96, 0x4F, 0x67, 0xCC, 0x3B, 0x9A, 0x77, 0xE8, 0x90, 0x04, + 0x97, 0xE0, 0x20, 0x43, 0x96, 0x07, 0xB9, 0xD9, 0x56, 0x8F, 0xBB, 0x9C, 0x48, 0xBA, 0xA3, 0x44, + 0x36, 0xC7, 0x6F, 0x25, 0x76, 0x10, 0x66, 0x17, 0x50, 0x49, 0x10, 0xBD, 0xB4, 0xE1, 0x92, 0x81, + 0xE6, 0x74, 0x20, 0x1D, 0x50, 0xD3, 0x31, 0x9B, 0xD6, 0x48, 0x16, 0x20, 0xB4, 0x3E, 0x95, 0x8D, + 0x72, 0xE9, 0x6D, 0xC7, 0x15, 0x3E, 0x42, 0xA4, 0xF8, 0x75, 0xC5, 0xD0, 0x2C, 0x13, 0x9F, 0x4A, + 0x3E, 0x4C, 0x19, 0xAC, 0x14, 0x9A, 0x66, 0xF0, 0x66, 0x6B, 0x41, 0x7F, 0xA5, 0x44, 0x1D, 0x96, + 0x03, 0x85, 0x0C, 0xCE, 0x49, 0x80, 0xDC, 0x8F, 0x0F, 0xE3, 0x32, 0x9C, 0x57, 0xE3, 0x2E, 0x21, + 0xC5, 0x35, 0xFA, 0x28, 0x44, 0x7B, 0x8B, 0x99, 0x0F, 0x2D, 0x9F, 0xB2, 0x68, 0xB7, 0x33, 0xAA, + 0xAB, 0xED, 0x3E, 0xA4, 0x46, 0xD5, 0xDB, 0x30, 0x4A, 0x46, 0xDD, 0x7B, 0x46, 0x02, 0xBB, 0x55, + 0x21, 0xA3, 0x33, 0xDB, 0x8B, 0xCA, 0xE7, 0x1C, 0x27, 0x75, 0x17, 0xB3, 0xE2, 0x4F, 0x56, 0x08, + 0x0D, 0xC5, 0x2F, 0xEC, 0x0E, 0x15, 0xEB, 0x79, 0x21, 0xD2, 0xA1, 0x5F, 0x67, 0xDB, 0xED, 0x05, + 0x3C, 0x3E, 0x51, 0x09, 0x17, 0xAE, 0x66, 0x59, 0x7D, 0xA2, 0xDF, 0xE8, 0x80, 0x98, 0x5F, 0x89, + 0x48, 0x6E, 0xDF, 0x64, 0xE1, 0x04, 0xA2, 0xF2, 0x3E, 0xF5, 0x93, 0x23, 0x56, 0xDB, 0x0A, 0x1E, + 0x59, 0x68, 0x19, 0x6F, 0x77, 0xD3, 0x55, 0xCC, 0x6D, 0xB1, 0x89, 0x14, 0x53, 0x14, 0xD8, 0x49, + 0x22, 0xA1, 0xEC, 0x3D, 0x10, 0x5D, 0x2B, 0xA6, 0x79, 0xA0, 0x76, 0x2D, 0xC6, 0x7C, 0x61, 0x06, + 0x34, 0xDD, 0x44, 0xB2, 0x15, 0x4D, 0xD6, 0x6A, 0x89, 0x4B, 0xA6, 0x82, 0x94, 0x4A, 0x55, 0xB2, + 0x2F, 0x1F, 0x92, 0xC7, 0xAB, 0xAE, 0xB6, 0xF9, 0xAE, 0xD9, 0xE2, 0x36, 0x3A, 0x9A, 0xC7, 0x31, + 0xDC, 0xFC, 0xE5, 0x07, 0x24, 0xCD, 0x12, 0xC2, 0x51, 0xF3, 0x6E, 0x8E, 0x61, 0x39, 0xAC, 0x4D, + 0xCB, 0xD0, 0x49, 0xF6, 0x6F, 0xE6, 0xCF, 0xC0, 0x32, 0xE7, 0xE6, 0x8C, 0xB5, 0x86, 0x7E, 0xCC, + 0x97, 0x8F, 0xA8, 0xB8, 0xE4, 0x59, 0xD4, 0x6D, 0xA8, 0xAC, 0x11, 0x16, 0xFD, 0x6C, 0x69, 0xBF, + 0xC3, 0x81, 0x11, 0x11, 0x43, 0xF6, 0x15, 0x22, 0x42, 0x53, 0xC8, 0x09, 0x8E, 0x9A, 0x2D, 0x32, + 0x3A, 0x95, 0xBD, 0x0F, 0x4B, 0xB3, 0xD5, 0x85, 0xF6, 0x07, 0xCA, 0xEA, 0xFA, 0xA0, 0x35, 0x64, + 0x3F, 0x2F, 0x1E, 0xEF, 0xDB, 0xB1, 0xA3, 0xCE, 0x2A, 0x6C, 0x71, 0x90, 0xAE, 0x7D, 0x0F, 0x19, + 0x39, 0x88, 0x36, 0x7C, 0xE0, 0xF8, 0xB1, 0xE7, 0xF5, 0xF7, 0xAE, 0xB6, 0xCB, 0xF5, 0x8F, 0xD8, + 0x58, 0x7B, 0x93, 0x6D, 0x07, 0x66, 0x22, 0x6C, 0x31, 0xA6, 0x44, 0x53, 0xED, 0x85, 0x5B, 0x22, + 0x09, 0x86, 0x3D, 0xCF, 0xA8, 0x70, 0xAA, 0xA0, 0xC0, 0x4B, 0x55, 0x40, 0xED, 0xE8, 0x2F, 0x37, + 0xF0, 0x8E, 0xCC, 0x20, 0x59, 0x1F, 0x48, 0xAA, 0xC4, 0x7C, 0x9F, 0xB4, 0xF3, 0xB0, 0xDD, 0x09, + 0xD7, 0xBC, 0x24, 0x61, 0xAD, 0x5A, 0x3A, 0x71, 0xD4, 0xCB, 0xBD, 0x46, 0x10, 0xB9, 0xE3, 0x53, + 0x6E, 0x86, 0x79, 0x2F, 0xFB, 0x92, 0xD1, 0x5C, 0xF6, 0x05, 0x59, 0x0F, 0x0F, 0x6F, 0x3D, 0x40, + 0xB8, 0xD3, 0x7E, 0x87, 0xEF, 0x69, 0x21, 0x93, 0xA0, 0x08, 0xC1, 0x36, 0xE8, 0x65, 0xA1, 0x09, + 0xB6, 0x76, 0x5A, 0xA6, 0xED, 0x64, 0x51, 0xC3, 0x12, 0xD2, 0x91, 0x57, 0x47, 0x5D, 0xE7, 0x21, + 0x8A, 0x4E, 0x56, 0x11, 0x20, 0x78, 0xE9, 0x99, 0x0B, 0xA0, 0x7A, 0xCB, 0xE8, 0xAC, 0x91, 0xE6, + 0xCA, 0x60, 0x2A, 0x4B, 0x05, 0xD0, 0xCB, 0x7A, 0xAC, 0xB8, 0x19, 0x7D, 0xDA, 0xB2, 0x7F, 0x28, + 0x9F, 0x91, 0xC3, 0xF6, 0xFB, 0x36, 0x25, 0x88, 0x2C, 0xC1, 0x6B, 0x7A, 0x03, 0xA5, 0x07, 0x64, + 0xFA, 0xBD, 0x4C, 0x65, 0x69, 0x49, 0x00, 0x4C, 0x92, 0xB4, 0xAB, 0xEF, 0xA6, 0xB0, 0x39, 0x28, + 0xEA, 0xCF, 0x2F, 0x1F, 0xBC, 0xEE, 0x29, 0xF9, 0x06, 0x49, 0xB5, 0x23, 0x77, 0x55, 0x64, 0x02, + 0x33, 0x6A, 0x1C, 0xF6, 0xE8, 0x05, 0x2A, 0xF0, 0x94, 0xD8, 0xFC, 0x4A, 0xD2, 0x4E, 0x76, 0x08, + 0x99, 0xE5, 0x01, 0x6E, 0xFF, 0x49, 0x31, 0x98, 0xBD, 0xAE, 0x9D, 0x05, 0x54, 0x37, 0xC6, 0x0B, + 0x4B, 0x9C, 0x9C, 0x6F, 0x5C, 0x38, 0xE4, 0x76, 0xD2, 0xEF, 0xD9, 0x9F, 0xE6, 0xFA, 0x90, 0xD7, + 0x21, 0xC6, 0xB0, 0x9B, 0x13, 0xD7, 0xB8, 0xA2, 0xEC, 0x09, 0x67, 0xB7, 0x3A, 0x2F, 0x83, 0x87, + 0x36, 0x3C, 0xC2, 0xC0, 0x1F, 0xF1, 0xE8, 0x8E, 0x46, 0x62, 0xD9, 0x8A, 0x41, 0x92, 0x16, 0xAD, + 0xCB, 0xD6, 0xAC, 0xA8, 0x4D, 0xCB, 0x39, 0x30, 0x81, 0x3A, 0x14, 0x12, 0x45, 0x75, 0xC3, 0xAA, + 0xAB, 0x01, 0x06, 0x6D, 0xC7, 0x42, 0x1F, 0xF9, 0x04, 0x88, 0x90, 0x5A, 0x98, 0x35, 0xDE, 0xC4, + 0xC6, 0x8D, 0x08, 0x56, 0x4A, 0x2E, 0xE3, 0x78, 0x46, 0x47, 0x07, 0x4E, 0x40, 0xD1, 0x8F, 0x5A, + 0x67, 0xAD, 0xF2, 0x5F, 0xF0, 0x0A, 0x8E, 0x71, 0xBF, 0x0A, 0x00, 0xFB, 0xC5, 0xC8, 0x90, 0x7B, + 0x4F, 0xF4, 0xCC, 0x6F, 0xE5, 0xAE, 0x30, 0x56, 0x9B, 0xEF, 0x7E, 0x48, 0x21, 0x2B, 0x97, 0x65, + 0xCE, 0xAB, 0x98, 0x6D, 0x89, 0xF9, 0x35, 0x39, 0x37, 0xE3, 0x89, 0x67, 0x53, 0x1F, 0x1C, 0xE4, + 0x9F, 0xD0, 0x3B, 0xAE, 0xFB, 0x63, 0x29, 0xCA, 0xE9, 0x58, 0x02, 0xE3, 0x4A, 0xA7, 0x2D, 0x99, + 0x06, 0x03, 0x3B, 0x9A, 0x2A, 0x13, 0xE9, 0x27, 0xA7, 0xD7, 0x06, 0x8A, 0x49, 0x7A, 0xD3, 0x64, + 0xC1, 0xF4, 0x69, 0xA0, 0xC0, 0x14, 0xC4, 0x56, 0x89, 0x31, 0xD0, 0xDC, 0xF3, 0xB2, 0xB3, 0x51, + 0xF5, 0x38, 0x47, 0x47, 0x90, 0xC2, 0x2F, 0xFF, 0x80, 0x43, 0x35, 0x96, 0x2B, 0xE3, 0x50, 0x55, + 0x2D, 0x11, 0xCB, 0xF4, 0x93, 0x10, 0xD5, 0x3A, 0x5B, 0x82, 0x58, 0x10, 0xC1, 0x17, 0x31, 0xDE, + 0x96, 0x7B, 0xCA, 0xE4, 0x90, 0x89, 0x74, 0x97, 0x91, 0xA2, 0x2F, 0x01, 0xE0, 0xCC, 0x73, 0x0F, + 0xB1, 0x76, 0x56, 0x5F, 0x2B, 0xDE, 0x7C, 0x29, 0xD3, 0x51, 0x42, 0xA3, 0x7C, 0x16, 0xB6, 0x6B, + 0x4A, 0x06, 0x7B, 0xDD, 0xF0, 0x3B, 0x8B, 0x6A, 0x55, 0x0C, 0x2B, 0xF2, 0x61, 0x41, 0xB4, 0x37, + 0xA2, 0xB4, 0x4E, 0x01, 0xD3, 0x09, 0x44, 0xD0, 0xE3, 0x88, 0x6E, 0x6F, 0xF3, 0x22, 0x6E, 0xF7, + 0x59, 0xC9, 0xE4, 0xA6, 0x97, 0x51, 0x33, 0x16, 0x53, 0xA0, 0xE9, 0xD5, 0x6E, 0x97, 0xAE, 0x5B, + 0x02, 0x11, 0x2B, 0x5F, 0xE3, 0x93, 0xAA, 0x09, 0x56, 0x09, 0x17, 0xFE, 0xE9, 0x93, 0x1A, 0x46, + 0x45, 0xBD, 0xBD, 0x75, 0xD6, 0x60, 0xE9, 0x5A, 0xA9, 0x7E, 0x91, 0xD1, 0x7C, 0xDB, 0xF1, 0x32, + 0x6F, 0x79, 0x26, 0xBC, 0xE3, 0x79, 0xB0, 0x2D, 0xCE, 0xBE, 0x08, 0xD5, 0xFD, 0x52, 0xD5, 0xD5, + 0xAC, 0x86, 0x70, 0xBC, 0x17, 0xB3, 0xF0, 0x4F, 0x6A, 0x94, 0xF2, 0x20, 0xDD, 0xCB, 0x2F, 0xAF, + 0x1D, 0xA7, 0x24, 0xFE, 0x3A, 0x98, 0x07, 0x68, 0xBE, 0xE1, 0x6F, 0x01, 0x78, 0xF1, 0x26, 0x3E, + 0xFC, 0x75, 0xBC, 0xA1, 0x05, 0xE7, 0x70, 0xAA, 0xFC, 0x7C, 0x8C, 0x29, 0x6B, 0x20, 0x30, 0x65, + 0xBF, 0x34, 0x30, 0xA7, 0xFE, 0x2F, 0x51, 0x2E, 0x11, 0x99, 0xF9, 0xD5, 0xDA, 0xF4, 0x1D, 0x74, + 0xEF, 0x50, 0x7E, 0x3D, 0xEE, 0xD6, 0xDA, 0x44, 0xDD, 0x83, 0x3F, 0x9C, 0x2F, 0xE8, 0x7E, 0x28, + 0x65, 0x4E, 0x9C, 0xEF, 0x6C, 0xAA, 0xE0, 0x0C, 0x33, 0x33, 0xDB, 0x65, 0x19, 0x18, 0xC5, 0x91, + 0xA3, 0x9F, 0x02, 0x1D, 0x0D, 0xDA, 0x44, 0x8A, 0x1D, 0xF5, 0x61, 0x41, 0x55, 0x11, 0x75, 0x06, + 0x3C, 0x79, 0x45, 0xDE, 0xDC, 0x75, 0x24, 0xC6, 0x92, 0x16, 0xFE, 0x7C, 0x0C, 0x1B, 0x0A, 0x62, + 0x9E, 0x5E, 0x0A, 0x30, 0xF4, 0x1A, 0x2C, 0x45, 0xEF, 0xE4, 0x10, 0xB6, 0x0C, 0xC2, 0x8B, 0x73, + 0xDE, 0x4E, 0x37, 0x6C, 0xAB, 0xBA, 0x70, 0x76, 0x30, 0x26, 0x11, 0x92, 0x8C, 0x80, 0x6C, 0x1C, + 0x3F, 0xBF, 0x7D, 0xD4, 0x63, 0x70, 0x0C, 0x9B, 0xEF, 0xF2, 0x75, 0x34, 0x67, 0x81, 0x77, 0x8F, + 0xF9, 0x2F, 0x9E, 0x9F, 0xA6, 0x3B, 0x9C, 0x1E, 0x42, 0x9A, 0xCB, 0x3F, 0xA7, 0xF1, 0xBF, 0xF1, + 0x39, 0xB4, 0x0A, 0x6D, 0x73, 0xC9, 0x01, 0x6E, 0xAE, 0x17, 0x95, 0x5A, 0xC0, 0x25, 0xA1, 0xB1, + 0x4D, 0xF1, 0xA4, 0x42, 0xAC, 0x92, 0xE6, 0x84, 0xD4, 0xAF, 0x14, 0x44, 0x2E, 0x2F, 0xA5, 0x34, + 0x24, 0x61, 0x0A, 0x22, 0x07, 0x60, 0x7B, 0xE6, 0x4B, 0xF6, 0xB2, 0x7C, 0x24, 0x86, 0x2E, 0x86, + 0xCF, 0xC1, 0x13, 0xB6, 0xC9, 0x9F, 0xD6, 0x19, 0x57, 0x3F, 0x2A, 0x4A, 0x54, 0x68, 0xDE, 0x16, + 0x5D, 0xED, 0x35, 0x99, 0x6C, 0xFC, 0xED, 0x31, 0xE2, 0xD7, 0x8E, 0x2E, 0x3C, 0x35, 0xA2, 0xEA, + 0xEE, 0x7B, 0xEE, 0x33, 0x62, 0x37, 0x8D, 0xE8, 0x12, 0x9A, 0x05, 0x17, 0xCC, 0xDC, 0x38, 0xFF, + 0x41, 0x6A, 0xC6, 0x67, 0x80, 0x76, 0x98, 0x57, 0x06, 0x4B, 0x31, 0x8F, 0x9C, 0x1A, 0x90, 0x3D, + 0x3F, 0xD8, 0x10, 0x2A, 0xC5, 0xF9, 0xC6, 0x0C, 0x16, 0x9A, 0x5A, 0xCD, 0x41, 0xB3, 0x1A, 0x75, + 0x26, 0x7B, 0x5D, 0x18, 0xAA, 0xB9, 0x1E, 0x98, 0xEC, 0x3C, 0xE0, 0xCA, 0x13, 0xAE, 0x0B, 0x6C, + 0x6E, 0x09, 0x9C, 0x2D, 0xF0, 0xCC, 0x2E, 0x88, 0x2E, 0xDC, 0xA5, 0xB6, 0x4F, 0x14, 0x9A, 0x11, + 0x95, 0x3B, 0xB3, 0x0B, 0xA1, 0x62, 0x84, 0x67, 0xE2, 0x50, 0x90, 0x5A, 0x75, 0xFA, 0x2F, 0x35, + 0x39, 0xF0, 0xBB, 0x34, 0x89, 0xF5, 0x6A, 0xBC, 0x01, 0x76, 0xFF, 0xCF, 0xE3, 0xF7, 0xA2, 0x71, + 0xCE, 0xD8, 0x58, 0xC7, 0xBB, 0x6F, 0x08, 0xE3, 0xB4, 0x44, 0x5C, 0x95, 0x4D, 0xF5, 0x84, 0x35, + 0x39, 0x14, 0x1F, 0x8E, 0xD7, 0x52, 0x57, 0x1E, 0xE9, 0x1D, 0x2D, 0x27, 0x82, 0xCC, 0x07, 0xF2, + 0xE7, 0xA1, 0xCA, 0xB7, 0xF3, 0xED, 0x30, 0x9D, 0xC3, 0x8C, 0x30, 0x09, 0x50, 0x51, 0xAF, 0xE1, + 0x50, 0xC4, 0x57, 0x31, 0xC3, 0x88, 0xC4, 0x7A, 0xAF, 0xBB, 0x97, 0x89, 0xB5, 0xED, 0x42, 0xC9, + 0xDF, 0xB4, 0x2A, 0x12, 0x4C, 0x73, 0x0B, 0x23, 0xC8, 0xF7, 0x09, 0x6F, 0x81, 0xE7, 0x12, 0x7C, + 0xD8, 0xD7, 0x6F, 0x84, 0x5B, 0xBC, 0xFF, 0x0D, 0xCD, 0x3D, 0x29, 0x0F, 0x03, 0xB3, 0x29, 0x28, + 0x83, 0x7B, 0x78, 0xD1, 0x3B, 0x15, 0x38, 0x6F, 0xC1, 0x29, 0xF5, 0x0E, 0x04, 0x88, 0xCC, 0xB2, + 0x6C, 0x4A, 0xF1, 0x51, 0x5E, 0x11, 0x39, 0x80, 0x26, 0xCF, 0xC4, 0x07, 0x2E, 0x20, 0x40, 0xB1, + 0xE9, 0x9D, 0xD5, 0xED, 0x99, 0xC6, 0x6D, 0xCE, 0xBE, 0x0D, 0x28, 0x17, 0xCA, 0x1B, 0x13, 0xFA, + 0xC2, 0x66, 0xD2, 0x4D, 0xF6, 0x1B, 0x9F, 0x0F, 0xAB, 0x24, 0x3C, 0x31, 0x04, 0xA2, 0x91, 0x38, + 0x19, 0x6E, 0x58, 0x72, 0x20, 0x90, 0xE0, 0x54, 0x4C, 0xCB, 0x3E, 0x6F, 0xBC, 0x09, 0x26, 0x72, + 0x20, 0x83, 0xF2, 0x46, 0xD4, 0xED, 0x52, 0x3D, 0x5B, 0xE4, 0x27, 0xD4, 0xDB, 0x83, 0xE6, 0x4A, + 0x0E, 0x6D, 0x33, 0x12, 0x89, 0xE3, 0x8B, 0x57, 0xDF, 0xBB, 0x84, 0xEE, 0x44, 0x6F, 0xD1, 0x44, + 0x5C, 0x30, 0x49, 0x13, 0x3E, 0xDE, 0xFE, 0x87, 0xAD, 0x73, 0x73, 0xF8, 0xE6, 0x0C, 0x0C, 0xBC, + 0xA9, 0x18, 0x33, 0x97, 0x4D, 0xF5, 0x53, 0xAF, 0x93, 0xEA, 0xF4, 0x01, 0x39, 0x18, 0x59, 0xB3, + 0x8F, 0xE5, 0x0D, 0xEB, 0x4A, 0xD3, 0xF3, 0xE8, 0x79, 0xB8, 0xAD, 0x16, 0xC3, 0x5A, 0x24, 0xF2, + 0x8B, 0xB1, 0x52, 0x51, 0x33, 0xBD, 0xA1, 0x00, 0xBA, 0x78, 0x48, 0x7E, 0xD1, 0xC3, 0xD6, 0x3A, + 0x62, 0x44, 0xC9, 0x6A, 0x26, 0xA9, 0x65, 0x1E, 0xC8, 0x27, 0xE4, 0xD9, 0x9E, 0x78, 0xEC, 0xC7, + 0x20, 0xC0, 0x2D, 0x8F, 0xF6, 0x04, 0x8B, 0x0A, 0x51, 0x73, 0xF3, 0x5E, 0xF2, 0x09, 0xDF, 0x39, + 0xBE, 0x62, 0x80, 0x7D, 0x55, 0xDC, 0xD6, 0x3F, 0xA6, 0x78, 0x69, 0xDB, 0xC4, 0x48, 0x20, 0x2F, + 0x37, 0xCB, 0xC4, 0xDE, 0xEB, 0xB8, 0x6B, 0xD3, 0x73, 0x87, 0xA2, 0x94, 0xF8, 0x7B, 0x98, 0x2A, + 0x63, 0xFA, 0xBE, 0x4B, 0x72, 0x3E, 0xC2, 0x3B, 0x59, 0x34, 0xBD, 0xF5, 0x0C, 0xBF, 0x5B, 0x9C, + 0x64, 0xE3, 0xF8, 0x93, 0x94, 0x9F, 0x63, 0x0A, 0xDF, 0x5A, 0xAF, 0xEE, 0x3F, 0xC2, 0x2D, 0x08, + 0xA9, 0x41, 0xAD, 0x67, 0x42, 0xEC, 0x42, 0x91, 0xE2, 0xE5, 0x2D, 0xA9, 0x1D, 0x8D, 0x20, 0xB7, + 0x36, 0x89, 0x6B, 0xC9, 0xDB, 0x83, 0xE3, 0x37, 0x7F, 0xDC, 0x5A, 0x61, 0x8A, 0x1E, 0x31, 0xFE, + 0x1F, 0x77, 0x43, 0x8C, 0xD9, 0x8C, 0x46, 0x5C, 0x7A, 0x0C, 0xFB, 0x17, 0x35, 0x39, 0xD0, 0xA1, + 0xED, 0xF8, 0x10, 0xCB, 0x0D, 0x2C, 0x7C, 0xCA, 0x89, 0x29, 0xB8, 0x3E, 0x85, 0x68, 0x44, 0x9F, + 0xE8, 0x2D, 0x35, 0x7D, 0x77, 0x2F, 0x11, 0xB1, 0xB2, 0x62, 0xAA, 0xF1, 0x9D, 0xB3, 0x14, 0x1A, + 0x90, 0xD0, 0xAF, 0x88, 0xB2, 0xBC, 0x26, 0x83, 0xAF, 0x4D, 0xC4, 0xB2, 0xAD, 0xEA, 0x48, 0xFD, + 0xDF, 0xE7, 0xF7, 0x83, 0x31, 0x81, 0x74, 0xD9, 0x20, 0x06, 0x30, 0x87, 0x36, 0x6C, 0xC4, 0x9D, + 0xA9, 0x31, 0x60, 0x01, 0xD3, 0x9E, 0xEE, 0xD3, 0x28, 0x39, 0xEA, 0xD1, 0x16, 0xBB, 0x90, 0x1B, + 0x59, 0x26, 0x8D, 0xAF, 0xAC, 0x00, 0xEE, 0xBD, 0x1D, 0x62, 0x9E, 0xC5, 0x7E, 0x26, 0x5B, 0xBE, + 0x7A, 0x7A, 0x64, 0x75, 0xC2, 0x0B, 0x11, 0xDA, 0x3C, 0x1D, 0x9A, 0x42, 0xFD, 0x64, 0x6C, 0x04, + 0x96, 0x57, 0x8B, 0x62, 0x26, 0x02, 0xAD, 0x33, 0xE5, 0x35, 0x9F, 0x39, 0xDF, 0xF0, 0xEC, 0x04, + 0x65, 0x4D, 0xA7, 0xE9, 0x78, 0xDC, 0xEB, 0x2C, 0xA9, 0xC1, 0x82, 0x3E, 0x30, 0x83, 0x99, 0x17, + 0x74, 0x67, 0x92, 0xCE, 0x90, 0x24, 0x7A, 0x50, 0xF0, 0x90, 0xD5, 0x09, 0x82, 0x49, 0x70, 0x19, + 0xEF, 0x20, 0xFA, 0x2E, 0x9E, 0x60, 0xC1, 0x01, 0x04, 0x0E, 0x4C, 0x82, 0x9E, 0xA5, 0x81, 0x3C, + 0x78, 0x05, 0x08, 0x87, 0xDB, 0x84, 0xDD, 0x92, 0x63, 0xFA, 0xEF, 0x92, 0x8E, 0xCE, 0xB9, 0x65, + 0xED, 0xB7, 0x29, 0x30, 0xF5, 0x5F, 0xFA, 0xA8, 0x46, 0xDA, 0xF3, 0xFC, 0x78, 0x06, 0x19, 0x9A, + 0xC5, 0xDC, 0x8B, 0xD2, 0x8F, 0x3F, 0xA2, 0x9D, 0xE4, 0x02, 0xD9, 0x36, 0xA9, 0xBC, 0x73, 0x95, + 0xC6, 0xA8, 0x43, 0x7B, 0x65, 0x46, 0xDB, 0xBD, 0x5C, 0x93, 0xE6, 0xD1, 0x3C, 0xF5, 0xC8, 0x35, + 0x2B, 0xB3, 0x90, 0x37, 0x07, 0xEE, 0x48, 0x42, 0x63, 0x10, 0x27, 0xE9, 0xF6, 0xD5, 0x3D, 0xB4, + 0x44, 0x01, 0xC7, 0xAF, 0x07, 0xD5, 0x39, 0x07, 0xC9, 0x8F, 0x13, 0x37, 0x42, 0xBF, 0xCF, 0xC8, + 0xA1, 0x50, 0xDB, 0x45, 0x39, 0x3D, 0x4D, 0xD0, 0x0B, 0x66, 0xA3, 0x10, 0x8F, 0xB8, 0x74, 0x01, + 0x47, 0x3B, 0x2E, 0xE4, 0x93, 0xF3, 0x7C, 0xD6, 0x96, 0x34, 0xE2, 0x5D, 0x2C, 0xC2, 0x57, 0x15, + 0x85, 0x3A, 0xC4, 0xBB, 0xB6, 0x7F, 0xD8, 0xBD, 0x08, 0x7C, 0x8F, 0xB8, 0x90, 0xB4, 0xBE, 0x69, + 0xC8, 0xFE, 0x03, 0xAA, 0xBA, 0x3A, 0x35, 0xC8, 0x23, 0xC1, 0xE2, 0xDE, 0xA0, 0xD1, 0x1F, 0xBE, + 0x6D, 0xDF, 0xFD, 0xD3, 0x9F, 0x87, 0xF5, 0xA8, 0x72, 0x1C, 0x68, 0xA9, 0xD3, 0x11, 0x3E, 0x05, + 0xBF, 0x7B, 0x00, 0x1F, 0x65, 0xB3, 0x1E, 0x8E, 0xFC, 0x66, 0x47, 0xFB, 0x64, 0x29, 0x43, 0x05, + 0x76, 0x9A, 0xA1, 0xF9, 0xB4, 0x6C, 0x86, 0xBC, 0x76, 0xA6, 0x3B, 0x42, 0xD5, 0x7D, 0x2F, 0x93, + 0xF6, 0xE8, 0xEF, 0x32, 0xEC, 0x61, 0x62, 0xD1, 0xA3, 0xA1, 0xF5, 0xAD, 0xBF, 0x55, 0x92, 0x42, + 0xD9, 0xF3, 0x37, 0x88, 0xFA, 0xD2, 0x9B, 0x54, 0xF1, 0xE3, 0x43, 0xEF, 0x18, 0x29, 0xA6, 0xA9, + 0xB9, 0x74, 0x9A, 0xD7, 0x77, 0x38, 0xE3, 0x36, 0x3D, 0xF5, 0x11, 0x22, 0x52, 0xBB, 0x4E, 0xBF, + 0xC1, 0xF9, 0xF4, 0x48, 0x73, 0x32, 0x1D, 0x3E, 0x1D, 0x70, 0x7C, 0x63, 0xF1, 0xB7, 0x0B, 0xAB, + 0x1B, 0x7C, 0x22, 0x8E, 0x9C, 0xA4, 0x9B, 0x28, 0xF6, 0xD7, 0x02, 0xD1, 0x25, 0x9F, 0x4F, 0x20, + 0x77, 0xB1, 0xE1, 0x40, 0x63, 0x30, 0x3E, 0xC1, 0x6D, 0x85, 0x3A, 0x25, 0xFC, 0x65, 0xE4, 0xE4, + 0xAA, 0x70, 0x8B, 0xB2, 0xC5, 0xEB, 0xC9, 0xAF, 0x86, 0x39, 0x2C, 0x70, 0x3A, 0x74, 0x96, 0x32, + 0xDD, 0x6B, 0x37, 0x26, 0x6F, 0x63, 0x2A, 0xEB, 0xD1, 0x2F, 0xF6, 0x25, 0x3B, 0xFA, 0x8B, 0x9F, + 0x32, 0x9C, 0xD3, 0x40, 0x76, 0x86, 0x4D, 0x99, 0x4D, 0x9C, 0x57, 0xF7, 0x0F, 0x99, 0xF9, 0x45, + 0x43, 0x31, 0x50, 0x39, 0x50, 0x84, 0x55, 0xD3, 0x9B, 0x03, 0x11, 0x36, 0xE1, 0x59, 0x51, 0xDF, + 0x6F, 0xFA, 0x19, 0x07, 0x59, 0x1F, 0x40, 0xB1, 0x7C, 0x85, 0x60, 0xC4, 0x15, 0xDB, 0x12, 0xB6, + 0x2A, 0x31, 0x6E, 0x9D, 0x28, 0x74, 0xAE, 0xF6, 0x85, 0xCA, 0x34, 0x07, 0x6F, 0x90, 0xBF, 0xAC, + 0xF0, 0xDC, 0xF1, 0x14, 0x65, 0x7E, 0x6D, 0x60, 0xC8, 0xEA, 0x8C, 0xC7, 0xB1, 0x52, 0x42, 0xD0, + 0x0C, 0x88, 0xC2, 0x14, 0xF8, 0xD3, 0x08, 0x51, 0xBB, 0x19, 0x4A, 0x56, 0x77, 0x37, 0x7E, 0x8C, + 0xE0, 0xB2, 0x90, 0x26, 0x95, 0xCD, 0x4B, 0x05, 0xA9, 0x42, 0xF4, 0x62, 0x11, 0x04, 0x4A, 0x76, + 0x6F, 0x9D, 0x04, 0x37, 0x35, 0xCB, 0xC2, 0x29, 0xB6, 0x5D, 0xE4, 0x2D, 0x09, 0xD3, 0x94, 0x21, + 0x4A, 0xEA, 0xFB, 0x1F, 0x21, 0xBF, 0x41, 0x36, 0xB6, 0x3F, 0x03, 0x8C, 0x2D, 0x33, 0x3B, 0x67, + 0x31, 0x67, 0xC8, 0x83, 0x08, 0xD2, 0x33, 0x3E, 0x36, 0xA2, 0x8B, 0x5A, 0xA2, 0x11, 0xF0, 0xDB, + 0xBD, 0x19, 0x8F, 0x40, 0x3C, 0x73, 0x52, 0x76, 0x98, 0xFD, 0xB4, 0xE3, 0x61, 0xFD, 0x89, 0xE7, + 0x18, 0xC4, 0xA2, 0x67, 0x41, 0x55, 0x00, 0x1A, 0x34, 0x48, 0xE5, 0x8A, 0x34, 0x1C, 0xBF, 0xD0, + 0x7F, 0x42, 0x0C, 0x61, 0x3F, 0x05, 0x77, 0x4C, 0xA8, 0xBB, 0x11, 0xF6, 0x9F, 0xAA, 0x18, 0x6A, + 0x9A, 0xC0, 0x31, 0xAE, 0xBA, 0x27, 0xFC, 0xDF, 0x21, 0x71, 0x03, 0xF2, 0xD3, 0x54, 0x39, 0x84, + 0x22, 0xC5, 0x35, 0x48, 0x49, 0x07, 0x84, 0x8A, 0xA1, 0x49, 0x34, 0x4B, 0xFD, 0x75, 0x3B, 0x41, + 0x0B, 0xD3, 0xEE, 0x62, 0x1B, 0x88, 0xAD, 0x2F, 0x7B, 0xED, 0x7D, 0x8F, 0xB9, 0x6B, 0xF3, 0x37, + 0xDF, 0x87, 0x0D, 0x88, 0xF0, 0xE8, 0x1E, 0x64, 0xF5, 0xB6, 0x09, 0x93, 0x7B, 0xBC, 0x58, 0xE8, + 0x21, 0x4E, 0x32, 0xE5, 0xC2, 0x04, 0x3C, 0x64, 0x9C, 0x16, 0x6D, 0x3A, 0xD6, 0x5C, 0xDE, 0x85, + 0x39, 0x25, 0x1B, 0x1C, 0xDD, 0x67, 0x95, 0xA9, 0xAA, 0x68, 0x35, 0x62, 0x61, 0xE5, 0xED, 0x8C, + 0x62, 0xFA, 0xA3, 0xB7, 0x81, 0x9B, 0x41, 0xAF, 0x43, 0xDC, 0x14, 0xF5, 0x71, 0x93, 0xA6, 0x04, + 0x2D, 0x97, 0xD1, 0x34, 0x7D, 0x10, 0x18, 0xDC, 0x34, 0x8B, 0xBC, 0x50, 0xC3, 0x25, 0x8E, 0x96, + 0x97, 0x7B, 0x7B, 0x7D, 0xCA, 0x62, 0xD1, 0xFF, 0x19, 0xD8, 0xF3, 0x8F, 0xC3, 0x60, 0xC9, 0x22, + 0xE9, 0x70, 0x27, 0x70, 0x34, 0xE5, 0xD7, 0x0E, 0x00, 0x5E, 0x86, 0x83, 0x58, 0x8F, 0x5C, 0x98, + 0x6B, 0xB8, 0xAA, 0x68, 0x89, 0x26, 0x82, 0xD5, 0x67, 0x81, 0xAD, 0x45, 0x5D, 0x72, 0xBA, 0x11, + 0x86, 0xB7, 0x12, 0x68, 0xD1, 0xC6, 0xFC, 0xDD, 0x2A, 0xEA, 0xF8, 0x13, 0x16, 0x00, 0x3C, 0x21, + 0xCB, 0x1D, 0x46, 0x31, 0xC4, 0xC3, 0xFF, 0x04, 0xDB, 0xF4, 0x0C, 0xF9, 0xAC, 0x75, 0x52, 0x22, + 0x07, 0xC4, 0xD4, 0xC1, 0xAB, 0xF3, 0x10, 0x0C, 0x67, 0x5F, 0x21, 0x31, 0xB9, 0x8A, 0x52, 0x22, + 0x12, 0x34, 0x80, 0x8D, 0x3F, 0x5B, 0xE3, 0x32, 0x28, 0x28, 0xBE, 0x26, 0xC7, 0xEF, 0x8A, 0x71, + 0xD6, 0xCA, 0x71, 0x2C, 0x9F, 0x9E, 0xA3, 0xAA, 0xB5, 0xD4, 0x6B, 0xA5, 0x0A, 0xD7, 0x25, 0x92, + 0x81, 0x10, 0xB3, 0xC0, 0x7A, 0xC1, 0xDC, 0x2C, 0x1F, 0xAC, 0x96, 0xD9, 0x32, 0xCF, 0x69, 0xAC, + 0x3B, 0xBF, 0xE4, 0xA2, 0xF7, 0xDD, 0xD7, 0xFC, 0x1E, 0x7C, 0x47, 0x6D, 0xFE, 0x17, 0x40, 0x1C, + 0x4A, 0xEB, 0x8D, 0x2C, 0x03, 0xFE, 0x56, 0x37, 0x89, 0xE4, 0x59, 0x99, 0x5D, 0x7C, 0x20, 0x6A, + 0x57, 0xCD, 0x66, 0xD9, 0xF8, 0x33, 0x42, 0x1E, 0xE4, 0x0F, 0xBA, 0x32, 0xFB, 0x67, 0xA4, 0x79, + 0x43, 0xAA, 0xFB, 0xB3, 0x20, 0xA4, 0xC1, 0xCE, 0x48, 0x03, 0xB0, 0x1E, 0x4A, 0x26, 0x47, 0x81, + 0x90, 0x70, 0x69, 0x0E, 0x3E, 0x75, 0x89, 0x1B, 0xBC, 0x57, 0x09, 0xE8, 0x78, 0xE8, 0xDB, 0xAB, + 0x43, 0xE2, 0xC4, 0xAB, 0xBF, 0xDA, 0x50, 0x45, 0x6E, 0x4D, 0x5E, 0xE7, 0xE4, 0x4B, 0x12, 0xBF, + 0x9A, 0x36, 0xF3, 0xCF, 0x75, 0xBF, 0x7A, 0x2A, 0xD5, 0xC6, 0x92, 0xCB, 0xCE, 0x49, 0xD7, 0xF3, + 0x35, 0xE4, 0x26, 0x70, 0x0D, 0x98, 0x0A, 0x46, 0x53, 0xCC, 0xB3, 0xFE, 0x48, 0xA8, 0xB8, 0x5E, + 0x1C, 0x1F, 0x29, 0xBF, 0xF5, 0x46, 0x36, 0xF9, 0xF5, 0xDA, 0x4D, 0xF4, 0x3E, 0x4B, 0x7A, 0x39, + 0xA1, 0xA6, 0x17, 0x23, 0x21, 0xB9, 0x98, 0xFB, 0x19, 0x61, 0x30, 0x86, 0xE4, 0xC1, 0x4A, 0x95, + 0x70, 0x4A, 0x34, 0x73, 0x60, 0x4C, 0xAA, 0xEC, 0x16, 0xE9, 0x0B, 0xA8, 0xA3, 0x43, 0xD1, 0xC5, + 0x3C, 0xB6, 0xEB, 0xA1, 0x2A, 0xFC, 0x75, 0xDE, 0x1B, 0x08, 0x1A, 0x32, 0xE7, 0x6B, 0xFD, 0xFC, + 0x64, 0x0E, 0xCC, 0x67, 0x7F, 0x98, 0xFD, 0xCE, 0xF1, 0xE2, 0x80, 0xF3, 0xCC, 0xAC, 0x07, 0x08, + 0x88, 0x0D, 0x73, 0xE7, 0x7E, 0xF8, 0xB8, 0x9F, 0xF5, 0xFB, 0x3F, 0x02, 0x72, 0xBA, 0x2D, 0x60, + 0xEF, 0x8C, 0xAC, 0x75, 0x26, 0xE5, 0xA6, 0xA8, 0xA9, 0xC8, 0x85, 0x28, 0xC4, 0x8D, 0x5C, 0x9A, + 0xF9, 0xC6, 0x48, 0x3F, 0x4A, 0x83, 0x5E, 0xD0, 0xFC, 0x62, 0x58, 0x6A, 0x7C, 0x26, 0x2F, 0xB4, + 0x2D, 0x23, 0xD5, 0xBC, 0x4F, 0x18, 0x39, 0xF6, 0xEB, 0x34, 0xED, 0xF7, 0xDD, 0x47, 0xC4, 0x3B, + 0x32, 0x53, 0xE6, 0x72, 0x1F, 0xE6, 0x04, 0x3A, 0x58, 0x95, 0x7E, 0x0E, 0x53, 0x66, 0xB9, 0x85, + 0x25, 0x96, 0xB2, 0xDE, 0xEC, 0x60, 0xF3, 0x64, 0x1D, 0xFC, 0xB6, 0xAB, 0x48, 0x48, 0xB7, 0xEA, + 0xA9, 0x29, 0x05, 0xDC, 0xB3, 0x75, 0xFB, 0xB9, 0x45, 0x3F, 0x75, 0xE5, 0x9A, 0xCE, 0x7A, 0xBD, + 0x1A, 0x17, 0x14, 0xAA, 0xBA, 0x94, 0xDA, 0xA9, 0x7D, 0x32, 0xEB, 0x99, 0x8F, 0xE8, 0x1C, 0xCB, + 0xE4, 0x03, 0x35, 0x80, 0xCF, 0xA5, 0xD4, 0x42, 0xD9, 0x37, 0xCB, 0x1C, 0xE5, 0x13, 0x5E, 0x21, + 0x9E, 0x91, 0x04, 0xF4, 0xB4, 0x7D, 0x28, 0xC7, 0xF4, 0x1A, 0x75, 0x43, 0x07, 0x4E, 0xD5, 0x59, + 0x3B, 0x1C, 0x65, 0x71, 0x23, 0x31, 0x9A, 0x82, 0x43, 0x14, 0x1D, 0x22, 0xE5, 0x08, 0xAF, 0xD3, + 0xCB, 0xFB, 0x5A, 0x48, 0xC8, 0xF0, 0xB6, 0xBE, 0xAB, 0x70, 0x6E, 0x8F, 0x3B, 0x7B, 0xB4, 0xE7, + 0x4A, 0x80, 0x8E, 0x96, 0x65, 0x90, 0x0E, 0x49, 0xDC, 0x07, 0x49, 0xCF, 0x2C, 0xE1, 0xE7, 0x25, + 0xCD, 0xE9, 0x2D, 0xC9, 0x7D, 0xF4, 0x16, 0x27, 0x88, 0x24, 0x51, 0x97, 0x52, 0x66, 0xE8, 0x77, + 0xD2, 0x2C, 0xFF, 0x5A, 0xB8, 0x57, 0xEE, 0xA6, 0x94, 0x36, 0xD0, 0x35, 0x35, 0x9B, 0x14, 0xA3, + 0x6E, 0xE8, 0x5E, 0x05, 0xBD, 0xD3, 0x1D, 0x76, 0xE4, 0xA7, 0x62, 0x6E, 0x50, 0x8E, 0xED, 0xB5, + 0x38, 0x15, 0x42, 0x48, 0xC3, 0x4C, 0x73, 0x9B, 0xE8, 0xD7, 0xF5, 0x7F, 0xB0, 0xF4, 0x13, 0x98, + 0x7A, 0x8D, 0xBE, 0x82, 0x0C, 0x5E, 0x28, 0xAF, 0x1D, 0x4F, 0x34, 0x1F, 0x66, 0xE1, 0x54, 0x78, + 0xDC, 0xA8, 0x48, 0x4A, 0xF7, 0xC5, 0x34, 0x8A, 0x03, 0x5B, 0xE5, 0x16, 0xB8, 0x13, 0x60, 0x62, + 0x74, 0x27, 0xEB, 0xE3, 0x1D, 0xC1, 0x0D, 0x36, 0xFD, 0xB6, 0xE8, 0xDC, 0xB3, 0xEB, 0xDA, 0x37, + 0xD9, 0x6C, 0xDC, 0xE4, 0xA3, 0x28, 0xCF, 0x66, 0xF6, 0xB1, 0xC4, 0x62, 0x6F, 0xD8, 0x00, 0xBB, + 0x7D, 0xA1, 0xEA, 0xCE, 0x88, 0x8F, 0xE6, 0x91, 0x15, 0x0F, 0x02, 0xAC, 0x87, 0x14, 0xA8, 0x3C, + 0x71, 0x14, 0x8E, 0xCB, 0x0D, 0x65, 0x48, 0xA2, 0xCB, 0x67, 0xBE, 0xA5, 0x4D, 0x0B, 0x44, 0xCE, + 0x57, 0xB0, 0xCA, 0x79, 0x3B, 0xA8, 0x4E, 0x4F, 0x95, 0xBD, 0xF0, 0xD0, 0x44, 0xCC, 0xD9, 0x0E, + 0x1C, 0x8D, 0xE2, 0x4B, 0xC4, 0x38, 0x58, 0xA1, 0x8D, 0x52, 0xA8, 0xF9, 0x28, 0xEE, 0x52, 0x33, + 0xE7, 0x9A, 0x32, 0x29, 0x0F, 0x7B, 0x41, 0x47, 0x6D, 0x14, 0x4D, 0xA3, 0x93, 0xEC, 0x3E, 0xBA, + 0xE8, 0x7C, 0xFC, 0x38, 0x07, 0x22, 0x8C, 0x7B, 0x6E, 0x6E, 0xAB, 0x34, 0x40, 0xC7, 0xBD, 0x47, + 0x48, 0x43, 0x01, 0x73, 0x60, 0xC9, 0xA4, 0x46, 0xF9, 0x5C, 0xC5, 0xD2, 0xF0, 0x03, 0xF6, 0x13, + 0x8D, 0x2A, 0x6D, 0xB1, 0xEF, 0x0B, 0x6F, 0x93, 0x25, 0x7C, 0xA8, 0xA7, 0xDF, 0xFA, 0x5C, 0x15, + 0xD1, 0x99, 0x95, 0x7E, 0x34, 0x6E, 0xB7, 0x2B, 0xAB, 0xC2, 0xDC, 0xDD, 0xE6, 0xB2, 0x83, 0x1A, + 0xAE, 0x3C, 0x75, 0x1C, 0xEF, 0xB7, 0xB5, 0x29, 0xEA, 0x5C, 0x92, 0xB2, 0xB5, 0x7B, 0x6E, 0xE4, + 0xCF, 0x12, 0x34, 0xD1, 0xDF, 0xA0, 0x30, 0x7E, 0xF6, 0xA1, 0xF8, 0xE2, 0x4F, 0x23, 0xF8, 0xC4, + 0xA5, 0x71, 0x80, 0xE7, 0x7F, 0xBB, 0x1C, 0x9D, 0xFF, 0x5D, 0x8D, 0xDC, 0xC6, 0x49, 0x7D, 0xC8, + 0x13, 0xA2, 0x86, 0x7A, 0x61, 0xBB, 0xD3, 0xF7, 0xCA, 0xAC, 0xAF, 0xB6, 0x17, 0x79, 0xF9, 0xE6, + 0x96, 0x72, 0xFB, 0xB8, 0x83, 0x4C, 0xF9, 0x44, 0xB9, 0xF0, 0xD8, 0xF1, 0x5E, 0xA8, 0xD3, 0xC6, + 0xEF, 0xD8, 0x40, 0x63, 0xF9, 0xAC, 0x68, 0x2F, 0x17, 0xCA, 0x71, 0x8A, 0xF1, 0x4A, 0x69, 0xBA, + 0x34, 0x6A, 0xA5, 0x4B, 0xBE, 0x4F, 0x16, 0x60, 0x25, 0xFF, 0xAC, 0xA3, 0x76, 0xB2, 0x07, 0x19, + 0x86, 0x97, 0xAE, 0x37, 0x62, 0x79, 0x39, 0x8F, 0x3C, 0xEF, 0xB8, 0xFB, 0x64, 0xC9, 0x50, 0xF6, + 0x38, 0x57, 0x7A, 0x1A, 0x0E, 0x97, 0x60, 0x49, 0x13, 0x22, 0x21, 0x15, 0xC4, 0x14, 0x42, 0x0D, + 0xFC, 0x00, 0x92, 0x89, 0xAA, 0xBD, 0x00, 0x5D, 0xF0, 0x0C, 0xC2, 0x32, 0xD9, 0xCD, 0x9D, 0x31, + 0x4B, 0xF0, 0x94, 0x3A, 0xD2, 0x3C, 0xBF, 0x92, 0xC3, 0x79, 0xAC, 0x19, 0xB9, 0x18, 0x9A, 0x58, + 0x4C, 0xAD, 0x1A, 0x84, 0x85, 0x21, 0x6F, 0x02, 0x1F, 0xB4, 0x2D, 0x38, 0x39, 0xFE, 0xAD, 0xD5, + 0x6C, 0xB5, 0x4F, 0xE3, 0x9A, 0xD9, 0x08, 0x10, 0x7C, 0x7D, 0xE2, 0xD9, 0x78, 0xF4, 0x28, 0x57, + 0x99, 0xC8, 0x06, 0xE0, 0x58, 0x54, 0x85, 0x9A, 0xA1, 0x87, 0x4E, 0x02, 0xA7, 0x4F, 0x64, 0xDA, + 0x5A, 0x73, 0xFC, 0x6C, 0xB2, 0xF8, 0x6F, 0xA6, 0xFC, 0x67, 0xE1, 0x64, 0xB2, 0xA2, 0xDB, 0x41, + 0x1B, 0xEA, 0x21, 0xE4, 0x4A, 0x24, 0x11, 0xB6, 0xB1, 0xF3, 0x51, 0x6E, 0x81, 0xF8, 0x42, 0xA9, + 0xC2, 0xF6, 0x37, 0x3E, 0xB6, 0xDC, 0xAB, 0x15, 0x2F, 0x7E, 0x23, 0x72, 0xFE, 0x8A, 0xD7, 0x8C, + 0xDF, 0x11, 0xB8, 0xA0, 0xAF, 0x57, 0x28, 0xE6, 0xF8, 0x79, 0x89, 0x94, 0x36, 0x15, 0xD9, 0x08, + 0x7B, 0xFB, 0xDA, 0x1C, 0x88, 0xAC, 0x2A, 0xDA, 0xE4, 0xE2, 0x14, 0x51, 0x1C, 0x3F, 0x79, 0xDE, + 0xD9, 0x02, 0x51, 0xEE, 0xE0, 0x80, 0x4C, 0xCE, 0x6D, 0xD0, 0xDB, 0x58, 0x77, 0x72, 0x42, 0x91, + 0x08, 0x13, 0x7A, 0x69, 0xFD, 0xDA, 0x9E, 0x97, 0xEF, 0x9C, 0xA4, 0x76, 0x18, 0x21, 0x9B, 0x1E, + 0xCA, 0xAC, 0xBD, 0x69, 0xBE, 0xE2, 0x00, 0xD7, 0x77, 0xCC, 0x3D, 0x5C, 0xED, 0xB7, 0x35, 0x3D, + 0x42, 0x57, 0xED, 0xC7, 0x3D, 0xB7, 0xC3, 0xC0, 0x0B, 0x0E, 0x12, 0xC0, 0xEA, 0x26, 0xB0, 0xB6, + 0x31, 0x3B, 0xAD, 0x0A, 0xDD, 0x1E, 0xE7, 0xFB, 0x33, 0x6C, 0x6F, 0x7A, 0x45, 0xCC, 0x1D, 0x37, + 0x88, 0x47, 0x7F, 0x67, 0xFA, 0x81, 0x02, 0x98, 0xD4, 0x54, 0x11, 0xFD, 0x9A, 0x5E, 0x46, 0x28, + 0xF6, 0xE5, 0xF3, 0x8A, 0x9B, 0x8B, 0xCB, 0x65, 0x03, 0x43, 0xDB, 0xD9, 0xD5, 0x60, 0xDF, 0x1C, + 0xFC, 0x30, 0x44, 0xDB, 0x9B, 0xE8, 0x86, 0x45, 0xB7, 0x69, 0x18, 0x21, 0x14, 0xE7, 0xD2, 0x7E, + 0xF8, 0x24, 0x0D, 0x4A, 0x73, 0xF7, 0xCE, 0x59, 0x41, 0x46, 0xC4, 0x89, 0xF8, 0x0D, 0xCE, 0xC8, + 0x5E, 0x9D, 0x18, 0x3A, 0x57, 0xE0, 0x08, 0x07, 0x55, 0x79, 0x1A, 0xEB, 0x25, 0x0C, 0xB3, 0x97, + 0x96, 0xA4, 0x6D, 0x74, 0x31, 0xEA, 0xD3, 0x44, 0xB3, 0x11, 0x9A, 0x31, 0xCB, 0xA6, 0xB4, 0x8A, + 0x3B, 0x6F, 0xFB, 0xE6, 0x50, 0xA8, 0xB3, 0x7D, 0xC6, 0x5C, 0xEB, 0xA5, 0xFA, 0x49, 0x3F, 0xD4, + 0x86, 0x34, 0x30, 0x6B, 0x92, 0xBA, 0x26, 0x66, 0xD2, 0x5A, 0xC9, 0xA8, 0xAC, 0x9D, 0x06, 0x76, + 0x69, 0x0C, 0x3D, 0x8D, 0x87, 0xB1, 0xEA, 0xC9, 0x69, 0xB2, 0x41, 0xA4, 0xA7, 0xDA, 0xE7, 0x69, + 0x17, 0x53, 0xB7, 0x7A, 0x6F, 0xF5, 0xDA, 0x59, 0x67, 0xB5, 0xC0, 0xD4, 0x5F, 0x28, 0x3A, 0x31, + 0x20, 0x38, 0xFD, 0xB6, 0xFE, 0x5A, 0x2A, 0xB0, 0x2B, 0x45, 0x1C, 0x8A, 0xAC, 0x92, 0x1B, 0x5D, + 0xB8, 0x14, 0x95, 0xAE, 0xD7, 0xBB, 0xB9, 0xCE, 0xDE, 0xFD, 0xB8, 0xB0, 0x50, 0xD0, 0x64, 0xCE, + 0x75, 0x2E, 0x4E, 0x51, 0x28, 0x8F, 0xEB, 0xF7, 0xEC, 0x70, 0x75, 0x60, 0x0F, 0x72, 0xD3, 0x16, + 0x9B, 0x90, 0x02, 0x8B, 0xC9, 0xBA, 0x29, 0x99, 0x2B, 0xB4, 0xD9, 0xAE, 0xCD, 0x0B, 0xC1, 0xD6, + 0xA3, 0x3E, 0x96, 0x8C, 0x3F, 0x58, 0x4C, 0xED, 0xB2, 0x89, 0x14, 0x51, 0xCB, 0xA4, 0x75, 0x26, + 0x49, 0xA8, 0x4F, 0xA8, 0xFB, 0xA4, 0x7C, 0x5E, 0x06, 0xA5, 0xF5, 0x64, 0x02, 0x15, 0x39, 0x20, + 0xA9, 0x98, 0x8E, 0x5E, 0xB5, 0xF4, 0x9F, 0xF9, 0xE5, 0x5C, 0x27, 0xB2, 0xA8, 0x7E, 0xA7, 0xA9, + 0xE0, 0x20, 0xCA, 0x9C, 0xC9, 0x96, 0x61, 0x2F, 0xC3, 0x65, 0x46, 0x93, 0x83, 0xF3, 0x84, 0x1C, + 0xF4, 0xE9, 0xA2, 0xC3, 0xC3, 0x31, 0xC7, 0x29, 0xDB, 0xB6, 0x59, 0xB0, 0xE0, 0xEE, 0xD0, 0x7C, + 0x51, 0x67, 0xA5, 0x43, 0xA4, 0xE4, 0x26, 0x1A, 0xB2, 0x0A, 0xFE, 0x5D, 0x70, 0x91, 0x29, 0x64, + 0x4D, 0xD3, 0x6D, 0x53, 0x9B, 0xC6, 0xE8, 0xB9, 0xF2, 0xE8, 0x7C, 0x50, 0x0D, 0x74, 0x88, 0x0C, + 0x6B, 0x33, 0xE3, 0x66, 0x48, 0x01, 0xE0, 0x70, 0x18, 0x37, 0xD9, 0x73, 0x29, 0x6B, 0x95, 0x42, + 0x20, 0x3D, 0xE7, 0x81, 0xB4, 0xF9, 0x39, 0xEF, 0xD2, 0xD6, 0xD4, 0xBE, 0xBC, 0x2B, 0x38, 0x52, + 0x50, 0x82, 0xA5, 0x0D, 0x53, 0x3E, 0x2A, 0x82, 0xF6, 0xB8, 0x0A, 0x78, 0x28, 0x41, 0x16, 0x8B, + 0x38, 0x1A, 0xDC, 0x6F, 0x91, 0x61, 0x5A, 0x59, 0x3D, 0xB0, 0xB1, 0x91, 0x27, 0x7F, 0xAD, 0x4F, + 0xD4, 0x71, 0x3A, 0xD0, 0xD6, 0x6A, 0xAA, 0x81, 0xEA, 0x50, 0x80, 0xA2, 0xEE, 0xAA, 0x4C, 0xD4, + 0x8B, 0xB1, 0x40, 0x9D, 0xAF, 0x7F, 0x62, 0x07, 0xFC, 0xD9, 0xC5, 0x52, 0x29, 0x1C, 0x6F, 0x8E, + 0x9A, 0x85, 0x75, 0x2A, 0x0F, 0x2C, 0xD7, 0x17, 0x82, 0x47, 0xCC, 0x7C, 0x0C, 0xBD, 0x68, 0x44, + 0xD5, 0x4E, 0xF6, 0x49, 0xB4, 0xCB, 0xF2, 0xC8, 0xF1, 0x2E, 0xB1, 0xB1, 0x95, 0x58, 0xAF, 0x20, + 0x05, 0x09, 0xA3, 0x53, 0x93, 0xD7, 0x79, 0xDC, 0x7E, 0xD5, 0x47, 0x68, 0x2C, 0x20, 0x6F, 0xCC, + 0x22, 0x8C, 0xC1, 0x9C, 0x6E, 0xE4, 0xB9, 0xB1, 0xE8, 0xA6, 0x94, 0x6A, 0x84, 0xC8, 0x1B, 0x83, + 0x92, 0x2B, 0x15, 0xEA, 0xF0, 0xCE, 0x6A, 0x8B, 0x30, 0x3C, 0x01, 0x52, 0xFC, 0x3E, 0x58, 0xBD, + 0x0A, 0xAD, 0xCC, 0x98, 0xFB, 0x0B, 0x36, 0xB6, 0xAB, 0x0C, 0x62, 0x46, 0x45, 0x8B, 0xC2, 0x4C, + 0xF3, 0x5B, 0xDF, 0x2C, 0xD1, 0xBC, 0xD4, 0x46, 0xD4, 0x22, 0xE3, 0xE1, 0x71, 0xE3, 0xAE, 0x0D, + 0x0C, 0x89, 0xB9, 0x75, 0x84, 0xE3, 0xDF, 0x3E, 0x4E, 0xE0, 0xA7, 0x1A, 0x0A, 0x4A, 0x3C, 0x6C, + 0x62, 0x0A, 0xBC, 0x0B, 0x22, 0xBE, 0xB2, 0x9F, 0x1E, 0x5F, 0x39, 0x63, 0x10, 0xDC, 0x58, 0xE3, + 0x06, 0xAA, 0xCC, 0x18, 0x25, 0xB9, 0x34, 0xC6, 0x66, 0x74, 0x7C, 0xFC, 0xED, 0xA2, 0x5F, 0x07, + 0x8A, 0x4E, 0x62, 0x3B, 0xCD, 0x66, 0xBD, 0x7E, 0x9E, 0x45, 0x5B, 0xF8, 0x30, 0xDA, 0x20, 0xD7, + 0xA7, 0xE9, 0x8A, 0xE1, 0xF1, 0x13, 0xFD, 0x3B, 0xE2, 0x8A, 0xFF, 0xEF, 0x67, 0xFA, 0xD1, 0x99, + 0xA2, 0x44, 0x3D, 0x24, 0x31, 0xE8, 0x59, 0x57, 0x99, 0x47, 0xE3, 0x60, 0xAA, 0xF8, 0x15, 0x0F, + 0x77, 0x45, 0x3A, 0x91, 0x29, 0xFA, 0xA3, 0xEB, 0xB9, 0xB6, 0x64, 0xD6, 0x51, 0xE4, 0xD2, 0xF4, + 0xEF, 0x93, 0x14, 0x6A, 0xC0, 0x41, 0xFB, 0x78, 0x03, 0x8E, 0x3A, 0xCA, 0x1B, 0xFB, 0xA3, 0x78, + 0x94, 0x81, 0xAC, 0x56, 0xCC, 0x54, 0x15, 0x46, 0xF4, 0x64, 0xA6, 0x9E, 0xCA, 0x43, 0x2D, 0x91, + 0x8F, 0x1F, 0xCF, 0x97, 0xF1, 0xA9, 0x72, 0x63, 0xCC, 0x35, 0x28, 0x51, 0x08, 0x5D, 0x72, 0xEB, + 0x63, 0xF4, 0x21, 0xC5, 0x5C, 0x1D, 0x58, 0x4C, 0x83, 0x22, 0xAD, 0x27, 0xFF, 0x6E, 0x6B, 0x5B, + 0xB8, 0x82, 0xFB, 0xDF, 0x4F, 0x5A, 0x12, 0x6F, 0xF0, 0x3B, 0xF5, 0x7F, 0x82, 0x4D, 0x8E, 0xB7, + 0x6A, 0xC4, 0x0A, 0x3A, 0xA1, 0x09, 0x33, 0x65, 0xAA, 0x59, 0x82, 0xC8, 0xC9, 0x70, 0x2E, 0xF9, + 0x8B, 0x89, 0x2F, 0xAC, 0xB0, 0xFE, 0x29, 0xA2, 0xA7, 0x5D, 0x66, 0xE1, 0x08, 0xE2, 0xE9, 0x8F, + 0x94, 0x37, 0x5A, 0x4F, 0x2D, 0x4F, 0x06, 0x2C, 0x4C, 0x62, 0x4C, 0x09, 0x54, 0x0F, 0x4C, 0xEB, + 0x69, 0x13, 0x39, 0xD0, 0xA6, 0x8B, 0x7E, 0xA4, 0xEB, 0x48, 0x2C, 0xAF, 0xA2, 0x74, 0x9D, 0x80, + 0x6E, 0x48, 0xF6, 0x07, 0xFD, 0x48, 0xBC, 0x55, 0xB8, 0x2B, 0xAC, 0xA0, 0x64, 0x00, 0xC5, 0xDE, + 0xC9, 0x35, 0x34, 0x98, 0x88, 0xF6, 0x3B, 0xC0, 0x95, 0xC9, 0x77, 0x08, 0x5A, 0xC3, 0x3D, 0x39, + 0x1D, 0x60, 0x24, 0x79, 0x99, 0x27, 0xAA, 0x41, 0xF1, 0xDA, 0xA1, 0xD5, 0xF0, 0x5E, 0xD1, 0x04, + 0xD7, 0xD1, 0xBA, 0x71, 0x10, 0x55, 0x9C, 0xF9, 0x61, 0xA9, 0x53, 0x23, 0x67, 0x2E, 0x4D, 0x89, + 0x2B, 0x7F, 0x07, 0x4A, 0x6A, 0x8A, 0x2D, 0xE4, 0x9D, 0xA3, 0x20, 0x0A, 0x1F, 0x6A, 0x1C, 0xB4, + 0xCD, 0x11, 0x7A, 0x60, 0xEB, 0x71, 0xDE, 0x89, 0xFC, 0xEB, 0xBD, 0x33, 0x50, 0xA2, 0x3D, 0x32, + 0x6B, 0xC7, 0x37, 0x1B, 0x0D, 0x76, 0x6A, 0xE6, 0xD7, 0xB9, 0xB3, 0x69, 0x27, 0x14, 0xCD, 0xB3, + 0x73, 0xEE, 0x6F, 0x85, 0xE2, 0xCB, 0x3E, 0x5A, 0xF9, 0x05, 0xD3, 0x0A, 0x9A, 0x84, 0x97, 0xB5, + 0x73, 0x39, 0x89, 0xB4, 0x10, 0x73, 0xAD, 0x34, 0x94, 0x86, 0x56, 0x6C, 0x22, 0x2C, 0x9D, 0xA1, + 0xBC, 0xED, 0x83, 0x29, 0x20, 0x44, 0xE1, 0xCD, 0xAD, 0xDC, 0x00, 0x61, 0xD6, 0xDF, 0xF3, 0x45, + 0xBA, 0x29, 0x97, 0x29, 0xA8, 0xAD, 0xCF, 0x76, 0x7A, 0x60, 0x17, 0x75, 0xED, 0xFE, 0x5F, 0xA2, + 0xC2, 0x2D, 0x7B, 0xA9, 0x22, 0xE9, 0x3B, 0xBE, 0x4F, 0xAB, 0x7C, 0x23, 0xBD, 0xAB, 0x8A, 0x37, + 0x4F, 0x82, 0xFB, 0x7F, 0xE6, 0x28, 0x1E, 0x46, 0x6F, 0xAF, 0x30, 0x58, 0x3A, 0x2A, 0x0C, 0xFC, + 0xCD, 0x87, 0x6C, 0x07, 0xB7, 0x3A, 0xEC, 0x75, 0x5A, 0x50, 0x6F, 0x7B, 0x59, 0x23, 0xAD, 0xB8, + 0xD3, 0xD1, 0xF2, 0x88, 0x89, 0xBD, 0x2F, 0xA5, 0x00, 0x79, 0x21, 0x00, 0x39, 0x39, 0x7B, 0x5A, + 0xA0, 0x36, 0x6B, 0x2A, 0x41, 0xD8, 0x93, 0x8F, 0xFD, 0xA2, 0xCA, 0xF3, 0xCD, 0xEA, 0x37, 0xF4, + 0xC9, 0x63, 0x50, 0xD6, 0x43, 0x4C, 0xDC, 0x10, 0x96, 0x20, 0xC2, 0xE4, 0xE9, 0x62, 0x51, 0x51, + 0xE3, 0x5E, 0x0E, 0x57, 0x4B, 0xA9, 0xA5, 0x43, 0xCB, 0xE6, 0xE8, 0xAC, 0x8E, 0xB0, 0xDA, 0x68, + 0x46, 0xDC, 0xC8, 0x02, 0xE1, 0x1A, 0x9A, 0xFB, 0x5D, 0x5E, 0x84, 0x28, 0xAC, 0xFD, 0xB9, 0x21, + 0x0B, 0xD0, 0x14, 0x3C, 0x80, 0x67, 0xF6, 0x51, 0x3E, 0xC7, 0x1B, 0xB7, 0xFC, 0x08, 0xA3, 0x7E, + 0xB6, 0x80, 0x52, 0xE9, 0x0D, 0x4B, 0x84, 0x21, 0xA7, 0x6B, 0x69, 0x0D, 0x0E, 0x62, 0xDB, 0xEC, + 0xB8, 0x4A, 0x54, 0x43, 0xE3, 0xC6, 0x42, 0x58, 0x3A, 0xDD, 0x0B, 0x94, 0x7E, 0xC0, 0xAC, 0xD9, + 0x51, 0xB5, 0xD9, 0xA3, 0x02, 0x64, 0x6D, 0xA8, 0xAA, 0xA1, 0x38, 0x07, 0x4E, 0x93, 0xAA, 0xC6, + 0xD8, 0x87, 0x63, 0x14, 0xA6, 0xE4, 0x07, 0xC9, 0xE7, 0x37, 0x8F, 0xC8, 0x7D, 0xCD, 0x90, 0xD1, + 0xCF, 0x64, 0x04, 0x0B, 0xF2, 0x74, 0x7A, 0x8D, 0x3C, 0xB2, 0x39, 0x8B, 0x37, 0x76, 0x8F, 0x0F, + 0x99, 0x01, 0xAF, 0xE3, 0xB8, 0x27, 0xA8, 0xA9, 0xB4, 0xB6, 0x10, 0x71, 0xA6, 0x2D, 0x69, 0xD5, + 0xD7, 0x10, 0x72, 0xB3, 0x8F, 0xBB, 0x67, 0xA8, 0x98, 0x12, 0x33, 0x5D, 0x89, 0x4C, 0xE7, 0x30, + 0xA6, 0xF6, 0x1D, 0x19, 0x1F, 0x8D, 0x0E, 0xF4, 0xA1, 0xAA, 0x32, 0x0A, 0x75, 0x48, 0x7A, 0x99, + 0xA8, 0x4D, 0xF5, 0xBA, 0xB8, 0x82, 0x0C, 0xDA, 0xB0, 0x91, 0x7C, 0x4E, 0x3D, 0x57, 0x82, 0x3F, + 0x86, 0xEC, 0xAF, 0x72, 0x16, 0x6C, 0x00, 0xA0, 0xCC, 0x31, 0x1A, 0x1B, 0x4E, 0x29, 0xA5, 0xF4, + 0x60, 0x46, 0x35, 0xC6, 0xE6, 0x80, 0xA0, 0xB4, 0x39, 0xB5, 0x74, 0x9B, 0x64, 0x48, 0xBA, 0x3C, + 0x9C, 0x24, 0xEC, 0x2D, 0x9E, 0xEC, 0x0D, 0xC9, 0x8B, 0x68, 0x58, 0xA7, 0x28, 0x79, 0x7C, 0xC5, + 0x23, 0x99, 0xF1, 0x3B, 0xA9, 0x39, 0xD0, 0xF7, 0x48, 0x4F, 0x94, 0x81, 0x8A, 0x8E, 0x65, 0x71, + 0x30, 0xCF, 0xD9, 0x04, 0x05, 0xE8, 0xFD, 0x85, 0x5F, 0x9C, 0xC7, 0xAC, 0x6C, 0x3A, 0x35, 0xCA, + 0xA3, 0xDA, 0x69, 0x29, 0x1C, 0xC7, 0xD8, 0x98, 0x42, 0x64, 0x74, 0x40, 0x2A, 0x9D, 0xBB, 0x30, + 0xCC, 0xEC, 0x99, 0xFF, 0x4F, 0xF8, 0x5E, 0xFA, 0x0C, 0x0D, 0x95, 0x8D, 0x53, 0xB9, 0x41, 0x26, + 0xB9, 0xFB, 0x42, 0xAA, 0xC7, 0x7C, 0xCD, 0x73, 0x8F, 0xA2, 0x1E, 0x0F, 0xC6, 0xCD, 0x25, 0x36, + 0x48, 0x5B, 0x97, 0x69, 0x6D, 0x53, 0xF4, 0x37, 0x12, 0xA2, 0x4C, 0x59, 0xBF, 0x02, 0xEA, 0xC5, + 0xB4, 0x26, 0x67, 0xFF, 0xFB, 0x57, 0xA8, 0x4D, 0x94, 0x6E, 0xA6, 0x44, 0x50, 0xCF, 0x3E, 0x85, + 0x63, 0x47, 0xE4, 0x91, 0x72, 0xED, 0x77, 0xDC, 0xC8, 0x0F, 0x65, 0x36, 0x4E, 0xF1, 0xEC, 0x83, + 0x84, 0xEF, 0xA9, 0xBD, 0x1A, 0x67, 0x4B, 0x95, 0x7A, 0x3A, 0x51, 0x52, 0xDB, 0x2A, 0x3E, 0x4B, + 0x88, 0x92, 0x47, 0x92, 0x83, 0xFA, 0xE4, 0xA4, 0xA1, 0xB9, 0x1D, 0xB3, 0xB5, 0xF4, 0xA2, 0x93, + 0x56, 0x25, 0xA7, 0xF6, 0xEC, 0x86, 0x80, 0x5F, 0x6E, 0xAF, 0x2B, 0xC4, 0xE9, 0x1F, 0xA7, 0xE3, + 0x6B, 0x96, 0xF0, 0x87, 0x86, 0xB5, 0x34, 0xD2, 0xB8, 0xF0, 0xA2, 0x72, 0x0E, 0x3C, 0xFC, 0x3F, + 0x3A, 0x2F, 0x4D, 0x2A, 0xFA, 0x2A, 0x17, 0x0C, 0xC6, 0x9A, 0x88, 0x3C, 0x3C, 0x8D, 0x36, 0xA0, + 0x0C, 0x5D, 0xDB, 0x50, 0x5C, 0xEE, 0x45, 0x47, 0xD0, 0x3E, 0x82, 0x64, 0x8D, 0x6B, 0x17, 0xE7, + 0xEC, 0xAB, 0xF2, 0xC2, 0xB0, 0x11, 0xEE, 0x25, 0x76, 0xDE, 0x0B, 0xAC, 0x18, 0x90, 0xFF, 0xAA, + 0x91, 0x27, 0xA8, 0xA6, 0x2B, 0x99, 0xDF, 0x9D, 0xE1, 0x7C, 0x3A, 0xF8, 0xF7, 0xB7, 0x85, 0x89, + 0x99, 0xD4, 0x8C, 0x70, 0x64, 0xED, 0x06, 0xC9, 0x76, 0xE6, 0x3D, 0x6E, 0xC0, 0xC8, 0x11, 0xF0, + 0x91, 0x84, 0x4D, 0x20, 0xCB, 0x02, 0x41, 0x76, 0x06, 0xAD, 0xE2, 0xC6, 0xCC, 0x4F, 0xCE, 0x2F, + 0xA4, 0x8B, 0x33, 0x71, 0x2D, 0xC9, 0x07, 0x2D, 0x5B, 0x9A, 0x55, 0xB9, 0xC0, 0x9C, 0x63, 0xDA, + 0x56, 0x57, 0x49, 0xBA, 0x74, 0xBB, 0xFE, 0x8E, 0xC9, 0xB2, 0x1E, 0xCE, 0xB5, 0xA3, 0x7A, 0x6D, + 0xBD, 0x28, 0x30, 0x4D, 0xD3, 0x91, 0x6F, 0x47, 0x7C, 0xD1, 0x61, 0xF8, 0xA6, 0xC5, 0x9F, 0x0B, + 0x13, 0xCD, 0xD5, 0x05, 0x81, 0xFC, 0x95, 0xEE, 0xD3, 0x3C, 0x0D, 0x19, 0x45, 0x4E, 0x0C, 0x31, + 0x6E, 0xBE, 0x7E, 0xB9, 0x4B, 0x2F, 0xA4, 0x4D, 0xBA, 0x94, 0x59, 0x7C, 0x5B, 0xDC, 0xC1, 0x3D, + 0x8B, 0x3A, 0x80, 0x00, 0x00, 0x3D, 0x94, 0x47, 0xA6, 0x0D, 0x95, 0xF7, 0xCD, 0xE4, 0xCF, 0x16, + 0x11, 0x19, 0x4C, 0x3E, 0x35, 0x85, 0x95, 0x1A, 0xC8, 0x3D, 0x15, 0x5D, 0xA6, 0x7F, 0x46, 0x06, + 0x30, 0xAE, 0x61, 0x80, 0x27, 0xAB, 0xD8, 0xF4, 0x03, 0xD8, 0xD5, 0xA3, 0x6C, 0x2A, 0x0F, 0x15, + 0x25, 0x3F, 0xA8, 0xCE, 0xA9, 0x53, 0xF8, 0x6B, 0x4E, 0x4B, 0xE1, 0x08, 0xD1, 0xB0, 0x34, 0xB8, + 0x8D, 0xA1, 0xF1, 0x31, 0xFA, 0x03, 0x33, 0xBD, 0x35, 0xDF, 0x52, 0xE8, 0x9E, 0x77, 0xB0, 0x48, + 0xEB, 0xD5, 0xF0, 0x59, 0x62, 0x3D, 0x14, 0x5C, 0xF2, 0x59, 0xD0, 0xC0, 0xDA, 0x4F, 0x29, 0x3F, + 0x42, 0x38, 0x06, 0xB3, 0x78, 0xBB, 0xCC, 0xD9, 0x37, 0x7F, 0x83, 0x4E, 0xEE, 0x7A, 0xB8, 0x34, + 0x55, 0x51, 0xBE, 0xFB, 0x74, 0x10, 0xEC, 0x7F, 0x33, 0x17, 0xDD, 0xF1, 0x8C, 0xF3, 0xFE, 0xA7, + 0x49, 0x8A, 0x81, 0xF2, 0x08, 0x9D, 0xDC, 0x47, 0x9E, 0xDB, 0xAD, 0xD3, 0x45, 0x3B, 0xDC, 0x7D, + 0x2F, 0x5A, 0xAE, 0xB2, 0xAA, 0x90, 0x86, 0x24, 0x8A, 0xAA, 0x63, 0x8D, 0x24, 0x41, 0xFC, 0xA8, + 0x8C, 0xF1, 0xF1, 0x11, 0x5A, 0xCA, 0x82, 0x6E, 0xCF, 0x9B, 0x2D, 0x2D, 0x15, 0xA3, 0x29, 0xE4, + 0xBA, 0x25, 0xD8, 0x0C, 0x3F, 0x38, 0xCC, 0x8A, 0xBF, 0x43, 0xD8, 0x8B, 0x31, 0xFC, 0xFB, 0x57, + 0xA1, 0xD9, 0x56, 0xEE, 0x1F, 0xE7, 0xD3, 0x77, 0xFB, 0xB9, 0x1C, 0xBC, 0x4A, 0x31, 0x88, 0xE1, + 0x29, 0x51, 0xA4, 0x5A, 0x15, 0xF2, 0x66, 0xF0, 0x76, 0xA4, 0x77, 0xAA, 0x7E, 0x4D, 0xD4, 0xB7, + 0x2C, 0x82, 0x37, 0xE7, 0xA0, 0x79, 0x4E, 0xBB, 0x4B, 0x75, 0x25, 0x7C, 0x30, 0x56, 0xC8, 0xA4, + 0xDF, 0xF8, 0x29, 0x3C, 0xD1, 0x91, 0x72, 0x88, 0xB0, 0xFB, 0x24, 0xE2, 0x82, 0xCF, 0x6A, 0x0F, + 0x1A, 0x79, 0xC6, 0x46, 0x0B, 0x1F, 0xA8, 0x88, 0x95, 0xD1, 0xB2, 0xD0, 0xE0, 0x5D, 0xE6, 0x42, + 0xB4, 0x22, 0x63, 0x13, 0x17, 0xFC, 0xBE, 0xA7, 0xFF, 0xC9, 0x1D, 0xAC, 0x11, 0x89, 0xA2, 0xD5, + 0x67, 0xC3, 0x61, 0xF8, 0x8C, 0x09, 0x88, 0xF6, 0x1E, 0x2A, 0x65, 0x92, 0x6A, 0x1A, 0x1B, 0x48, + 0xA9, 0x12, 0x4A, 0xF6, 0xFE, 0x38, 0xFC, 0xAA, 0x99, 0x26, 0x5E, 0x21, 0xDC, 0xEE, 0x5D, 0x13, + 0xE1, 0x93, 0xA8, 0xD3, 0x3D, 0x98, 0x2A, 0x8D, 0x04, 0xAF, 0x5F, 0x76, 0xED, 0xE6, 0x8C, 0x93, + 0x42, 0xED, 0x26, 0x8E, 0x4A, 0x8E, 0xFF, 0xB6, 0xED, 0x71, 0xFF, 0x7F, 0x2F, 0xD3, 0x82, 0x25, + 0x34, 0xC9, 0x78, 0xC1, 0x6E, 0x71, 0xDC, 0x8E, 0xD7, 0xFB, 0xFB, 0x90, 0x53, 0x75, 0x93, 0x1E, + 0x21, 0x66, 0x96, 0x6F, 0x1A, 0xC8, 0x6C, 0x4E, 0x1A, 0xA4, 0x8A, 0xEB, 0x64, 0xC1, 0x21, 0xEF, + 0xA6, 0x10, 0x06, 0x1E, 0x3B, 0x88, 0x5B, 0x47, 0x4B, 0x9E, 0xCE, 0xB0, 0xA3, 0xAC, 0x49, 0xD4, + 0xAA, 0x43, 0xF0, 0xC5, 0xB4, 0x24, 0x29, 0xC0, 0xFB, 0xB4, 0x03, 0xD2, 0x79, 0x54, 0x90, 0x02, + 0xCE, 0xB8, 0x10, 0x6B, 0xC0, 0xEE, 0x6E, 0x43, 0xC6, 0x1B, 0x61, 0xB5, 0x64, 0xC3, 0x12, 0x05, + 0xD4, 0xE7, 0x74, 0x8B, 0x1B, 0x1F, 0x8C, 0x13, 0xC7, 0x3F, 0x64, 0x50, 0x7A, 0xA3, 0x07, 0x57, + 0xFC, 0x11, 0x79, 0x13, 0x5C, 0xC8, 0xC0, 0x41, 0xEA, 0x75, 0xFA, 0x0C, 0x3E, 0x90, 0x7A, 0x36, + 0xB8, 0x6B, 0x9D, 0x37, 0xED, 0x7F, 0xE1, 0x4F, 0x12, 0xCD, 0x87, 0x15, 0x69, 0x5E, 0x3E, 0x94, + 0x94, 0xB2, 0xFC, 0x72, 0x0D, 0x04, 0x57, 0xDA, 0x31, 0xD9, 0x3E, 0xEA, 0xD7, 0xA0, 0x6C, 0xB7, + 0xBC, 0x8A, 0xD3, 0x08, 0x7D, 0x12, 0x00, 0x5C, 0x40, 0x66, 0x13, 0x57, 0x6D, 0x41, 0xCD, 0x9E, + 0x8F, 0x39, 0x1F, 0xD1, 0x7E, 0xD2, 0xA3, 0x43, 0x83, 0x48, 0x26, 0x73, 0xA2, 0x80, 0x4E, 0xED, + 0x38, 0xB4, 0x93, 0xE7, 0x19, 0x24, 0xAA, 0x75, 0xF4, 0x4E, 0x48, 0xDB, 0x59, 0x1F, 0x76, 0x32, + 0xF5, 0xF7, 0x9F, 0xB9, 0x44, 0xE2, 0x74, 0x8F, 0xDB, 0xA6, 0x0A, 0x61, 0xC3, 0x2D, 0x5D, 0x6A, + 0x47, 0xDC, 0x23, 0xE1, 0x02, 0x0D, 0x77, 0xAF, 0x25, 0xD8, 0xB8, 0x7C, 0x10, 0xBE, 0xB3, 0x54, + 0x4C, 0xFE, 0x0D, 0x4A, 0xCE, 0x21, 0x19, 0x43, 0x14, 0xE1, 0x13, 0x28, 0x5D, 0x96, 0xCC, 0xF9, + 0xF3, 0x02, 0xEA, 0xE7, 0xA1, 0xAE, 0xA7, 0x40, 0x6D, 0x7B, 0x0E, 0xA8, 0x43, 0x05, 0xC7, 0x47, + 0x97, 0xE8, 0x0C, 0xEC, 0xBD, 0x2F, 0x92, 0xE1, 0x9A, 0x88, 0x65, 0x54, 0xF5, 0x1D, 0xF3, 0xE2, + 0x1D, 0x2D, 0x15, 0xD3, 0x9E, 0xFF, 0x37, 0x4D, 0x87, 0x8C, 0x1C, 0x0B, 0x1F, 0xFF, 0xE7, 0xB5, + 0xA0, 0xF1, 0x86, 0x7A, 0x01, 0x67, 0xAB, 0x98, 0xE7, 0xC1, 0x40, 0x06, 0x83, 0x43, 0x5C, 0x0D, + 0x50, 0xFF, 0xA7, 0xF1, 0xA7, 0x20, 0xDD, 0xFC, 0xDE, 0x33, 0x38, 0x18, 0x87, 0x02, 0x2D, 0x5F, + 0x13, 0xE3, 0xFF, 0x25, 0xE7, 0xF4, 0xD1, 0xF1, 0x98, 0x3C, 0x22, 0x10, 0x2C, 0x4C, 0x66, 0xA8, + 0xDC, 0x5D, 0xBC, 0xE6, 0xE4, 0xCB, 0x84, 0x77, 0x0E, 0x4A, 0xBE, 0xC9, 0xD5, 0x91, 0xEC, 0xA2, + 0x15, 0x51, 0xC6, 0xEC, 0x67, 0x1A, 0x21, 0x7F, 0x1D, 0x47, 0xB3, 0x45, 0x3B, 0xB6, 0x3A, 0x81, + 0x37, 0xA2, 0xC2, 0x31, 0xC0, 0xC3, 0xD3, 0xF0, 0x00, 0x2B, 0x61, 0xB9, 0x6A, 0xD5, 0xBB, 0x96, + 0xF3, 0x08, 0x4B, 0xCC, 0xE7, 0x9B, 0x2C, 0xAA, 0x21, 0x9B, 0xC7, 0x63, 0xF6, 0x24, 0x33, 0x0A, + 0xFD, 0xE0, 0x1E, 0x50, 0xAC, 0x86, 0xF6, 0x35, 0xFE, 0xC2, 0x3F, 0x4A, 0x85, 0xB7, 0x3C, 0xAF, + 0xF5, 0xAF, 0xD4, 0x0B, 0xEE, 0x44, 0x69, 0x44, 0xFA, 0x7F, 0x44, 0x46, 0x84, 0x4F, 0xB1, 0xAA, + 0x0A, 0xCA, 0xBA, 0x00, 0xC6, 0x51, 0x29, 0x64, 0x31, 0x7E, 0xFF, 0xCA, 0x5F, 0x26, 0xFC, 0x86, + 0xA9, 0xF4, 0xDB, 0x50, 0x19, 0x52, 0xBD, 0xDA, 0xDA, 0x36, 0x6E, 0x79, 0xBA, 0x21, 0xC6, 0x16, + 0x8A, 0xBC, 0xAC, 0x9E, 0x3F, 0x55, 0x96, 0x6D, 0x8B, 0xD6, 0xDC, 0x48, 0xF0, 0x1A, 0x43, 0x8A, + 0x29, 0x71, 0x25, 0x39, 0x11, 0xD3, 0x0E, 0x68, 0x7A, 0x87, 0x28, 0x5B, 0xB4, 0x70, 0x46, 0x29, + 0xCD, 0x1F, 0x8E, 0x38, 0xAA, 0xDB, 0xD4, 0xFC, 0x99, 0xDB, 0x8A, 0x40, 0xFC, 0x70, 0xD5, 0xEE, + 0x27, 0xD7, 0x35, 0x86, 0xA1, 0x06, 0xA3, 0x63, 0x33, 0x38, 0x94, 0x63, 0xBD, 0x34, 0xD4, 0x55, + 0x32, 0x5A, 0x97, 0x24, 0x72, 0x64, 0x60, 0xD9, 0x2A, 0x97, 0x8D, 0xC4, 0x19, 0x1C, 0xAD, 0x13, + 0xF8, 0xC1, 0xD4, 0x94, 0x4A, 0x0F, 0x9B, 0x63, 0x5F, 0x59, 0x67, 0x88, 0x48, 0x8D, 0xD3, 0x92, + 0xE1, 0xE3, 0x47, 0x2F, 0x4B, 0xE6, 0xCE, 0x4E, 0x87, 0x30, 0xCB, 0x4C, 0xFB, 0x49, 0x54, 0x1A, + 0x59, 0x2D, 0x18, 0x59, 0xB3, 0xAE, 0xD5, 0xFD, 0xB9, 0x8F, 0x03, 0x36, 0x14, 0x0E, 0x39, 0xAE, + 0x92, 0x9C, 0x04, 0x16, 0xFD, 0x52, 0x20, 0x2F, 0xC8, 0xEA, 0xCF, 0x7D, 0xC7, 0x3A, 0xF8, 0x6D, + 0x86, 0xA3, 0x2A, 0x0F, 0x5E, 0xB6, 0xDA, 0x6C, 0xED, 0xF2, 0x79, 0x32, 0xD7, 0x3C, 0x77, 0x9B, + 0x90, 0xA3, 0x7E, 0x1D, 0x30, 0xDE, 0xD5, 0xEE, 0xA0, 0x96, 0xD5, 0xE4, 0x92, 0xEA, 0x09, 0x3A, + 0x62, 0x00, 0xFC, 0x72, 0x67, 0xDA, 0x60, 0x36, 0x80, 0x38, 0xE6, 0x85, 0xE2, 0x50, 0x0F, 0x49, + 0x60, 0x4A, 0x5F, 0xC4, 0x25, 0xFB, 0x48, 0xBB, 0xB9, 0x50, 0x71, 0x34, 0xA1, 0x37, 0x6D, 0x7C, + 0x50, 0x71, 0x20, 0x35, 0x60, 0x42, 0x33, 0xFB, 0x81, 0xCA, 0xAD, 0x95, 0x36, 0x5A, 0x8E, 0x08, + 0x8B, 0x93, 0x86, 0xC3, 0x9B, 0x28, 0xFD, 0xFB, 0xF7, 0xEF, 0x3E, 0x19, 0xE6, 0x93, 0x29, 0xF9, + 0x2D, 0xA6, 0x69, 0x95, 0xCE, 0x25, 0x4A, 0xAA, 0x32, 0x69, 0xD1, 0xF4, 0x64, 0x16, 0x12, 0x6A, + 0x0C, 0xF7, 0x82, 0xEC, 0x61, 0xEC, 0x3A, 0x0D, 0x8A, 0x16, 0xF4, 0x27, 0x6E, 0x5B, 0xDE, 0xB9, + 0xDD, 0x4F, 0x81, 0x50, 0x03, 0x1C, 0x6F, 0x7A, 0x52, 0xFA, 0xC7, 0x6B, 0x3D, 0x32, 0x23, 0xD5, + 0xE8, 0xF0, 0x15, 0x6B, 0xB5, 0x55, 0xF1, 0x06, 0xFE, 0x85, 0xA5, 0x42, 0x10, 0x10, 0x5C, 0x1C, + 0xDC, 0x98, 0x01, 0x95, 0x49, 0x96, 0x57, 0xFA, 0xE0, 0x32, 0x59, 0xFE, 0x1C, 0x05, 0xB0, 0x3F, + 0x01, 0xFD, 0x86, 0xD6, 0xD3, 0xFE, 0x1B, 0x3A, 0x42, 0x85, 0x4F, 0xB8, 0xB3, 0x5E, 0x11, 0x29, + 0xF9, 0xEB, 0x04, 0x8E, 0x5C, 0xDC, 0x70, 0x37, 0x18, 0xF9, 0x00, 0x1F, 0xB7, 0xC4, 0x16, 0x46, + 0xC1, 0x39, 0xC9, 0xD6, 0x13, 0x66, 0xF9, 0xBB, 0xB5, 0xC1, 0x9D, 0xB5, 0x66, 0xBA, 0x52, 0x2A, + 0xA1, 0xEC, 0x3F, 0x1E, 0x92, 0xDC, 0x0C, 0x91, 0x4D, 0xED, 0xE4, 0x51, 0xB0, 0xF8, 0x92, 0x55, + 0xD1, 0x86, 0xD6, 0x4D, 0xCC, 0x9E, 0x05, 0x28, 0x97, 0xAC, 0x92, 0x4F, 0x46, 0xCE, 0xE9, 0x17, + 0x50, 0x4F, 0x3B, 0x51, 0x09, 0xDC, 0x80, 0x8A, 0xFD, 0xDF, 0x56, 0x66, 0xB4, 0xAF, 0xDC, 0x40, + 0xB8, 0x29, 0x8D, 0xE2, 0xF9, 0x92, 0x18, 0x1D, 0xBC, 0x9E, 0x25, 0xB1, 0x30, 0x94, 0xDB, 0x0B, + 0x5B, 0x8E, 0x4B, 0x68, 0xC1, 0xE7, 0x2E, 0x94, 0x08, 0xD4, 0x9A, 0x2F, 0x39, 0xCE, 0x69, 0xAB, + 0x50, 0x5E, 0x5D, 0x45, 0x8D, 0x14, 0xAE, 0x5D, 0xB7, 0x8A, 0xCA, 0xE1, 0xDF, 0xF6, 0x01, 0xE7, + 0x2B, 0xB4, 0x18, 0xB8, 0xA3, 0xF0, 0xD5, 0x4F, 0xD4, 0xF4, 0x0C, 0x96, 0x5D, 0x3D, 0x9F, 0xEE, + 0x73, 0x12, 0x48, 0xFB, 0xE9, 0xAC, 0x33, 0xDA, 0xD9, 0xA5, 0x1E, 0x2E, 0xEB, 0xDD, 0xEE, 0x0A, + 0x8A, 0x55, 0xD6, 0x80, 0x63, 0x74, 0x6C, 0x44, 0x7B, 0xF6, 0x44, 0x4D, 0x17, 0x2B, 0x67, 0x37, + 0xD2, 0xC7, 0x8A, 0xEB, 0xCB, 0x11, 0x80, 0xF3, 0xFB, 0xBA, 0x46, 0x14, 0xD9, 0x82, 0xE8, 0x1C, + 0x95, 0x28, 0x6B, 0xFF, 0x26, 0xF7, 0x85, 0xD8, 0x82, 0x2A, 0x46, 0x4F, 0x0C, 0xA1, 0x9D, 0xB6, + 0xAA, 0x61, 0xAD, 0x71, 0x1F, 0xF3, 0x4C, 0xDE, 0xE0, 0xE1, 0xAB, 0xCF, 0x97, 0xA9, 0xE0, 0x62, + 0xDC, 0xBD, 0xDE, 0xAD, 0xF3, 0x37, 0x4F, 0x61, 0xAB, 0xB1, 0x85, 0xFD, 0xCE, 0x42, 0x67, 0xAF, + 0x3C, 0x5B, 0xED, 0x71, 0x35, 0xA5, 0x4C, 0x3C, 0x2B, 0x98, 0x18, 0x69, 0xA7, 0x24, 0xBE, 0x25, + 0xFB, 0x6C, 0x88, 0x6A, 0x6D, 0xA4, 0x72, 0x7E, 0xF8, 0x1E, 0x88, 0xA4, 0x20, 0x84, 0x0B, 0x2B, + 0x9C, 0xB0, 0x48, 0x66, 0x82, 0x18, 0xEA, 0x98, 0x49, 0x51, 0x1A, 0xEE, 0x12, 0x17, 0x30, 0xC8, + 0x5A, 0xB8, 0xE3, 0x90, 0x36, 0x35, 0x4D, 0xC1, 0xA1, 0x60, 0x22, 0xE5, 0xC3, 0x07, 0xB8, 0x36, + 0x24, 0x3C, 0x2C, 0x76, 0x2A, 0x60, 0xDC, 0xF5, 0x42, 0xD4, 0x02, 0x3F, 0xCA, 0xCA, 0xA7, 0x86, + 0xD3, 0x7A, 0x38, 0x51, 0x32, 0xA0, 0x0E, 0x7E, 0x22, 0xFC, 0xDB, 0xDD, 0xF8, 0x52, 0x36, 0xDE, + 0xCD, 0x84, 0x30, 0x83, 0xC1, 0x84, 0xDF, 0xDE, 0xEF, 0xF9, 0x99, 0xF6, 0xBC, 0x38, 0x18, 0x15, + 0x99, 0xAD, 0x46, 0x90, 0xD4, 0xFA, 0xEF, 0x8B, 0x63, 0x57, 0x37, 0x12, 0x6C, 0x39, 0x2D, 0xAA, + 0xD5, 0x25, 0x44, 0x51, 0x30, 0xA5, 0xE2, 0x38, 0x21, 0x20, 0x39, 0x31, 0xC3, 0x8D, 0x8C, 0x7F, + 0x54, 0xD1, 0x00, 0x2C, 0x19, 0x70, 0x97, 0xB1, 0xEF, 0x17, 0x1E, 0xED, 0x6E, 0x99, 0xF6, 0xE9, + 0xCC, 0xED, 0x92, 0xC2, 0x45, 0xBB, 0xF5, 0x72, 0x87, 0x65, 0x21, 0xA3, 0x46, 0xBB, 0x43, 0x78, + 0x11, 0x9F, 0xAD, 0x6E, 0xDD, 0xD1, 0xF8, 0x1E, 0x18, 0xA1, 0xB2, 0x80, 0xB8, 0x52, 0x52, 0xBE, + 0xD9, 0xE8, 0xD8, 0xE9, 0xA4, 0x02, 0x24, 0x2F, 0x01, 0x8B, 0x4E, 0x71, 0xC7, 0x27, 0xE8, 0x2B, + 0xD9, 0x71, 0xE5, 0xE4, 0x36, 0x4B, 0x17, 0xBC, 0x55, 0x02, 0xA2, 0x82, 0xCE, 0xD4, 0x33, 0x71, + 0xA2, 0x1F, 0x9F, 0xA9, 0x7F, 0x73, 0x5F, 0x31, 0xC5, 0xBA, 0xB0, 0x31, 0x9A, 0xA5, 0x8F, 0x9E, + 0x81, 0x69, 0xA6, 0x26, 0x32, 0x58, 0xB9, 0x6A, 0x8D, 0xF1, 0xCE, 0xC3, 0x97, 0xE2, 0xEC, 0x0A, + 0x27, 0x21, 0x9C, 0xC6, 0xCD, 0xC2, 0x62, 0xC0, 0x78, 0xB1, 0xDD, 0xCC, 0xD1, 0x19, 0x53, 0x05, + 0x5B, 0x96, 0x62, 0xBB, 0xF8, 0x55, 0x38, 0x71, 0x6D, 0x34, 0x0A, 0x4C, 0x35, 0xA6, 0xBE, 0x91, + 0xEE, 0xFF, 0x4F, 0x81, 0x11, 0xEE, 0x61, 0xA8, 0xDD, 0x0A, 0x8A, 0x31, 0xEC, 0xF5, 0x4C, 0x70, + 0x01, 0x02, 0x01, 0x10, 0x60, 0xF8, 0xB4, 0x2F, 0x74, 0x48, 0xF8, 0xF6, 0x34, 0xE3, 0xC8, 0xEB, + 0x34, 0x5E, 0x4B, 0x44, 0x03, 0x68, 0xE6, 0x6D, 0x56, 0x5D, 0x70, 0x94, 0x57, 0x05, 0x62, 0x43, + 0x22, 0x5A, 0xD5, 0x5C, 0xC6, 0x04, 0xAD, 0xCF, 0x2A, 0x2D, 0x56, 0x9D, 0x86, 0x38, 0x57, 0xA5, + 0x30, 0xDD, 0x4A, 0x41, 0x2B, 0x1A, 0xB2, 0x3D, 0x4C, 0x4A, 0xF3, 0x5C, 0xD0, 0x5C, 0xF2, 0xF7, + 0x1E, 0xE9, 0x18, 0x63, 0x73, 0xF7, 0x69, 0xE8, 0xDD, 0x80, 0xF5, 0x3C, 0x3D, 0xC6, 0x24, 0xCA, + 0xC9, 0x7E, 0x80, 0xBB, 0xDF, 0x17, 0x38, 0x61, 0x37, 0xE2, 0x93, 0xDC, 0x6F, 0x78, 0x7A, 0x63, + 0x0C, 0x93, 0xDC, 0x21, 0xE1, 0xE9, 0x56, 0xA3, 0xE4, 0x81, 0x82, 0x81, 0x69, 0x86, 0x8E, 0xF2, + 0x37, 0xD3, 0xC3, 0x1D, 0x5F, 0x12, 0x46, 0xAC, 0x9B, 0x76, 0xDD, 0xBF, 0x16, 0xA1, 0xD8, 0x0D, + 0xE4, 0x45, 0x13, 0x87, 0xAA, 0xAF, 0x5F, 0x88, 0xF6, 0xAE, 0x2D, 0xC4, 0x46, 0x2B, 0xE3, 0x91, + 0x28, 0x2E, 0x17, 0xAE, 0xB8, 0x3C, 0xB0, 0xCA, 0xA0, 0x4D, 0x85, 0x81, 0xB6, 0x2D, 0x81, 0x04, + 0x8D, 0x13, 0xA9, 0xE4, 0xF1, 0x56, 0xDE, 0x86, 0x24, 0x52, 0x6B, 0x23, 0xD6, 0xC1, 0xD6, 0xA5, + 0xD5, 0x13, 0x42, 0xDF, 0x14, 0x3D, 0x20, 0xEF, 0x18, 0x57, 0xAC, 0xCF, 0x88, 0x28, 0x3F, 0xE2, + 0x40, 0x45, 0xA2, 0xAC, 0x05, 0xCC, 0x37, 0x6D, 0x09, 0x54, 0xA6, 0x75, 0x67, 0x99, 0xBA, 0xFF, + 0x0E, 0x47, 0xB8, 0xC1, 0x3D, 0x4E, 0xFE, 0x0F, 0x4F, 0xEB, 0x48, 0xD1, 0x07, 0x0E, 0xD7, 0xA6, + 0x8F, 0xD1, 0x74, 0x67, 0xA4, 0x35, 0xC8, 0x83, 0x91, 0x5A, 0x47, 0xA7, 0x06, 0xF8, 0xB8, 0x3D, + 0x48, 0x19, 0xF5, 0x32, 0x0E, 0x22, 0xA5, 0xB4, 0x31, 0x20, 0x79, 0x30, 0x19, 0x17, 0x75, 0x50, + 0x7B, 0x3B, 0x12, 0x9C, 0xB1, 0xC5, 0xE8, 0xBC, 0x38, 0xCF, 0x5D, 0x65, 0x26, 0x1C, 0x00, 0xE7, + 0xA1, 0xED, 0x74, 0x6D, 0x08, 0x8F, 0xF6, 0xC5, 0x9E, 0x29, 0x7D, 0xF5, 0x19, 0xC2, 0x48, 0x1C, + 0xE8, 0x2E, 0x6E, 0xC2, 0x2B, 0xE1, 0x98, 0x88, 0xB6, 0x95, 0xF4, 0xA5, 0x3E, 0xFD, 0x1A, 0x97, + 0xFB, 0xAA, 0xB2, 0x7D, 0x3F, 0x16, 0x07, 0x00, 0x44, 0xD1, 0x8D, 0x67, 0x89, 0x4D, 0x5B, 0x1E, + 0x51, 0xFF, 0x1B, 0x46, 0x31, 0x05, 0xFC, 0x73, 0x39, 0x0B, 0xB1, 0x39, 0x70, 0x7E, 0x1A, 0x80, + 0x99, 0x9C, 0x36, 0x00, 0x6D, 0xDD, 0xDE, 0x9A, 0xDB, 0x1C, 0x52, 0x32, 0xDA, 0x62, 0x79, 0xFF, + 0x4A, 0x68, 0xDE, 0x16, 0xC2, 0x83, 0x4E, 0xBC, 0xDA, 0x0F, 0xAB, 0x98, 0xDB, 0xA1, 0x92, 0x96, + 0x57, 0x66, 0x5B, 0x39, 0x96, 0x30, 0x1C, 0xE6, 0x56, 0xB7, 0x34, 0xE8, 0xA1, 0xBF, 0xD1, 0xB0, + 0xDC, 0xCB, 0x5E, 0x09, 0x88, 0xF8, 0x34, 0x2D, 0xEF, 0xC3, 0x67, 0x3C, 0x4F, 0x69, 0x85, 0x97, + 0xDE, 0x03, 0x36, 0xC8, 0xE7, 0x42, 0x8C, 0x03, 0xFA, 0x31, 0x84, 0x95, 0x25, 0xC2, 0x46, 0xA7, + 0x3F, 0xC1, 0x90, 0xEF, 0x85, 0x48, 0x0C, 0xE4, 0xA8, 0x8A, 0x8F, 0x0E, 0x0A, 0x9E, 0x28, 0xCD, + 0x71, 0x3D, 0x57, 0x5F, 0x46, 0xBF, 0x12, 0xEB, 0x18, 0x72, 0x4E, 0x4F, 0x62, 0xAE, 0xFE, 0x4C, + 0xD6, 0xD7, 0x6C, 0x22, 0x00, 0xBE, 0x21, 0xBD, 0xFF, 0x49, 0xDE, 0x3F, 0x6B, 0xBF, 0x8F, 0x02, + 0xF1, 0x63, 0xF0, 0xB4, 0x86, 0x30, 0x0A, 0xF6, 0x94, 0xD9, 0x11, 0xF8, 0xB1, 0x7A, 0x8C, 0x51, + 0x8D, 0x67, 0x4B, 0xE7, 0xCC, 0xC2, 0x06, 0x04, 0xD5, 0x28, 0xD7, 0xCA, 0xF2, 0x0E, 0x87, 0xC0, + 0x71, 0x47, 0x8D, 0x4F, 0xEC, 0x90, 0x23, 0x8C, 0x82, 0x95, 0xAE, 0xAF, 0x32, 0x05, 0x29, 0x32, + 0x22, 0x59, 0x3C, 0x39, 0xC7, 0x50, 0x30, 0x0F, 0x6B, 0x0E, 0x44, 0x34, 0xD9, 0xB2, 0xF3, 0xE3, + 0x53, 0x10, 0x32, 0x0B, 0x6E, 0xF5, 0x58, 0xE7, 0x2E, 0x1A, 0xD5, 0xDB, 0x14, 0x92, 0xAC, 0xF9, + 0x20, 0xC5, 0xE5, 0x91, 0xC5, 0xF2, 0x92, 0x51, 0x19, 0x0D, 0x82, 0xCE, 0xAC, 0xA6, 0x39, 0x6B, + 0x3C, 0xD0, 0x4D, 0x0A, 0x7E, 0xEB, 0x8C, 0x59, 0xCB, 0x9C, 0x1D, 0x47, 0x9D, 0x68, 0x7D, 0x44, + 0xED, 0xD4, 0x07, 0x24, 0x3B, 0x37, 0x3E, 0x38, 0xA9, 0x35, 0xFE, 0x8D, 0x3F, 0xDD, 0xDF, 0x86, + 0xB1, 0xEB, 0xDC, 0xAC, 0x10, 0xA7, 0xBF, 0x78, 0x0A, 0xA0, 0x20, 0x32, 0x0D, 0x45, 0xE0, 0xC2, + 0xF7, 0x96, 0xB2, 0x8A, 0x4C, 0xB0, 0x93, 0x1C, 0x19, 0x91, 0xA7, 0xD6, 0x80, 0x45, 0xE5, 0x39, + 0x54, 0xDB, 0x89, 0xBC, 0xD8, 0xD9, 0xBD, 0x16, 0xC9, 0x0F, 0x02, 0xAA, 0x50, 0x0D, 0xDD, 0x74, + 0xE7, 0xEF, 0x99, 0x8F, 0x0E, 0x42, 0xAF, 0x86, 0xF0, 0x48, 0x7F, 0xB2, 0x54, 0xC6, 0xDD, 0x45, + 0x40, 0x98, 0x15, 0xEA, 0xB0, 0xBA, 0x29, 0x68, 0x3E, 0x76, 0x43, 0x52, 0x18, 0x47, 0x86, 0xC6, + 0xB0, 0x62, 0x2E, 0x8E, 0x42, 0xB0, 0x68, 0x5A, 0xE2, 0xD9, 0x8E, 0x95, 0x0A, 0xEE, 0x7A, 0xFA, + 0x5B, 0x5B, 0x00, 0xE8, 0x5E, 0x97, 0xEC, 0x9B, 0xC3, 0xB1, 0xFD, 0x3A, 0xC3, 0x19, 0x64, 0xF2, + 0x69, 0x28, 0x2C, 0x34, 0x48, 0x34, 0xF6, 0x0A, 0x9B, 0x7E, 0x5B, 0x3A, 0x49, 0x91, 0x25, 0xDE, + 0x5A, 0x02, 0xBC, 0x34, 0x7F, 0x32, 0x65, 0x55, 0x6E, 0x76, 0x4D, 0x61, 0xD6, 0xE9, 0xA7, 0xBC, + 0x80, 0x85, 0x97, 0xA5, 0xA9, 0x07, 0x5C, 0xB8, 0xAD, 0x5C, 0x2D, 0xD7, 0x1F, 0xAA, 0x72, 0x95, + 0xB7, 0x4F, 0x88, 0xA5, 0xAD, 0x85, 0xAF, 0x32, 0x4E, 0x8E, 0xFF, 0x76, 0x37, 0x05, 0x96, 0xEA, + 0xCB, 0x82, 0xFC, 0xAD, 0x18, 0xA0, 0x37, 0x87, 0x20, 0xFF, 0x42, 0xCD, 0x9F, 0x9A, 0x08, 0x56, + 0x22, 0xE5, 0xF6, 0x2E, 0x9F, 0x4B, 0xF8, 0x29, 0x07, 0xD4, 0x16, 0xD6, 0x5B, 0xF0, 0xF8, 0xE7, + 0x91, 0x1D, 0x2A, 0x51, 0xDC, 0x17, 0x73, 0xBA, 0x0B, 0xB8, 0xFD, 0x60, 0xF4, 0xB2, 0x53, 0x33, + 0xD7, 0x17, 0xDC, 0x30, 0x45, 0x74, 0xBB, 0xCB, 0xED, 0x00, 0x0A, 0x6C, 0xBF, 0x18, 0xEE, 0x28, + 0xB0, 0x16, 0x71, 0x8B, 0x8B, 0x6D, 0xEE, 0x0C, 0xC0, 0xF7, 0x3E, 0x4E, 0x92, 0xD8, 0x10, 0x89, + 0x22, 0x5B, 0x07, 0xD0, 0xB6, 0xE2, 0x11, 0x4D, 0xBE, 0x27, 0xF6, 0x0A, 0x6C, 0xE3, 0x50, 0xA6, + 0x40, 0xBA, 0xDC, 0x56, 0x50, 0x5B, 0x30, 0x47, 0x45, 0x1F, 0x6C, 0xF6, 0xC1, 0xB4, 0xC8, 0xB9, + 0xC2, 0xFD, 0x95, 0x2D, 0x2A, 0x73, 0x28, 0xAB, 0x23, 0x37, 0xB2, 0xE1, 0xC2, 0x86, 0xED, 0x70, + 0x8A, 0xE3, 0xF1, 0x4D, 0x99, 0x8C, 0x71, 0xFB, 0xD7, 0x3D, 0x4B, 0x54, 0x89, 0x7D, 0x00, 0xB0, + 0x66, 0x82, 0xA2, 0xEC, 0x1D, 0x67, 0x65, 0x2C, 0xD2, 0x2B, 0xF9, 0xA7, 0x26, 0x04, 0x9E, 0x49, + 0xC8, 0x1D, 0xF7, 0x34, 0x90, 0x0D, 0x4D, 0x9F, 0xCA, 0xB0, 0x0D, 0x0E, 0x3B, 0x2E, 0x11, 0x61, + 0xE7, 0x5F, 0x73, 0x3E, 0x92, 0x6C, 0xB5, 0x86, 0xE3, 0xDC, 0x4F, 0x52, 0xFC, 0x8C, 0x6E, 0x97, + 0xD0, 0x75, 0xB1, 0xE6, 0x91, 0xF5, 0xD3, 0x10, 0x61, 0x0F, 0x2D, 0x12, 0xAC, 0x9C, 0x6A, 0x31, + 0xC9, 0x49, 0xA8, 0xC2, 0x2E, 0x52, 0xC3, 0x29, 0xA5, 0xC6, 0x64, 0x54, 0x52, 0x76, 0x16, 0xEE, + 0x4E, 0xD0, 0x67, 0x0D, 0x32, 0xEE, 0x52, 0x1E, 0xF6, 0x46, 0x16, 0x89, 0x54, 0xD7, 0x8A, 0x0A, + 0x3F, 0x98, 0x94, 0x9B, 0xAF, 0xFF, 0x06, 0xA7, 0x7F, 0x31, 0xF5, 0x55, 0x6F, 0xE9, 0x92, 0xF6, + 0xA0, 0x10, 0x9B, 0xCD, 0xD2, 0x9B, 0xF7, 0xF4, 0x70, 0xAF, 0xC7, 0x56, 0xB0, 0xE1, 0x54, 0xC6, + 0x62, 0x1E, 0x24, 0x42, 0x78, 0xC5, 0xF1, 0x67, 0x13, 0x81, 0x0B, 0x41, 0xA3, 0x10, 0x8B, 0x34, + 0xD5, 0x60, 0xC2, 0xC4, 0xA2, 0x7A, 0xB8, 0x81, 0x04, 0x90, 0x32, 0x85, 0x9A, 0x01, 0xCA, 0x79, + 0xC5, 0x79, 0xA3, 0x6F, 0xFD, 0x5D, 0xF5, 0xBB, 0x20, 0x86, 0xDB, 0xB2, 0x14, 0x32, 0x24, 0x7E, + 0xEB, 0xEE, 0xF7, 0x05, 0x1B, 0xB4, 0x37, 0x18, 0x8D, 0xCF, 0x25, 0xC4, 0x0B, 0x68, 0xCB, 0xF9, + 0xC7, 0xD8, 0x73, 0xFF, 0xF9, 0x7A, 0x99, 0x24, 0xC5, 0x1C, 0x0F, 0xEA, 0x84, 0xEC, 0x05, 0x1B, + 0xAB, 0x71, 0x50, 0xDA, 0xF4, 0x20, 0x1E, 0x01, 0xCD, 0x21, 0x87, 0x50, 0x76, 0xEA, 0x13, 0xA0, + 0x21, 0x6D, 0xA1, 0xD7, 0xE3, 0x09, 0x36, 0x73, 0xF0, 0xA3, 0xA1, 0x21, 0xAE, 0x73, 0x12, 0xB9, + 0xC6, 0x11, 0xF4, 0x5B, 0xCB, 0x25, 0x64, 0x59, 0xF3, 0x6F, 0xE7, 0x60, 0x2D, 0xCC, 0x04, 0xBD, + 0x92, 0xB0, 0xFA, 0x63, 0x3C, 0x66, 0xA8, 0xC4, 0x91, 0x96, 0x41, 0x19, 0x58, 0x8F, 0xF1, 0xC1, + 0x01, 0x2F, 0x70, 0x93, 0x68, 0xC7, 0xFB, 0x23, 0xED, 0x70, 0x39, 0xE0, 0x7D, 0x36, 0xE7, 0xE5, + 0x4B, 0x00, 0xD4, 0xC7, 0xE5, 0x81, 0xA4, 0xFC, 0x9F, 0x89, 0xD6, 0x9C, 0xC1, 0xA1, 0x24, 0x88, + 0x59, 0x93, 0xAC, 0xBC, 0xF7, 0x54, 0xD1, 0x9F, 0xE5, 0x19, 0xF9, 0x8C, 0xE6, 0xE6, 0x4E, 0xD5, + 0x3F, 0xF3, 0xD7, 0xEE, 0xF8, 0x84, 0x8D, 0x2D, 0x41, 0x0F, 0xBE, 0x8F, 0xC0, 0xB2, 0x6F, 0x89, + 0xDE, 0xDA, 0x23, 0xE7, 0x1F, 0x35, 0x71, 0x52, 0x76, 0xAF, 0x3A, 0x8B, 0x49, 0xCD, 0xDD, 0x4C, + 0x8B, 0xAD, 0xB5, 0x7A, 0xA4, 0x01, 0x8C, 0x79, 0x15, 0xA9, 0x0D, 0x0A, 0xE8, 0x02, 0x29, 0x81, + 0x47, 0xF2, 0xF1, 0x6F, 0x26, 0xC2, 0xBC, 0xB4, 0x97, 0xEC, 0xCD, 0x3F, 0xF1, 0x2F, 0x3A, 0x35, + 0xD1, 0xA5, 0x41, 0xC5, 0xC9, 0x6B, 0xAE, 0x29, 0x92, 0xAE, 0x84, 0xD6, 0xCF, 0x16, 0x80, 0xD3, + 0xBC, 0x1B, 0xE0, 0x19, 0x4C, 0x15, 0x54, 0x4E, 0x13, 0x68, 0x07, 0xF2, 0xB2, 0xA7, 0x22, 0x64, + 0xAB, 0x2B, 0xEC, 0x93, 0x51, 0xB3, 0xF8, 0x58, 0x76, 0x66, 0xD3, 0xE7, 0x40, 0xAF, 0x09, 0x6E, + 0xE1, 0x14, 0xC7, 0xAE, 0xCB, 0x20, 0xA5, 0xF0, 0x44, 0x05, 0x4B, 0x3E, 0x4F, 0xA0, 0x6A, 0x19, + 0x35, 0x89, 0xE0, 0x72, 0x64, 0x5C, 0x38, 0xC6, 0xA0, 0xA4, 0x36, 0x5F, 0xDA, 0xD0, 0xE5, 0xC1, + 0xFA, 0xAF, 0xF7, 0x6D, 0x94, 0x80, 0xFA, 0x19, 0xEE, 0xFF, 0xC8, 0x2D, 0x3A, 0x21, 0x1A, 0xDD, + 0x69, 0x3E, 0x36, 0xC4, 0x7A, 0x56, 0x8E, 0xE9, 0x7F, 0x23, 0x46, 0x66, 0xA1, 0xCF, 0xCE, 0x24, + 0xB8, 0x6C, 0xCC, 0x3F, 0xF8, 0x47, 0x4A, 0x7C, 0x4D, 0x1A, 0x42, 0x4B, 0x75, 0x7F, 0x2E, 0x09, + 0x57, 0x1D, 0x3D, 0xE5, 0x2D, 0x03, 0x9E, 0x47, 0xC6, 0xB8, 0x1C, 0x99, 0xDC, 0x2E, 0xC7, 0x41, + 0x1B, 0x6B, 0xBB, 0x49, 0x75, 0xA0, 0xB5, 0x67, 0x83, 0x9A, 0xA3, 0xA7, 0xF4, 0x6F, 0x54, 0x5C, + 0xD8, 0xE8, 0x1D, 0xAA, 0xE4, 0x52, 0x4F, 0x0A, 0x61, 0x48, 0x2C, 0x4A, 0x53, 0x64, 0x62, 0x96, + 0x0A, 0xC0, 0x70, 0xAF, 0x67, 0xC2, 0x0A, 0x63, 0x10, 0x80, 0x68, 0x3D, 0xFC, 0xA2, 0xD0, 0x05, + 0x8C, 0xEE, 0x10, 0xFA, 0xC6, 0x72, 0x99, 0x40, 0x86, 0xFD, 0x3D, 0x84, 0x20, 0xD2, 0x38, 0xBD, + 0xAC, 0x6E, 0x65, 0x23, 0x23, 0x35, 0x5D, 0xC5, 0x72, 0x01, 0xDC, 0xF9, 0xB8, 0xC0, 0x91, 0x57, + 0xE8, 0x50, 0xD1, 0x44, 0xE7, 0xD8, 0x4D, 0x1F, 0xDC, 0xDF, 0x10, 0x4D, 0xE7, 0xF4, 0x63, 0x4B, + 0x80, 0xEC, 0x7D, 0xCE, 0xF3, 0xBC, 0xBC, 0x26, 0xFB, 0x82, 0xC2, 0x7F, 0xCC, 0x41, 0x23, 0x04, + 0x0F, 0xC1, 0xFB, 0xF5, 0xBD, 0x49, 0xCD, 0xF5, 0xA5, 0x1E, 0x05, 0xDE, 0x65, 0x6B, 0x7D, 0xFE, + 0x2E, 0x3A, 0x93, 0x6B, 0x52, 0x19, 0xE5, 0xF3, 0x87, 0x47, 0x44, 0xE1, 0xF4, 0xB3, 0xAB, 0x0D, + 0xA1, 0xD6, 0x8B, 0xE9, 0x3C, 0x17, 0x88, 0x01, 0xBE, 0xC8, 0x24, 0x3D, 0x52, 0xD2, 0x1F, 0xF2, + 0x50, 0xE2, 0x93, 0x23, 0xC1, 0xBF, 0x1A, 0x84, 0x98, 0x81, 0xF2, 0x31, 0x4E, 0xBD, 0xA8, 0x70, + 0x8B, 0x3B, 0xB8, 0x6D, 0x2C, 0x57, 0x0A, 0xEE, 0x2C, 0xBE, 0xED, 0xC0, 0xF7, 0x0F, 0xEF, 0xBA, + 0xB5, 0x7B, 0xD0, 0x2F, 0xE2, 0x46, 0x1A, 0x0A, 0xC4, 0x97, 0xB3, 0xB9, 0xF7, 0xEC, 0x76, 0xF8, + 0x8C, 0x60, 0x4C, 0xA6, 0xA4, 0xCC, 0xE5, 0x42, 0x51, 0x9C, 0x3A, 0xBD, 0xCC, 0x22, 0xCF, 0x63, + 0xAE, 0xF1, 0x57, 0xCA, 0x7A, 0x93, 0xAD, 0x6D, 0x8F, 0x64, 0x4A, 0x53, 0x95, 0x55, 0x62, 0x19, + 0x12, 0x92, 0x3C, 0x92, 0x59, 0x47, 0xA2, 0x51, 0x79, 0xFC, 0x00, 0x54, 0x43, 0xE3, 0x71, 0x48, + 0x4C, 0x4F, 0x62, 0x70, 0x80, 0xE5, 0x78, 0x36, 0x32, 0xE8, 0xD6, 0x0A, 0x49, 0xDB, 0x27, 0x93, + 0xDC, 0xF7, 0x6B, 0x71, 0x4A, 0xCF, 0x45, 0x8C, 0x56, 0xE3, 0xB3, 0x8F, 0x46, 0x2F, 0xC8, 0xBD, + 0xB6, 0xC0, 0xEB, 0x08, 0xF5, 0x0E, 0x26, 0x68, 0x36, 0x95, 0x4E, 0x24, 0x16, 0xA0, 0x2B, 0x99, + 0x9A, 0x97, 0x59, 0x89, 0xE9, 0x9A, 0x3D, 0xEA, 0x2D, 0x42, 0xA2, 0x8A, 0xFF, 0xAF, 0xC4, 0x6D, + 0xAB, 0xA5, 0xBF, 0x5D, 0xB9, 0x09, 0x17, 0x07, 0xCC, 0xE6, 0x6C, 0xD1, 0x8A, 0x33, 0xAF, 0x0F, + 0x23, 0x49, 0x90, 0xD7, 0x90, 0xC1, 0x72, 0x3D, 0x19, 0x0A, 0x10, 0x7E, 0xBA, 0xF2, 0x30, 0x36, + 0x14, 0xE1, 0xB1, 0x12, 0x7E, 0xB6, 0x3C, 0x64, 0x5F, 0x1A, 0x37, 0x12, 0xE4, 0x52, 0x28, 0x17, + 0x5D, 0xF2, 0x38, 0x91, 0x4E, 0x1C, 0xAC, 0xD6, 0x76, 0xDA, 0xBA, 0xCA, 0xCA, 0xDC, 0x3B, 0xD2, + 0x92, 0xFD, 0x57, 0xB1, 0x67, 0xF4, 0xE1, 0x21, 0x6F, 0xB2, 0x6D, 0x99, 0xF3, 0x41, 0x9B, 0xB3, + 0xCC, 0x52, 0x3D, 0xDB, 0x54, 0xA7, 0xF3, 0x69, 0xCC, 0xD9, 0x39, 0x3F, 0x7F, 0x51, 0xB7, 0xAF, + 0x24, 0x7B, 0x14, 0x79, 0xB3, 0x4F, 0xDD, 0xD4, 0x5B, 0x2D, 0x8B, 0xE2, 0xB4, 0x07, 0x96, 0x22, + 0xE4, 0x78, 0x16, 0xC2, 0x45, 0x41, 0x58, 0x29, 0x16, 0x44, 0x87, 0x66, 0x62, 0x3B, 0xED, 0xF8, + 0xC9, 0x39, 0xF8, 0xE6, 0x59, 0x3E, 0xA4, 0x82, 0x21, 0x79, 0x06, 0x79, 0xF1, 0xDD, 0x0B, 0xB1, + 0x02, 0xA0, 0x22, 0xF1, 0xF8, 0x97, 0xB0, 0x86, 0x22, 0xAA, 0x4B, 0xF3, 0x82, 0x0D, 0x55, 0xEF, + 0xD4, 0x5F, 0x5B, 0xBF, 0x0F, 0x4C, 0x5C, 0x46, 0x20, 0xC9, 0xD9, 0xDB, 0x15, 0x6F, 0x8A, 0x57, + 0xD3, 0xED, 0x0D, 0x18, 0x5C, 0x90, 0x20, 0x35, 0x29, 0x96, 0xBD, 0x20, 0x54, 0xA9, 0x4F, 0x77, + 0xBB, 0x77, 0xB7, 0x2A, 0xA0, 0xDF, 0x2B, 0xB3, 0x1A, 0x42, 0x91, 0x66, 0x8F, 0x3A, 0x44, 0x9A, + 0xC4, 0x29, 0x68, 0x0D, 0x33, 0xE1, 0xA9, 0x53, 0xA9, 0x2E, 0x41, 0xA0, 0x94, 0xD0, 0x6B, 0x49, + 0x60, 0x48, 0x82, 0x13, 0xC1, 0x8D, 0x7C, 0xBC, 0xF8, 0x87, 0xD7, 0xEE, 0x68, 0x8C, 0x2E, 0x54, + 0x02, 0xB1, 0x0A, 0x15, 0x20, 0x71, 0x03, 0x94, 0x03, 0x00, 0x92, 0x7B, 0x43, 0xF7, 0xEC, 0x06, + 0xA9, 0x7A, 0xB0, 0xCC, 0xF3, 0x2B, 0x25, 0xD7, 0xC3, 0x67, 0x8F, 0x12, 0xAE, 0xCF, 0x63, 0x0C, + 0x42, 0x72, 0x24, 0x63, 0x10, 0x17, 0xC7, 0x4A, 0xFD, 0x14, 0x35, 0xBC, 0xF1, 0x3E, 0x3E, 0x1E, + 0x3F, 0x6A, 0x45, 0xEA, 0x3D, 0x5A, 0xC4, 0xFD, 0x0A, 0xD9, 0x7C, 0x47, 0xE3, 0x7C, 0x2B, 0x6D, + 0xFF, 0xBA, 0x68, 0x5E, 0xD5, 0x30, 0xF5, 0x38, 0x57, 0x58, 0xC7, 0x2F, 0x14, 0x6B, 0xDE, 0x7E, + 0xF6, 0x6C, 0x9B, 0x5C, 0xFC, 0x44, 0xF0, 0xEC, 0x73, 0xB9, 0x15, 0x9E, 0x6E, 0xE9, 0xC4, 0xC8, + 0xDA, 0xBA, 0x52, 0x72, 0x95, 0xD9, 0x47, 0x86, 0xE7, 0x79, 0x0E, 0x57, 0x8E, 0x11, 0xBC, 0xB5, + 0x9A, 0xA0, 0x29, 0xD2, 0x4F, 0xEE, 0x32, 0xAD, 0xBB, 0x8E, 0xE4, 0x66, 0x66, 0x51, 0x67, 0xBE, + 0x85, 0xFA, 0x0B, 0x4C, 0x77, 0x0B, 0x49, 0x24, 0xCA, 0x95, 0xF1, 0x6C, 0x60, 0x26, 0x0C, 0xD4, + 0x1A, 0x56, 0x21, 0x39, 0xA4, 0x51, 0x7F, 0x91, 0x19, 0xB5, 0xE5, 0xF8, 0x92, 0x90, 0x5D, 0xB6, + 0xCD, 0x8D, 0xCF, 0x33, 0x4A, 0xAB, 0x75, 0x2A, 0xA0, 0x1F, 0x3B, 0x66, 0x1D, 0x00, 0x01, 0x15, + 0x7C, 0x71, 0xAC, 0x71, 0x88, 0xBA, 0xA8, 0xCE, 0x04, 0xB6, 0xE3, 0xE1, 0xC2, 0x57, 0x10, 0xEA, + 0xCD, 0xAB, 0x67, 0x3F, 0x5E, 0xBB, 0x92, 0xAF, 0x5D, 0xD7, 0xDF, 0x6A, 0x1D, 0x5F, 0x44, 0x7B, + 0x35, 0xB8, 0xBC, 0xC6, 0x19, 0x22, 0x61, 0xAE, 0x8A, 0x93, 0xFC, 0x4F, 0x66, 0x9E, 0x38, 0xDA, + 0x09, 0xE8, 0xC8, 0xBA, 0x93, 0x88, 0x5E, 0x55, 0x68, 0xA7, 0x4E, 0x89, 0xF3, 0xE5, 0x1C, 0x23, + 0x0D, 0x92, 0x58, 0xAE, 0x17, 0x64, 0x08, 0x85, 0x62, 0xE8, 0xFC, 0xE2, 0x56, 0x4C, 0x57, 0x48, + 0x49, 0x1A, 0xA9, 0x1A, 0x7B, 0x34, 0xBF, 0x5F, 0x89, 0x81, 0x53, 0x8B, 0x14, 0x99, 0xBC, 0xA1, + 0x2F, 0x6B, 0xE7, 0xE5, 0x1A, 0x3F, 0xA9, 0x53, 0x57, 0x96, 0x96, 0xC6, 0x78, 0xF7, 0x44, 0x0C, + 0x4B, 0x54, 0x38, 0xB9, 0x71, 0xFB, 0x9F, 0x48, 0xD6, 0x3C, 0x6D, 0xBD, 0xE6, 0x2A, 0x11, 0xA4, + 0x49, 0x83, 0x8D, 0xE0, 0x14, 0xBD, 0x01, 0x69, 0xB7, 0xF0, 0x38, 0x4D, 0xE9, 0xBE, 0xC1, 0x26, + 0xA6, 0x97, 0x39, 0x45, 0x0E, 0x9F, 0x81, 0x1A, 0xCD, 0x61, 0xF6, 0x77, 0xCA, 0xA1, 0x9B, 0x86, + 0x74, 0x93, 0x4D, 0xC5, 0x34, 0xD5, 0x55, 0x35, 0xCC, 0xD4, 0x97, 0xEA, 0xF0, 0x65, 0xB4, 0x4B, + 0x46, 0xFE, 0x58, 0xED, 0x97, 0x3F, 0xE4, 0xD4, 0xF4, 0xF4, 0x29, 0x22, 0x66, 0xD6, 0xCA, 0x28, + 0xDC, 0xE0, 0x93, 0x9E, 0x31, 0x0D, 0xDC, 0x95, 0x0D, 0x5A, 0x77, 0x18, 0x0D, 0x2E, 0x60, 0xE1, + 0x6F, 0xEE, 0x67, 0xC2, 0xFB, 0x50, 0x01, 0xC5, 0x1A, 0x1A, 0x6C, 0x50, 0x19, 0xF8, 0xCE, 0xE2, + 0xA3, 0x9B, 0x9B, 0xFC, 0x7C, 0x88, 0xE2, 0x7A, 0x38, 0xF8, 0xB1, 0xC5, 0x12, 0x90, 0x5C, 0x1C, + 0x21, 0xEC, 0x41, 0x57, 0xDB, 0x8A, 0x4D, 0x8A, 0x5B, 0xCA, 0x2C, 0x23, 0x7B, 0x6B, 0xBF, 0x2B, + 0xBF, 0x3D, 0x57, 0x5A, 0x63, 0x1F, 0x9C, 0xFC, 0x4C, 0x51, 0xB2, 0x20, 0x52, 0xB6, 0x0F, 0xC9, + 0xAE, 0x01, 0xF0, 0x2F, 0xE1, 0xD6, 0x3F, 0x67, 0x7E, 0x1A, 0x05, 0x04, 0xAE, 0xBC, 0x13, 0xB2, + 0xFA, 0x36, 0x42, 0x69, 0xAF, 0xB8, 0x7F, 0xBF, 0xEE, 0x14, 0xA8, 0x41, 0x7C, 0x60, 0xEB, 0xA9, + 0xA9, 0x30, 0x9C, 0x17, 0x68, 0xFA, 0x3B, 0x54, 0x71, 0xDC, 0x4F, 0xE9, 0x5E, 0xEF, 0xC8, 0x02, + 0xDB, 0x00, 0x7F, 0x6F, 0x49, 0x63, 0x16, 0x3F, 0x3A, 0xE3, 0xD5, 0x36, 0x09, 0x31, 0x70, 0xA2, + 0x2F, 0x40, 0x26, 0x90, 0x94, 0x21, 0x62, 0xAA, 0x6A, 0xDE, 0x15, 0x92, 0x5A, 0x28, 0xEC, 0x7C, + 0x76, 0xF3, 0x76, 0x9F, 0x6A, 0xDE, 0x6C, 0x5D, 0xD1, 0x66, 0x74, 0xE3, 0xA5, 0xCA, 0x87, 0xAD, + 0x9B, 0x5F, 0x41, 0xB9, 0x5F, 0xDB, 0xE3, 0x56, 0x93, 0x9C, 0xB6, 0x5B, 0xBF, 0x07, 0x48, 0xFA, + 0xE2, 0xC1, 0x84, 0xB9, 0x99, 0x46, 0xE0, 0x43, 0x1B, 0x23, 0x14, 0xA6, 0x6F, 0x88, 0xEC, 0xA4, + 0x9C, 0xBA, 0x5D, 0x45, 0xE9, 0x11, 0x5B, 0x51, 0xFB, 0xB1, 0x1E, 0xE5, 0x46, 0x3E, 0x20, 0x67, + 0x72, 0xF0, 0x1E, 0x61, 0xEB, 0x24, 0x01, 0x20, 0xFE, 0x4B, 0xA2, 0x47, 0xF3, 0x14, 0x4F, 0x8D, + 0x4C, 0x67, 0x7D, 0x12, 0xD7, 0x5F, 0xBB, 0xED, 0x14, 0x66, 0xC7, 0x3C, 0x97, 0x80, 0x77, 0xA9, + 0x0D, 0xC3, 0x71, 0x33, 0xEE, 0x6C, 0x71, 0x80, 0xA4, 0x87, 0xA5, 0x81, 0xB3, 0x6C, 0x57, 0x7D, + 0x63, 0xAA, 0xD1, 0x9F, 0x33, 0x51, 0x29, 0x75, 0x06, 0xF6, 0xFE, 0xB9, 0x06, 0x97, 0xCF, 0x44, + 0xD7, 0x33, 0x21, 0x44, 0xF3, 0xA8, 0x81, 0x9F, 0x7E, 0x8D, 0xF0, 0x36, 0xCE, 0x40, 0xDA, 0x76, + 0x99, 0xEF, 0xFB, 0xED, 0xEF, 0xF3, 0x59, 0x6A, 0xA7, 0x67, 0xFA, 0xE1, 0xF5, 0x6C, 0x25, 0x63, + 0x95, 0xD0, 0x07, 0x92, 0x62, 0x1F, 0x09, 0x56, 0x87, 0x8A, 0x21, 0xDD, 0x13, 0x72, 0x36, 0x3F, + 0xC9, 0x45, 0x29, 0x77, 0x44, 0x49, 0x7F, 0x3F, 0x8F, 0x95, 0x55, 0x98, 0x9D, 0x03, 0x8F, 0x7B, + 0x91, 0x66, 0x0E, 0x9E, 0x17, 0x25, 0x94, 0x1C, 0x56, 0xBF, 0x78, 0x5D, 0x22, 0xC2, 0x5A, 0x8F, + 0x0D, 0x5E, 0x5B, 0x05, 0xE1, 0xCF, 0x07, 0x44, 0x09, 0x00, 0x8A, 0xBE, 0xEF, 0x1F, 0xCE, 0x3E, + 0x9A, 0x1E, 0xA5, 0xD1, 0x0C, 0x24, 0x52, 0xDE, 0x7E, 0x71, 0x4F, 0x1E, 0x93, 0x25, 0xAE, 0x03, + 0x59, 0x74, 0x6C, 0xD7, 0x68, 0xB4, 0x9F, 0x67, 0x28, 0x40, 0x54, 0xA3, 0x5E, 0xDE, 0x27, 0xFD, + 0x97, 0xED, 0x48, 0xBB, 0x73, 0x93, 0x0B, 0x6B, 0x1A, 0x4E, 0x51, 0x3F, 0x5F, 0x59, 0x42, 0xD6, + 0x6C, 0xDF, 0x03, 0xE7, 0x90, 0x70, 0x9B, 0x77, 0xE4, 0xB1, 0xEF, 0xA8, 0x5A, 0x10, 0x92, 0xE5, + 0x92, 0x6A, 0x03, 0x6D, 0x38, 0x19, 0xA4, 0xD7, 0xED, 0xA6, 0x92, 0x90, 0xB0, 0x00, 0x5A, 0x63, + 0xFB, 0x7F, 0x5A, 0xA2, 0x27, 0xC6, 0xE9, 0xA8, 0x51, 0x18, 0xFA, 0x70, 0x73, 0x32, 0xA6, 0xAE, + 0x3F, 0xE5, 0x5C, 0x36, 0xB1, 0xEA, 0xA6, 0xFC, 0xDD, 0xBA, 0x0F, 0x52, 0xD2, 0x56, 0xC4, 0x49, + 0xD0, 0xCB, 0xCE, 0x27, 0x87, 0xE9, 0x0B, 0x4C, 0x21, 0x0E, 0x88, 0x18, 0x9A, 0x4C, 0x65, 0x4D, + 0x12, 0x23, 0x45, 0xD6, 0x2D, 0xB4, 0x87, 0x20, 0x47, 0xE2, 0xFD, 0x9B, 0x42, 0xFB, 0x70, 0x17, + 0x3E, 0x30, 0xB1, 0x47, 0xD6, 0x85, 0x67, 0xAE, 0xF1, 0x33, 0xF2, 0x8F, 0xD0, 0xB0, 0xA3, 0xAC, + 0xB1, 0xFA, 0x57, 0xFE, 0x60, 0x3C, 0x40, 0xFC, 0x0A, 0x3B, 0xEE, 0x2E, 0xA8, 0xDB, 0xC0, 0x88, + 0x0F, 0x1C, 0xEF, 0xF9, 0x2A, 0x3A, 0x4A, 0x4C, 0x08, 0x6F, 0x29, 0x15, 0x11, 0x74, 0xB6, 0x9C, + 0xF5, 0xD4, 0x79, 0x38, 0x59, 0xE6, 0xFA, 0x4A, 0x68, 0xED, 0x22, 0xB2, 0xFC, 0x92, 0x87, 0xC6, + 0x81, 0xA8, 0x5B, 0x5E, 0x33, 0x5F, 0xD7, 0x70, 0xC1, 0xF7, 0xA7, 0xFF, 0x7D, 0xBA, 0xFF, 0x2E, + 0x60, 0x55, 0x76, 0xA9, 0x0B, 0xBB, 0x9D, 0xFC, 0xF7, 0x42, 0x97, 0xAC, 0xB6, 0x74, 0x1A, 0xF2, + 0xBE, 0x27, 0xE2, 0xD4, 0x5D, 0x29, 0x59, 0xFB, 0xEE, 0xAB, 0xFB, 0x49, 0xC5, 0xDE, 0x1C, 0x25, + 0x98, 0x32, 0x16, 0x90, 0x0A, 0x6C, 0xCF, 0x5C, 0xD7, 0x08, 0x82, 0x1C, 0x71, 0x33, 0x60, 0x8F, + 0x30, 0xF8, 0x98, 0xF2, 0x9A, 0x12, 0x87, 0xB7, 0xA5, 0x8D, 0xC5, 0x83, 0xAC, 0x20, 0x50, 0x2D, + 0xC3, 0x11, 0x6D, 0x63, 0x06, 0xDF, 0xB0, 0xA1, 0xE2, 0x09, 0x41, 0x92, 0x93, 0x0C, 0x92, 0xBB, + 0xD7, 0xAA, 0x26, 0x3D, 0x89, 0x71, 0x58, 0x72, 0x47, 0x77, 0x2C, 0x4C, 0x08, 0xD5, 0x05, 0x1C, + 0x6D, 0x6D, 0xBE, 0x76, 0x5C, 0x90, 0x9A, 0x8E, 0xD4, 0xC5, 0xC9, 0xCE, 0x59, 0x0A, 0x64, 0x51, + 0xA2, 0x45, 0xB5, 0x0B, 0xEA, 0x63, 0xD6, 0x6D, 0xB5, 0xBD, 0x44, 0xFA, 0x68, 0x16, 0xB0, 0x99, + 0x59, 0xE4, 0x29, 0xB3, 0x53, 0x57, 0x1D, 0xC5, 0x4D, 0x77, 0x3C, 0xFD, 0x3D, 0xFA, 0xC9, 0x1A, + 0x8E, 0x69, 0x90, 0xE7, 0xE6, 0xB9, 0xCE, 0x94, 0xF1, 0x5C, 0xBD, 0xA8, 0x62, 0xFF, 0x2D, 0x71, + 0x67, 0x1C, 0x24, 0x58, 0xAD, 0xC5, 0xAE, 0xA1, 0xD2, 0x80, 0xEC, 0xF9, 0x44, 0x4B, 0xF1, 0x12, + 0x02, 0xE7, 0x59, 0x0F, 0x26, 0x20, 0x51, 0x96, 0xDC, 0x39, 0xF1, 0x5D, 0x2B, 0xC5, 0xB2, 0x3F, + 0xD5, 0x4B, 0x8B, 0x51, 0x70, 0x07, 0xFE, 0xFD, 0xD8, 0x15, 0x4F, 0xE8, 0xA0, 0x29, 0x3A, 0xB7, + 0xB1, 0xBA, 0xE8, 0xF8, 0xFD, 0x98, 0x40, 0x38, 0x3B, 0x23, 0x5E, 0xDB, 0xA5, 0x3A, 0x58, 0x8A, + 0x32, 0x9A, 0xA8, 0xF1, 0xE2, 0x50, 0x7B, 0x54, 0x49, 0xAC, 0x9C, 0x60, 0x24, 0xC8, 0x7E, 0xA0, + 0x79, 0x8F, 0x02, 0x81, 0xAD, 0xDB, 0x5F, 0x71, 0xEA, 0xB3, 0x53, 0xCD, 0xDB, 0x0E, 0x69, 0x68, + 0x74, 0x49, 0x4E, 0x00, 0x9F, 0x02, 0xCE, 0x03, 0x6F, 0xCA, 0x4A, 0x31, 0xFA, 0xAE, 0xB7, 0xAF, + 0xB4, 0x5E, 0x4D, 0x35, 0x91, 0x20, 0xA0, 0xAD, 0x93, 0xE1, 0x9C, 0x88, 0x7E, 0x05, 0xAB, 0xFF, + 0x91, 0x16, 0x87, 0xB9, 0x0E, 0x6D, 0xC5, 0x85, 0x7C, 0xF8, 0xE1, 0x05, 0xF9, 0x35, 0x83, 0x9F, + 0xFA, 0x6D, 0xB1, 0x3D, 0x4E, 0x1F, 0xEF, 0xBD, 0xA6, 0x06, 0x14, 0xE4, 0xD5, 0xBD, 0x82, 0x61, + 0x13, 0x00, 0x94, 0x5E, 0x74, 0xFD, 0x44, 0xD9, 0x5F, 0xA7, 0xC9, 0x2A, 0xE1, 0xAF, 0x78, 0x44, + 0x67, 0x68, 0x15, 0x96, 0xDD, 0x46, 0x92, 0x18, 0xC5, 0x02, 0xC6, 0xEB, 0x8E, 0xC0, 0x4E, 0x62, + 0xE8, 0x2C, 0xD8, 0xA2, 0xFB, 0x54, 0x65, 0x1E, 0xF0, 0x2E, 0x2C, 0x2D, 0x78, 0xA3, 0x43, 0x22, + 0xD8, 0x30, 0xE9, 0x50, 0x23, 0x12, 0xDD, 0x50, 0x62, 0x0E, 0xF9, 0x58, 0x8C, 0xCB, 0xBA, 0x31, + 0x1B, 0x47, 0xB5, 0x60, 0xF3, 0x57, 0x47, 0x26, 0xA5, 0xD2, 0x47, 0x76, 0x4E, 0x84, 0xC8, 0xB6, + 0xA2, 0x08, 0x15, 0x11, 0x82, 0x8C, 0xA2, 0xE8, 0xBC, 0x98, 0x4D, 0x56, 0x87, 0x65, 0xB1, 0x31, + 0x8A, 0x06, 0x16, 0xD3, 0xD4, 0x05, 0xC5, 0xF6, 0xEE, 0xA2, 0x90, 0xC8, 0x11, 0xA8, 0x5B, 0x72, + 0x0F, 0xAE, 0x2B, 0x65, 0x66, 0x52, 0x12, 0x55, 0x2A, 0xB9, 0x99, 0x5B, 0x1C, 0xD4, 0x6D, 0x6A, + 0x6E, 0x25, 0x57, 0x9B, 0x47, 0x41, 0x7F, 0x0E, 0xB3, 0x6B, 0xC0, 0x0B, 0x52, 0xE5, 0xED, 0xE9, + 0x2B, 0x44, 0x35, 0x3D, 0xE5, 0xD1, 0x73, 0x12, 0x20, 0x2B, 0xCA, 0x62, 0x14, 0x99, 0xD6, 0x7D, + 0x22, 0x4B, 0x63, 0xA9, 0xEB, 0x67, 0x2F, 0x89, 0xFA, 0x15, 0x1E, 0x43, 0xFA, 0x6C, 0xEA, 0x64, + 0x45, 0x36, 0xAA, 0x80, 0xFE, 0x6D, 0xD5, 0xC1, 0x20, 0x31, 0x03, 0x0C, 0xFF, 0xAE, 0x13, 0x92, + 0x94, 0x0F, 0xCE, 0x1C, 0x07, 0x90, 0x88, 0x70, 0x6D, 0xD2, 0xF8, 0xC5, 0x86, 0x7A, 0x31, 0x69, + 0xF1, 0x90, 0x55, 0x48, 0x33, 0x57, 0x47, 0x21, 0x5E, 0x28, 0x1C, 0x3B, 0xE8, 0xE7, 0xDA, 0x34, + 0x09, 0xA0, 0x71, 0xB6, 0x97, 0x78, 0x1E, 0x0E, 0x3B, 0xAA, 0x39, 0xC4, 0x49, 0x85, 0xEB, 0x12, + 0xB8, 0xDE, 0xC9, 0xC1, 0x66, 0x60, 0x30, 0xE6, 0x85, 0xCD, 0x4F, 0x8C, 0xC2, 0x38, 0xB6, 0x19, + 0x6D, 0x3D, 0x64, 0x58, 0xD0, 0x57, 0xAD, 0xF2, 0xC9, 0x65, 0x70, 0x9C, 0x09, 0x98, 0xDB, 0xFD, + 0x29, 0xAC, 0xB2, 0x1E, 0x6B, 0xB9, 0x4E, 0x3A, 0xF1, 0x20, 0xBC, 0x04, 0x63, 0x3D, 0x2B, 0xAC, + 0x53, 0x7B, 0x89, 0x01, 0x13, 0xB5, 0xEC, 0x42, 0xF7, 0x2C, 0x27, 0xDA, 0x2D, 0xC2, 0xA7, 0x07, + 0x84, 0xF4, 0x3A, 0x06, 0x5E, 0xEE, 0x0A, 0x0A, 0x4F, 0xA5, 0xAA, 0x42, 0x04, 0xED, 0x28, 0x67, + 0x9B, 0x04, 0x95, 0x00, 0xEB, 0x53, 0x3F, 0xB5, 0xD3, 0x56, 0xCF, 0x0C, 0xAE, 0x95, 0x21, 0x1C, + 0xE4, 0x77, 0x8C, 0xF0, 0x59, 0x23, 0x3D, 0xE3, 0xE1, 0xA2, 0x8B, 0xEA, 0x0B, 0x5D, 0x8D, 0x64, + 0xF7, 0x7A, 0x6B, 0x6D, 0xCD, 0xB8, 0xBA, 0x63, 0x5D, 0x13, 0x30, 0x8D, 0x56, 0xFF, 0x53, 0xAA, + 0x96, 0x2F, 0x74, 0xA4, 0x36, 0x68, 0xF8, 0x3E, 0xC8, 0x79, 0x98, 0xA7, 0xF0, 0x4D, 0x33, 0xF8, + 0xC7, 0x20, 0xED, 0x42, 0x4E, 0xDA, 0x90, 0x58, 0xE7, 0xDB, 0x5A, 0x67, 0xD2, 0x0F, 0x0F, 0xB4, + 0xD5, 0x9F, 0x37, 0x36, 0xE6, 0xAB, 0x4E, 0x3D, 0xFA, 0x79, 0x4A, 0xB4, 0xE3, 0xD1, 0xBB, 0x2B, + 0xD5, 0x84, 0x6B, 0x48, 0x4C, 0xBC, 0xB7, 0xF6, 0xDB, 0xF7, 0x2D, 0x51, 0x45, 0xE4, 0x66, 0x43, + 0x60, 0xB7, 0x28, 0x3F, 0x51, 0x23, 0xB7, 0x14, 0x6D, 0xD5, 0xC0, 0x7E, 0x52, 0xB6, 0x8C, 0xE1, + 0xD8, 0xAF, 0x6F, 0xE9, 0xF3, 0xF7, 0xBC, 0x95, 0x18, 0x5A, 0x24, 0x7C, 0xE5, 0x6F, 0x99, 0x63, + 0x7B, 0xD7, 0xE7, 0x94, 0x42, 0xEE, 0xD8, 0x7D, 0xED, 0xEF, 0x6C, 0xE5, 0x4D, 0x35, 0xC7, 0xFF, + 0x20, 0xE8, 0x89, 0x71, 0xC3, 0xC9, 0xA6, 0x65, 0x7F, 0x36, 0x90, 0xA5, 0xE8, 0x37, 0x85, 0xA4, + 0x4A, 0x0E, 0x14, 0x30, 0x1C, 0x7B, 0x96, 0x38, 0x43, 0xB3, 0xE0, 0x2F, 0xEB, 0x47, 0x58, 0xC0, + 0x57, 0x21, 0x24, 0xCE, 0x7A, 0x32, 0x58, 0xA6, 0xE7, 0xC8, 0xCF, 0xE0, 0x01, 0xB6, 0x6F, 0xDB, + 0x51, 0x47, 0xB8, 0x6E, 0x8C, 0x59, 0xB6, 0xFB, 0x2B, 0x61, 0xA9, 0x4B, 0xA0, 0x61, 0xF5, 0x7C, + 0x7E, 0xA1, 0x3A, 0x0A, 0xC6, 0x39, 0xF3, 0x39, 0xF1, 0xB4, 0x30, 0x5F, 0xCB, 0x72, 0xA9, 0x38, + 0xF2, 0xE2, 0x6B, 0xEE, 0xFD, 0xDB, 0x0A, 0x00, 0x01, 0xA6, 0x1F, 0x76, 0x6C, 0x80, 0x8B, 0xEF, + 0x11, 0xB5, 0xB5, 0xE9, 0x8E, 0x08, 0xDA, 0x25, 0x52, 0xDF, 0x31, 0xB1, 0x2C, 0x1B, 0x87, 0x04, + 0x69, 0x90, 0x3A, 0x75, 0x1D, 0xDD, 0x09, 0x09, 0x7D, 0x0A, 0x55, 0x16, 0x0E, 0xA4, 0x10, 0x84, + 0xFC, 0x3D, 0xA8, 0x58, 0x44, 0x09, 0x62, 0xA1, 0x96, 0x92, 0xDC, 0x77, 0xC7, 0x87, 0x50, 0x18, + 0x99, 0x3C, 0x70, 0x07, 0xA8, 0xD1, 0x8E, 0x65, 0x41, 0xD3, 0x37, 0x10, 0x91, 0x73, 0xD0, 0x43, + 0x56, 0xAF, 0xB4, 0x29, 0x16, 0x3F, 0xF9, 0x64, 0x41, 0x0C, 0x98, 0xF8, 0x01, 0x89, 0xC5, 0xC3, + 0x66, 0x38, 0xA0, 0x42, 0x7D, 0x12, 0x56, 0x01, 0x6B, 0x5F, 0x37, 0x37, 0xE4, 0xE0, 0x48, 0xB5, + 0xB1, 0x79, 0x23, 0xBC, 0x7C, 0xC6, 0x42, 0x90, 0x25, 0xDD, 0xF7, 0x55, 0xA6, 0xAC, 0x7F, 0xEF, + 0x6A, 0x0D, 0x09, 0x30, 0x23, 0x4C, 0xC5, 0x39, 0xED, 0xC3, 0x81, 0xA1, 0x68, 0xB6, 0xEA, 0x98, + 0xE2, 0xA2, 0x72, 0x16, 0x71, 0xCD, 0xC5, 0x20, 0xC6, 0xDC, 0x18, 0xFB, 0x23, 0x35, 0x04, 0xDA, + 0x96, 0xE8, 0x57, 0xCE, 0xA9, 0xD6, 0xB0, 0xFD, 0x9C, 0x58, 0xCE, 0x4B, 0xE2, 0x82, 0x88, 0x82, + 0xAD, 0xDD, 0xAB, 0x29, 0x88, 0x52, 0x0E, 0xC3, 0xFC, 0xCB, 0x83, 0x93, 0x78, 0x23, 0xCF, 0x97, + 0x5F, 0x49, 0x12, 0x92, 0x7B, 0x6B, 0xEA, 0x44, 0x8E, 0x70, 0x81, 0xB6, 0x5A, 0x39, 0x4C, 0xAE, + 0x81, 0x69, 0x45, 0x4C, 0x6D, 0xAE, 0x4C, 0x69, 0x3B, 0x6B, 0x18, 0x8C, 0x2A, 0x66, 0x88, 0xFE, + 0xB2, 0x9A, 0xF7, 0x84, 0x68, 0x0C, 0xCC, 0x7C, 0x3D, 0x4A, 0x8F, 0x74, 0x84, 0x36, 0x8E, 0xDC, + 0xF3, 0xBC, 0x11, 0x59, 0x3B, 0x56, 0xCF, 0x49, 0x11, 0xEC, 0x70, 0x59, 0x7D, 0xFC, 0x96, 0x0F, + 0x67, 0xFD, 0x90, 0x95, 0x40, 0x96, 0x7F, 0x29, 0x7C, 0xD2, 0x68, 0xC5, 0x33, 0x20, 0xA2, 0xF4, + 0x6C, 0x12, 0x2D, 0xC9, 0xD5, 0xAE, 0x10, 0x9A, 0x73, 0x0A, 0xDD, 0x7F, 0x59, 0x60, 0x37, 0x36, + 0x26, 0x0E, 0x80, 0xF8, 0x4C, 0xCD, 0xF2, 0xEB, 0xAA, 0x44, 0x91, 0x22, 0xAF, 0xBD, 0x8E, 0x8B, + 0xE4, 0x09, 0xD0, 0x88, 0x18, 0x69, 0x62, 0xAD, 0x29, 0xAB, 0x93, 0x9C, 0x9B, 0xD7, 0x84, 0x67, + 0x03, 0x78, 0x00, 0x9C, 0x48, 0x25, 0xB5, 0x1A, 0x91, 0x47, 0x77, 0xFE, 0x6D, 0x1D, 0xAB, 0x3A, + 0x7D, 0xA4, 0x8C, 0x4D, 0xA1, 0xF4, 0x52, 0xAA, 0xB1, 0x70, 0x7A, 0x91, 0xA0, 0x22, 0xCC, 0x93, + 0x25, 0x0C, 0xC8, 0x8D, 0xD0, 0x89, 0x50, 0x6F, 0x6A, 0x86, 0x60, 0x6E, 0xD0, 0xFC, 0x6E, 0x57, + 0xB2, 0x71, 0xA1, 0x3B, 0x70, 0x70, 0x4B, 0x4C, 0xE9, 0xC0, 0x50, 0xC8, 0x58, 0x63, 0xAE, 0xEA, + 0xEF, 0x00, 0xBD, 0xA7, 0x42, 0x5C, 0xB9, 0x4A, 0xDD, 0x3C, 0x9B, 0x0C, 0xCF, 0x1B, 0xC3, 0x3E, + 0x8F, 0xAD, 0xE8, 0x0F, 0x75, 0x4E, 0x2C, 0xAE, 0x1F, 0x3B, 0xB6, 0x3E, 0xDD, 0x59, 0xB6, 0x80, + 0xCE, 0x95, 0x86, 0x5A, 0xA8, 0x08, 0x95, 0x69, 0x23, 0xA8, 0x1C, 0x73, 0xBC, 0xFE, 0x2A, 0x38, + 0xA0, 0xC2, 0x81, 0x88, 0xC3, 0x09, 0xB2, 0xA4, 0xBD, 0x16, 0xD8, 0x81, 0x43, 0x5E, 0x92, 0x7D, + 0x08, 0xBF, 0x96, 0xD3, 0xDB, 0xDC, 0xB2, 0x5D, 0x3A, 0xA5, 0xCD, 0x47, 0x7E, 0xFA, 0xDA, 0x88, + 0xED, 0xB8, 0x0E, 0x0E, 0x76, 0x19, 0x42, 0xA6, 0x55, 0x20, 0xF1, 0x1A, 0x17, 0x5A, 0x41, 0x1A, + 0x38, 0x03, 0x70, 0x85, 0xBF, 0x0F, 0x71, 0xAE, 0x1B, 0x2F, 0xCD, 0xDB, 0x0C, 0xAE, 0xA8, 0x30, + 0xB5, 0x9B, 0xA1, 0xEE, 0x45, 0xD2, 0x08, 0x3D, 0x3B, 0x75, 0x34, 0xFD, 0x81, 0xA5, 0x34, 0x87, + 0x27, 0x43, 0x95, 0x08, 0x7B, 0xE5, 0xFF, 0x73, 0xC7, 0x0A, 0x1A, 0x7B, 0x09, 0x9C, 0x4A, 0xDF, + 0x21, 0xBE, 0x38, 0xD3, 0x74, 0x80, 0x55, 0xA6, 0x28, 0xA2, 0x00, 0x5C, 0x04, 0x8E, 0xEE, 0x2F, + 0x16, 0x30, 0xBD, 0xD6, 0xB0, 0x57, 0x68, 0xD3, 0x4B, 0x2D, 0x24, 0x60, 0x67, 0x32, 0x13, 0x10, + 0x5D, 0xCF, 0x09, 0x3F, 0x15, 0x48, 0xA9, 0x99, 0x9B, 0x6C, 0x02, 0xD9, 0xA6, 0x4B, 0xFA, 0xFD, + 0xCD, 0x44, 0x0A, 0x60, 0x70, 0xAE, 0xEE, 0x07, 0xC4, 0xB4, 0xA7, 0xD0, 0x0C, 0x29, 0x15, 0x80, + 0x87, 0x62, 0x02, 0xF4, 0x79, 0x15, 0xF8, 0xA1, 0xF9, 0x78, 0x98, 0x11, 0x72, 0x09, 0xF6, 0x5A, + 0x0D, 0xA4, 0x38, 0x90, 0x87, 0x17, 0xC6, 0xD8, 0x96, 0xA0, 0x1E, 0x20, 0x96, 0x58, 0xAA, 0x1E, + 0x7E, 0xF9, 0x6C, 0x75, 0x95, 0x32, 0xD1, 0x82, 0x67, 0x1E, 0x51, 0xD2, 0x52, 0xA9, 0x2E, 0x35, + 0xD8, 0x59, 0x1E, 0x4A, 0xBA, 0x71, 0x21, 0xA3, 0xA9, 0x95, 0x3C, 0xE8, 0x71, 0x4E, 0xA4, 0x84, + 0x1B, 0x27, 0xD4, 0xFB, 0xFF, 0xFB, 0x16, 0x5C, 0xB4, 0xCF, 0x2B, 0x8F, 0x7C, 0x1C, 0x69, 0xE7, + 0x3F, 0x98, 0x05, 0x34, 0xDA, 0x73, 0x84, 0x00, 0x91, 0x52, 0x7C, 0xB9, 0x03, 0x9D, 0xEA, 0x10, + 0x6D, 0x16, 0xD0, 0x57, 0x69, 0xD2, 0x18, 0xCA, 0x80, 0x05, 0x89, 0x8E, 0x93, 0xD6, 0x28, 0x1A, + 0xEF, 0xB8, 0xA5, 0x66, 0xBC, 0x46, 0x83, 0xBC, 0x15, 0x2B, 0x99, 0xD8, 0xB5, 0x9E, 0x38, 0x93, + 0x4D, 0x18, 0xEB, 0x63, 0x15, 0x6F, 0xFB, 0x24, 0xF9, 0x5C, 0xDD, 0xE9, 0x7B, 0xE1, 0x91, 0x4B, + 0xFB, 0x2D, 0xAC, 0xF2, 0x3A, 0x09, 0x52, 0xDA, 0x54, 0x0E, 0xBC, 0x12, 0x5C, 0x11, 0xFF, 0xE1, + 0x27, 0x96, 0x96, 0x0C, 0x10, 0x7B, 0xC2, 0xCC, 0x48, 0x7C, 0xC9, 0xE8, 0x4C, 0xD0, 0x0E, 0xDA, + 0x3E, 0x57, 0x99, 0x5B, 0x4F, 0x76, 0xAF, 0x8D, 0x8E, 0x9E, 0xB7, 0x94, 0x6A, 0xD1, 0xCB, 0x34, + 0xFC, 0x41, 0x90, 0x5E, 0x68, 0x8E, 0x21, 0x44, 0x8F, 0x69, 0x5B, 0xAD, 0xB6, 0x9E, 0xBE, 0x9C, + 0x51, 0x5D, 0xE5, 0xA2, 0x8E, 0x75, 0x25, 0xFC, 0x27, 0x21, 0x14, 0x9B, 0xAC, 0xB8, 0x48, 0x2B, + 0x99, 0xAE, 0x8D, 0x17, 0x6D, 0x66, 0xEB, 0x08, 0x37, 0x61, 0x46, 0x47, 0x3C, 0x52, 0xCD, 0x94, + 0xEB, 0x58, 0x94, 0xC8, 0xFE, 0xE0, 0xF4, 0xD4, 0xFB, 0xB7, 0x88, 0x83, 0x62, 0xB4, 0xB9, 0x9F, + 0x17, 0x88, 0x94, 0xAA, 0x64, 0x6E, 0x5E, 0xA2, 0xFC, 0x01, 0xD6, 0xB0, 0xDE, 0xE3, 0xCF, 0xBA, + 0xB2, 0xFB, 0x93, 0x39, 0x13, 0xE4, 0x79, 0x9E, 0x2D, 0x7C, 0x68, 0xC8, 0x0B, 0x95, 0xA6, 0x5F, + 0x6D, 0x93, 0x43, 0xAF, 0xFF, 0xD2, 0x2A, 0xA2, 0x1C, 0x22, 0x4C, 0x4B, 0xAF, 0x60, 0x37, 0x3D, + 0xE1, 0xE7, 0xD9, 0x18, 0x6A, 0x6C, 0x75, 0x31, 0xF1, 0x83, 0x67, 0x42, 0x76, 0x94, 0xC9, 0x33, + 0x1C, 0xD0, 0x09, 0x70, 0xE2, 0x92, 0x59, 0x5F, 0xC1, 0x55, 0x13, 0xB6, 0x09, 0xA4, 0x81, 0xFA, + 0xE2, 0x4C, 0x90, 0xE7, 0x29, 0x92, 0x3A, 0x2A, 0xE1, 0x07, 0x9A, 0xE0, 0x34, 0x79, 0x64, 0xED, + 0x1B, 0x65, 0xF6, 0x15, 0x33, 0x20, 0xED, 0xB2, 0x8D, 0x4D, 0xF9, 0x6E, 0x16, 0x14, 0xF7, 0x4A, + 0x87, 0xCF, 0xF8, 0x61, 0x37, 0xC8, 0x48, 0x03, 0xF3, 0x75, 0x9C, 0xA0, 0xC0, 0x75, 0x61, 0x7F, + 0xD7, 0x64, 0x76, 0x16, 0x61, 0xD3, 0xF2, 0x46, 0xE9, 0x4F, 0x31, 0xA2, 0xFF, 0x12, 0xEB, 0xAC, + 0x86, 0x47, 0x2A, 0xBE, 0x27, 0x2E, 0x4E, 0x71, 0xA0, 0xA5, 0x73, 0xBC, 0x9A, 0x24, 0x98, 0x13, + 0xCC, 0x32, 0x52, 0xCB, 0x19, 0xCF, 0x3A, 0xEA, 0xBE, 0x82, 0x5C, 0x4C, 0xF4, 0x30, 0x81, 0x42, + 0x63, 0xC0, 0x1C, 0x27, 0xDE, 0x56, 0x64, 0x9D, 0xDE, 0xDE, 0x58, 0x0F, 0xC0, 0x20, 0xA0, 0x1C, + 0xB9, 0x71, 0x37, 0x38, 0x88, 0xB2, 0x62, 0xCA, 0x80, 0x54, 0x72, 0x64, 0x86, 0x59, 0x5F, 0xD4, + 0x1E, 0x58, 0xF4, 0x09, 0x68, 0x1A, 0x78, 0xFC, 0x94, 0xEF, 0x44, 0x65, 0x2F, 0x42, 0xDC, 0x36, + 0xDF, 0xBA, 0xD0, 0x8B, 0xD6, 0xCB, 0x70, 0xCB, 0x60, 0xB4, 0x9B, 0xBA, 0x2B, 0xF1, 0x14, 0x85, + 0x70, 0xFB, 0x6D, 0x5E, 0x02, 0xE4, 0x5B, 0x2F, 0xEA, 0xAC, 0x3A, 0x2D, 0x44, 0xCC, 0x58, 0x33, + 0x26, 0xEA, 0xFF, 0x0B, 0x0F, 0x06, 0x2D, 0xB1, 0x14, 0x4A, 0x4D, 0x32, 0xDF, 0x40, 0x75, 0x0D, + 0x17, 0x08, 0xE1, 0x7E, 0x6F, 0xE3, 0xAC, 0xED, 0x01, 0x2D, 0xF1, 0x67, 0xE8, 0x33, 0x2C, 0x98, + 0x60, 0xDA, 0x19, 0xE1, 0x3F, 0xBC, 0xE1, 0x72, 0xFC, 0xC6, 0x13, 0xB5, 0x66, 0x24, 0x55, 0x5E, + 0x37, 0x7F, 0xDA, 0x19, 0x7E, 0xD3, 0x3A, 0xF9, 0x7F, 0x0A, 0x37, 0x90, 0x34, 0xB8, 0x59, 0x74, + 0x55, 0xC6, 0xCD, 0xDC, 0xD0, 0xB1, 0x8A, 0x98, 0x2A, 0xC1, 0xFD, 0xA9, 0xC1, 0xA7, 0x76, 0xC8, + 0xE6, 0x5D, 0xCD, 0x70, 0xC1, 0xBA, 0x4A, 0xD3, 0x19, 0x02, 0x2C, 0xA9, 0xB4, 0xFD, 0x63, 0x6C, + 0x3D, 0xCD, 0x88, 0x08, 0xE3, 0xF9, 0x45, 0x89, 0x90, 0xCE, 0xC6, 0x67, 0xFD, 0x54, 0x23, 0x5A, + 0x78, 0x30, 0x5B, 0x56, 0xEC, 0x2F, 0x8F, 0x9A, 0xD8, 0xC5, 0x5D, 0xDB, 0x4C, 0x44, 0x5F, 0x43, + 0x3B, 0xF9, 0xA3, 0xAF, 0x53, 0x36, 0x95, 0x04, 0xFD, 0x19, 0x6B, 0x1C, 0x51, 0x01, 0x94, 0x8E, + 0x98, 0x74, 0x7E, 0x5A, 0x8D, 0x05, 0xFA, 0xC3, 0x51, 0xD5, 0x8D, 0xCB, 0xE9, 0x79, 0x53, 0x89, + 0x7D, 0x37, 0x79, 0xB8, 0xB2, 0xE9, 0xBB, 0x58, 0x58, 0x9B, 0x86, 0x98, 0x3B, 0xA9, 0xED, 0x3B, + 0x3C, 0x39, 0x17, 0x9B, 0x43, 0x09, 0x6C, 0x84, 0x9A, 0xAA, 0x46, 0x2C, 0x2F, 0xA7, 0x8A, 0x93, + 0x97, 0xFB, 0x0D, 0x9B, 0x16, 0x61, 0xFE, 0xA1, 0xDB, 0xDE, 0xF8, 0xC5, 0x75, 0x9E, 0x68, 0x05, + 0x5E, 0xAE, 0x22, 0x91, 0x7B, 0x2B, 0x74, 0xAC, 0xAC, 0xC9, 0xBF, 0x11, 0x0C, 0xCD, 0xCB, 0x17, + 0xA5, 0x85, 0x44, 0xA4, 0xB6, 0x99, 0xB8, 0x00, 0x94, 0x18, 0xF2, 0x8A, 0x80, 0xF5, 0xFC, 0xAB, + 0x19, 0x87, 0x4E, 0xE9, 0x37, 0xD1, 0x48, 0x81, 0x70, 0x8A, 0x91, 0x0B, 0xEB, 0x07, 0x7C, 0x4A, + 0xF0, 0xA6, 0x58, 0x8A, 0x0E, 0x82, 0xBD, 0x64, 0x2D, 0x14, 0xF8, 0x11, 0x67, 0x2F, 0x9F, 0x4B, + 0xE4, 0x65, 0xB2, 0xAE, 0x71, 0xBD, 0xAF, 0x48, 0x67, 0xD5, 0x28, 0x1F, 0x1B, 0x7E, 0x1A, 0x11, + 0xBD, 0x89, 0x8D, 0x22, 0x07, 0xAD, 0xD6, 0x08, 0xC7, 0x37, 0xE9, 0xFB, 0xB5, 0xE1, 0x89, 0x62, + 0x45, 0x1C, 0xB6, 0xEA, 0x44, 0x73, 0x3A, 0x15, 0x1C, 0xF5, 0xBD, 0x7F, 0xF8, 0xAA, 0x02, 0x3E, + 0x36, 0x5E, 0x57, 0xDA, 0x06, 0x8F, 0x97, 0x61, 0x92, 0x0D, 0x8A, 0x7E, 0x24, 0xA0, 0x0F, 0xE8, + 0x7C, 0xFD, 0xA7, 0x27, 0x9C, 0xDD, 0xE1, 0xE8, 0xF5, 0x04, 0x7D, 0xD3, 0x7A, 0xD2, 0x58, 0x80, + 0xF0, 0x37, 0xE6, 0x44, 0x00, 0xB0, 0x6D, 0x06, 0xB8, 0xCF, 0xAD, 0x3B, 0x2D, 0x47, 0xB0, 0x93, + 0x30, 0x70, 0x0E, 0x54, 0x37, 0x47, 0x05, 0xC1, 0xDF, 0x49, 0x90, 0x5A, 0xA1, 0x98, 0x92, 0x23, + 0x76, 0xAA, 0x08, 0x79, 0x20, 0x87, 0xCD, 0xC3, 0x1E, 0x33, 0xF6, 0x38, 0x7C, 0x01, 0xAB, 0x06, + 0x4A, 0x0A, 0x0B, 0xED, 0x05, 0x4A, 0x01, 0x33, 0x95, 0x04, 0x17, 0x4D, 0xE5, 0xD5, 0x1C, 0x36, + 0xFC, 0x8D, 0x6A, 0x5A, 0x3F, 0xB6, 0x56, 0xC6, 0xDB, 0x8E, 0xD5, 0xB5, 0x27, 0xAD, 0x6C, 0x7E, + 0x1F, 0xB5, 0x90, 0xBA, 0xE9, 0xAB, 0x64, 0xD9, 0x77, 0x07, 0xE3, 0xFC, 0x9E, 0x96, 0xB4, 0x1A, + 0xC8, 0xD4, 0xFE, 0x79, 0x7E, 0x8D, 0xDB, 0x07, 0xB4, 0x73, 0xC5, 0x48, 0xCD, 0x7C, 0x17, 0xD3, + 0x67, 0xCC, 0x34, 0x42, 0xE9, 0x34, 0x67, 0x9A, 0xAE, 0xA2, 0x43, 0x80, 0x0E, 0xA8, 0x8D, 0x1C, + 0xAB, 0x91, 0x2A, 0xEC, 0xBD, 0x21, 0x89, 0x5E, 0xF6, 0x6D, 0xF9, 0x6A, 0xE5, 0x2E, 0xFD, 0xAE, + 0xFF, 0x6E, 0xC8, 0x5F, 0xFB, 0x1B, 0x46, 0x96, 0x9A, 0x91, 0x8B, 0x44, 0xC7, 0x7D, 0xD2, 0xF5, + 0x13, 0xF8, 0x88, 0xF1, 0x96, 0xCF, 0x97, 0x89, 0x7F, 0xE9, 0x26, 0xE4, 0x1E, 0xA8, 0x75, 0x73, + 0x8B, 0x83, 0x68, 0x80, 0x4B, 0xF6, 0x44, 0xE9, 0x78, 0x33, 0x8A, 0xA1, 0x8F, 0x0B, 0x3D, 0x78, + 0xC0, 0xCC, 0xF2, 0xA2, 0x28, 0xDE, 0x0C, 0x92, 0x61, 0x05, 0x6B, 0xC0, 0xB1, 0x2B, 0xC6, 0x41, + 0xF4, 0x11, 0x99, 0x86, 0x90, 0x4A, 0xD3, 0x63, 0x28, 0xEC, 0xF5, 0x5C, 0x80, 0x0B, 0x8E, 0xF9, + 0xAB, 0x9C, 0xF6, 0xC3, 0xCA, 0x2F, 0xB2, 0xF2, 0x74, 0x86, 0x2E, 0x0E, 0x4F, 0xE3, 0x0D, 0xBE, + 0xFA, 0x1D, 0x2D, 0x83, 0x99, 0x36, 0x00, 0xCC, 0x25, 0xC0, 0xB4, 0xAF, 0xEA, 0x21, 0x0E, 0x55, + 0x42, 0x3F, 0x75, 0x2E, 0x6D, 0xA2, 0x64, 0x8B, 0x59, 0x11, 0xC5, 0xDC, 0x24, 0xBE, 0x5C, 0x94, + 0x78, 0xD2, 0xD1, 0xC9, 0x15, 0x56, 0xEE, 0xEE, 0x5D, 0xA2, 0x23, 0x9E, 0xFF, 0x99, 0x04, 0x9D, + 0x2F, 0x29, 0x5B, 0xCF, 0xAA, 0x2E, 0xB4, 0x4C, 0x05, 0xFC, 0xAA, 0xBA, 0x64, 0xAD, 0x40, 0xD2, + 0x2B, 0xEF, 0xEB, 0xF0, 0x09, 0x21, 0x60, 0xE6, 0x1D, 0x44, 0xFD, 0x4D, 0x07, 0xA5, 0xE0, 0x94, + 0xBE, 0xA1, 0xB7, 0xB2, 0x48, 0x96, 0xBD, 0x79, 0x4D, 0x0A, 0x18, 0xF3, 0x0A, 0xBE, 0x58, 0x3F, + 0x17, 0x23, 0x03, 0xC1, 0x6F, 0x9C, 0xD7, 0x40, 0x96, 0x77, 0x9A, 0x71, 0x56, 0xA4, 0x6A, 0x1A, + 0x93, 0xA1, 0xB6, 0xDF, 0xAB, 0xBE, 0xD7, 0x01, 0x38, 0xF4, 0xFD, 0x99, 0x14, 0x3D, 0x3D, 0x2E, + 0x5A, 0x9D, 0x6C, 0x02, 0x3C, 0xDF, 0xF1, 0xE7, 0x8D, 0x14, 0x5D, 0x8D, 0xBC, 0x56, 0xE0, 0x45, + 0x92, 0xFA, 0xFD, 0xC0, 0x70, 0x0B, 0xA8, 0x4B, 0xF4, 0xAB, 0x8C, 0x2B, 0xD0, 0x2E, 0x9F, 0xBD, + 0x7F, 0xFF, 0x72, 0x2A, 0x25, 0x47, 0x5C, 0x6A, 0x63, 0x89, 0xC6, 0x8C, 0xA1, 0x99, 0x6D, 0x72, + 0x24, 0xA6, 0xFA, 0x28, 0x85, 0xEA, 0xAE, 0x13, 0x6A, 0xFE, 0xDD, 0xA1, 0x20, 0x52, 0x2E, 0x43, + 0x2F, 0x5C, 0xE4, 0x66, 0x57, 0x78, 0x55, 0xD7, 0x70, 0xA8, 0x17, 0x6B, 0x60, 0xB6, 0x87, 0x02, + 0xC6, 0xC2, 0x4F, 0xE7, 0x32, 0x15, 0xEF, 0xC1, 0xCC, 0x50, 0xB6, 0x1F, 0x96, 0x87, 0xA2, 0x2A, + 0x85, 0x4C, 0x63, 0x02, 0x5A, 0x63, 0xD0, 0x12, 0xAA, 0x74, 0x5A, 0xC1, 0xDD, 0x86, 0xC4, 0x27, + 0x58, 0xE9, 0x53, 0xDE, 0x47, 0x64, 0xE4, 0x27, 0x5F, 0xB5, 0x70, 0xE3, 0x15, 0xEB, 0xDD, 0xDA, + 0x09, 0xD6, 0xE2, 0xBB, 0x8D, 0x70, 0xBB, 0x8A, 0xAD, 0xAD, 0x1B, 0xCF, 0xA7, 0x1B, 0xC3, 0xCF, + 0x98, 0x3C, 0x46, 0xBC, 0x2F, 0xE9, 0x88, 0x35, 0xC1, 0xE1, 0xB8, 0x08, 0xF1, 0x8B, 0xD0, 0x0F, + 0x2B, 0x5E, 0xAC, 0x43, 0x17, 0x62, 0x43, 0x5D, 0x8C, 0x97, 0xEB, 0x72, 0x0D, 0xCA, 0x13, 0xB7, + 0x90, 0xDD, 0x8F, 0x97, 0xF9, 0x11, 0xB9, 0xE4, 0xD2, 0xEF, 0x35, 0xE4, 0x60, 0x65, 0xDF, 0x82, + 0x7A, 0x52, 0xCF, 0x07, 0xB1, 0xCA, 0x33, 0xA5, 0x2A, 0x03, 0xA8, 0x9C, 0xEE, 0x27, 0xE3, 0x94, + 0x97, 0xD0, 0x49, 0xD3, 0x25, 0xEC, 0xC0, 0x11, 0x24, 0xFD, 0x36, 0xAE, 0x51, 0x53, 0x56, 0x61, + 0x2B, 0xA7, 0x4D, 0x7B, 0xD4, 0x70, 0x73, 0x61, 0xCD, 0x48, 0xA2, 0x74, 0xBD, 0x13, 0x54, 0x34, + 0xEA, 0x10, 0x0E, 0x3D, 0xC0, 0x02, 0xBB, 0x18, 0x70, 0x8D, 0x27, 0x58, 0xCE, 0xE2, 0x48, 0x95, + 0xE0, 0xA6, 0xFC, 0x2E, 0xE3, 0x14, 0x5D, 0x05, 0xCF, 0x31, 0xCE, 0x6B, 0xC8, 0x34, 0x32, 0x47, + 0xC5, 0x9C, 0xEF, 0x21, 0x50, 0x78, 0x47, 0xA6, 0xB1, 0x58, 0x37, 0x39, 0xAA, 0x6A, 0x0A, 0x7C, + 0x63, 0xCB, 0x22, 0x72, 0xB9, 0x87, 0xAA, 0x67, 0x7B, 0x30, 0xEB, 0x65, 0x62, 0xE2, 0x23, 0x08, + 0xB1, 0xF7, 0x38, 0x84, 0x6E, 0xEB, 0x6D, 0x60, 0x58, 0x94, 0x1F, 0xF3, 0xA9, 0x6E, 0x63, 0xD1, + 0x1F, 0xC0, 0xC2, 0x0B, 0xDA, 0xB0, 0xB0, 0x4F, 0x92, 0x6F, 0xE9, 0x34, 0xBA, 0xC8, 0x13, 0xC4, + 0xDF, 0x5B, 0x3B, 0x54, 0xF1, 0xD9, 0xEA, 0x6B, 0x9F, 0x12, 0x0D, 0xC1, 0xCD, 0x32, 0x50, 0x59, + 0x7E, 0x73, 0xE4, 0xB0, 0x3B, 0x64, 0xF3, 0x11, 0xD2, 0x7F, 0x0E, 0x78, 0xE9, 0x99, 0xFC, 0xDD, + 0x22, 0x43, 0xE1, 0x11, 0xA4, 0x4D, 0x11, 0x39, 0x44, 0x0A, 0x8D, 0x08, 0x32, 0x76, 0xF2, 0xF8, + 0xAB, 0x4B, 0x65, 0x79, 0x51, 0x38, 0xBB, 0x90, 0x51, 0xF4, 0xBC, 0x8A, 0x26, 0x1E, 0x12, 0x1F, + 0x7D, 0x9E, 0x54, 0x20, 0x31, 0x9A, 0x2E, 0x2F, 0x70, 0xA9, 0xF4, 0x88, 0x94, 0x1D, 0x6F, 0x9B, + 0x76, 0x28, 0x42, 0xB9, 0x0D, 0x37, 0x5C, 0xA2, 0xF7, 0xA7, 0xB7, 0xD8, 0x5B, 0xF3, 0x92, 0x2E, + 0x32, 0xF4, 0xAB, 0x24, 0xE3, 0x93, 0xE8, 0xBC, 0xFF, 0xB6, 0x66, 0x6F, 0x53, 0x2C, 0x8F, 0xC5, + 0x1E, 0x5C, 0x8E, 0x41, 0xA9, 0x8B, 0x68, 0xD1, 0xB6, 0xD1, 0x5F, 0x28, 0xB5, 0x05, 0x6A, 0x40, + 0x4C, 0xCA, 0x7D, 0x7E, 0x7E, 0xCB, 0xD2, 0xA5, 0x78, 0x18, 0xCD, 0x90, 0x38, 0xF2, 0x09, 0x0A, + 0x36, 0x49, 0x98, 0x86, 0x9C, 0x2E, 0x80, 0x6A, 0x61, 0x26, 0xFD, 0xCE, 0x78, 0x90, 0x23, 0x4C, + 0xB6, 0x64, 0xCA, 0x22, 0xBA, 0xE9, 0xAC, 0x5C, 0x3C, 0x09, 0x23, 0x99, 0x9C, 0x01, 0xF0, 0xA3, + 0x06, 0xE1, 0x65, 0x8B, 0x50, 0x27, 0x2F, 0x1C, 0x25, 0xA5, 0x7E, 0xD1, 0xBC, 0x06, 0xDB, 0x04, + 0xFF, 0x87, 0x66, 0xD1, 0xA8, 0x98, 0xB9, 0xAC, 0x98, 0xB9, 0xF8, 0x4F, 0x8F, 0x31, 0x21, 0xE0, + 0x3E, 0xB2, 0x17, 0xA0, 0x24, 0xCB, 0x8E, 0xD2, 0x87, 0xED, 0x09, 0xD6, 0x44, 0x12, 0xCF, 0xA8, + 0x31, 0xB6, 0x47, 0xE3, 0x2C, 0x2E, 0x91, 0x1A, 0x75, 0x3B, 0x25, 0x23, 0x45, 0x15, 0x6C, 0xB3, + 0x98, 0xFC, 0x83, 0x52, 0xED, 0x29, 0x87, 0xD2, 0x13, 0x30, 0x55, 0x67, 0x5C, 0xD8, 0xC9, 0x41, + 0x36, 0xAA, 0x2C, 0x19, 0xD8, 0x9B, 0x74, 0xEA, 0xC1, 0x4D, 0x3A, 0x79, 0xC5, 0x8E, 0x26, 0x90, + 0x01, 0x1D, 0x29, 0x6C, 0x3A, 0xDF, 0xB0, 0xAB, 0xDA, 0x4C, 0xBE, 0x6D, 0xF1, 0x9C, 0xC5, 0xD6, + 0x81, 0xA8, 0x41, 0xD4, 0xB0, 0x94, 0x53, 0xA4, 0x2A, 0x7E, 0x2B, 0xF3, 0xD4, 0xEF, 0x49, 0xFC, + 0x5C, 0x06, 0xF2, 0x7B, 0x69, 0x09, 0xF1, 0xD9, 0x15, 0x25, 0x6B, 0x76, 0x05, 0xAD, 0x25, 0xFA, + 0xA6, 0x07, 0x35, 0xA9, 0xC9, 0xD4, 0x32, 0x7C, 0xDF, 0x92, 0x68, 0xFB, 0x93, 0x18, 0x4F, 0xB9, + 0x20, 0x4A, 0x85, 0x62, 0x13, 0x44, 0x5B, 0x3E, 0x8C, 0xFE, 0x95, 0x8E, 0x7F, 0xE7, 0xE5, 0xEE, + 0xF9, 0x84, 0x83, 0x1B, 0x38, 0xEB, 0x6E, 0x10, 0x68, 0xC0, 0x3C, 0x71, 0xFA, 0xFD, 0x96, 0x2A, + 0xEE, 0x44, 0x49, 0x31, 0x9F, 0x50, 0x60, 0x1A, 0x29, 0xE5, 0xBD, 0x5D, 0x8C, 0x54, 0xAD, 0x82, + 0x14, 0x4A, 0xE0, 0x6E, 0x6D, 0x63, 0xEB, 0xC1, 0xD0, 0xA8, 0x76, 0xE6, 0x9E, 0x2B, 0x36, 0xDC, + 0x16, 0x3F, 0xA7, 0xCD, 0x72, 0x9E, 0x29, 0xE9, 0x1D, 0x78, 0x3D, 0x51, 0x6C, 0xDF, 0xA6, 0x1E, + 0x09, 0x63, 0x58, 0x14, 0x9B, 0xBD, 0xDB, 0xD8, 0xFF, 0x97, 0xEB, 0xD7, 0x78, 0xED, 0x28, 0xD8, + 0xFB, 0xE3, 0xE0, 0x19, 0xF2, 0x0E, 0x2F, 0xB1, 0xDA, 0xC8, 0xEE, 0xCC, 0xCD, 0xCC, 0xD9, 0xBC, + 0xF9, 0xCF, 0xBD, 0x66, 0x67, 0x20, 0xB3, 0xCC, 0x58, 0xDD, 0x95, 0x2F, 0x4A, 0xFF, 0xE2, 0x24, + 0xC8, 0x76, 0xBB, 0xC5, 0x18, 0x2D, 0x85, 0xF3, 0x7C, 0x79, 0x7A, 0x7A, 0x8A, 0x46, 0x37, 0x0A, + 0xE6, 0x45, 0x1B, 0xBB, 0xCA, 0xC4, 0x40, 0x29, 0xD0, 0x21, 0xC1, 0xB6, 0x41, 0xF3, 0xB3, 0x3B, + 0x19, 0xD5, 0xA3, 0x6D, 0x1A, 0xD9, 0xCA, 0x5C, 0xB6, 0x7D, 0xC5, 0x2E, 0xB5, 0x07, 0x9A, 0x08, + 0xF1, 0x38, 0x76, 0x0C, 0x22, 0xF5, 0xDF, 0xFC, 0x26, 0xEC, 0xBB, 0xE3, 0x6B, 0x40, 0xA0, 0xE0, + 0xCA, 0x19, 0x67, 0xC1, 0xE2, 0x79, 0x0A, 0x18, 0x98, 0x8C, 0x43, 0x91, 0x0D, 0x41, 0x40, 0x72, + 0x61, 0x21, 0xCA, 0x77, 0x96, 0x5B, 0x4E, 0xDB, 0xC4, 0xDD, 0x53, 0x5A, 0x9E, 0x49, 0x07, 0x28, + 0x37, 0xEC, 0x7B, 0x8A, 0xF3, 0x0B, 0xBD, 0xA3, 0x9F, 0x3F, 0x56, 0x74, 0xD7, 0x1F, 0xC9, 0x3C, + 0x60, 0x8D, 0x20, 0xA1, 0x76, 0x9B, 0xC0, 0x49, 0xAD, 0x2E, 0x3B, 0xD0, 0x7B, 0x40, 0x18, 0x0D, + 0x59, 0x2F, 0xD1, 0x94, 0x30, 0x0A, 0x7B, 0xE4, 0x14, 0x35, 0xFE, 0x00, 0xBE, 0x13, 0xE3, 0xF3, + 0x45, 0x4E, 0x95, 0x34, 0x88, 0xAF, 0x84, 0x57, 0xC8, 0x74, 0x1B, 0x7B, 0xE2, 0xF4, 0x97, 0x85, + 0x5C, 0x1C, 0x43, 0x39, 0x36, 0x46, 0x82, 0xEB, 0x02, 0xD6, 0x86, 0xF4, 0x38, 0xA0, 0x0E, 0x6F, + 0x89, 0x87, 0x0B, 0xAD, 0x7E, 0xAE, 0x02, 0xF1, 0x76, 0x3C, 0x3D, 0xF3, 0x90, 0xA3, 0x6A, 0x3C, + 0x06, 0x84, 0xAB, 0x4C, 0x21, 0xB3, 0x97, 0x66, 0xEF, 0xF7, 0x2A, 0x9B, 0x9E, 0x28, 0x8F, 0x79, + 0xCB, 0x07, 0x95, 0x1F, 0x48, 0xD8, 0x04, 0xCE, 0x89, 0x52, 0xBA, 0x56, 0xA0, 0x1F, 0xCF, 0x09, + 0x33, 0x30, 0xF9, 0x23, 0x68, 0xEB, 0xDA, 0x2B, 0x91, 0x1B, 0xA4, 0x24, 0x0B, 0xE5, 0x78, 0xB7, + 0x85, 0x22, 0x84, 0xD1, 0x8B, 0x14, 0xC3, 0x73, 0x77, 0x51, 0x4E, 0x13, 0x6E, 0x10, 0x07, 0x8A, + 0x95, 0x20, 0xE9, 0x3F, 0xE6, 0xA2, 0xB6, 0x9A, 0xC6, 0x13, 0xEC, 0x68, 0xAA, 0xC6, 0xC2, 0xAF, + 0xAF, 0x0E, 0xE7, 0xFC, 0xA3, 0x8B, 0x1F, 0xCD, 0xB8, 0xB3, 0xA5, 0x03, 0x59, 0x92, 0x8B, 0x76, + 0x21, 0xD7, 0x41, 0xF3, 0x4E, 0xCB, 0xE7, 0x1A, 0xCB, 0x61, 0x40, 0xBB, 0x2F, 0xDF, 0x9F, 0xB4, + 0x99, 0xB3, 0x52, 0x49, 0xCF, 0xAC, 0xCB, 0xFD, 0xE8, 0xD7, 0x32, 0x62, 0x6F, 0xF6, 0x00, 0x51, + 0x66, 0xCD, 0x7D, 0xE7, 0x4C, 0xF9, 0x5A, 0x95, 0x0F, 0x9C, 0x5C, 0x24, 0xC1, 0x98, 0xE0, 0xCD, + 0x10, 0x08, 0x72, 0xFF, 0xC1, 0xF0, 0x50, 0xD9, 0x80, 0xC1, 0x79, 0xED, 0x9F, 0x9C, 0x48, 0xC8, + 0x26, 0xDB, 0x51, 0x05, 0x0E, 0x04, 0x58, 0x53, 0xE0, 0x37, 0xA8, 0x26, 0xEC, 0x0A, 0xAB, 0x12, + 0xBC, 0xC0, 0x29, 0xC9, 0x24, 0x71, 0xE8, 0x84, 0xFF, 0x6B, 0x58, 0x3A, 0xA0, 0xA5, 0x15, 0xC9, + 0x6F, 0xD0, 0x25, 0x15, 0x35, 0x99, 0xDD, 0xE8, 0x0E, 0xD7, 0xFF, 0x6D, 0x91, 0xD6, 0x5D, 0xEB, + 0x3F, 0x28, 0xB8, 0x90, 0x4A, 0x72, 0xD3, 0x40, 0x17, 0x38, 0xAB, 0x63, 0x92, 0xF9, 0x78, 0x97, + 0x04, 0x56, 0xB4, 0xDA, 0x85, 0x5B, 0x50, 0x09, 0x25, 0x95, 0xE1, 0x2B, 0x97, 0x9F, 0x93, 0x70, + 0xA7, 0xC5, 0x9B, 0xE9, 0x55, 0x84, 0x46, 0x48, 0xE0, 0xAD, 0x07, 0xA3, 0x3E, 0xD9, 0xD8, 0x24, + 0x51, 0x6B, 0xB3, 0xED, 0xEF, 0x68, 0x14, 0xCE, 0xA8, 0x26, 0x97, 0x47, 0x50, 0x15, 0x60, 0x13, + 0x1B, 0x2D, 0x15, 0xF5, 0x96, 0x25, 0x51, 0xB3, 0x1A, 0xB3, 0x01, 0x67, 0x89, 0x3F, 0xA7, 0xD0, + 0xD0, 0xD6, 0xF6, 0xB5, 0xB6, 0xA9, 0x3E, 0x66, 0xF0, 0xBD, 0xD2, 0x1A, 0x41, 0x4B, 0x06, 0x14, + 0xCA, 0x92, 0x8F, 0xFC, 0x89, 0x6A, 0x7D, 0xEE, 0xB5, 0xD2, 0x19, 0x3B, 0x40, 0x51, 0xB7, 0x8F, + 0xBE, 0xE8, 0xC5, 0xC4, 0x7F, 0x6C, 0x54, 0xBB, 0x8E, 0xDB, 0xFE, 0x00, 0xF1, 0x11, 0x5A, 0x05, + 0x27, 0x7D, 0xB8, 0xE2, 0xA7, 0xC2, 0x03, 0xA9, 0x10, 0x7E, 0x63, 0x0F, 0x7D, 0xB6, 0x5B, 0x42, + 0x0E, 0x23, 0x80, 0xE0, 0xA2, 0xAA, 0x93, 0xDC, 0x0E, 0xAF, 0x49, 0xF1, 0x0B, 0xF9, 0x2B, 0x23, + 0x35, 0xDF, 0x61, 0xA2, 0x7C, 0xF6, 0x72, 0x2B, 0x19, 0xAD, 0x65, 0x38, 0xDE, 0xC8, 0xD1, 0x32, + 0x39, 0x0B, 0x0C, 0x9C, 0xDC, 0xE4, 0x06, 0xFC, 0xEC, 0xEA, 0x74, 0x48, 0x39, 0x0B, 0x76, 0x8E, + 0x98, 0x44, 0x74, 0xD2, 0xDA, 0x3F, 0x38, 0x7E, 0x2B, 0xA9, 0x4F, 0x45, 0x4E, 0x88, 0x9C, 0xAF, + 0xF2, 0x22, 0x94, 0x43, 0x22, 0xC5, 0xC0, 0xAE, 0x04, 0xD5, 0xE4, 0xD2, 0xD1, 0x83, 0xA7, 0xEB, + 0xFA, 0x6C, 0xB7, 0xFB, 0xFC, 0xA1, 0xA4, 0x18, 0x1F, 0xB0, 0xF4, 0xF4, 0x38, 0xD6, 0x57, 0x2A, + 0x4C, 0x77, 0xAA, 0x4B, 0xA7, 0x4F, 0xA8, 0x63, 0x26, 0x47, 0x14, 0x85, 0x5C, 0x16, 0xA4, 0x43, + 0xDA, 0xCD, 0x73, 0x46, 0x99, 0x56, 0x6C, 0xF0, 0xD7, 0x2B, 0xCB, 0x2A, 0x38, 0x2A, 0x02, 0xA1, + 0xD0, 0x90, 0x37, 0x6F, 0x6B, 0xD7, 0xDF, 0xCA, 0xA7, 0x32, 0xDF, 0x61, 0x5E, 0xDD, 0x7C, 0x05, + 0x16, 0x10, 0x8C, 0x36, 0xDB, 0xC4, 0x44, 0x60, 0xD5, 0xF7, 0xF8, 0x90, 0x0F, 0x87, 0xE1, 0xBE, + 0x6C, 0x0C, 0xF2, 0x72, 0xEE, 0xFD, 0x2B, 0xDD, 0xE5, 0xD2, 0x22, 0x58, 0x32, 0x49, 0x1F, 0xB0, + 0xAF, 0x52, 0x2C, 0xC0, 0x12, 0xA9, 0x6F, 0xF7, 0xF7, 0x3C, 0x9B, 0x03, 0xFA, 0x66, 0x28, 0xE3, + 0x6A, 0xC4, 0xDC, 0x04, 0x51, 0xFA, 0x6F, 0x10, 0x63, 0xBE, 0x95, 0xD7, 0xC1, 0x76, 0x59, 0xAC, + 0xA3, 0x78, 0x85, 0x6B, 0x6A, 0x03, 0x9F, 0x74, 0x0F, 0x0F, 0x94, 0x0B, 0xAD, 0x4B, 0xEB, 0x69, + 0x9D, 0x26, 0x7A, 0xE9, 0x3D, 0x48, 0xF4, 0x49, 0x19, 0xBC, 0x3D, 0xAB, 0x95, 0xDC, 0xAF, 0x67, + 0x22, 0xD7, 0x52, 0x2D, 0xBD, 0xB6, 0x8B, 0x86, 0x39, 0x34, 0xDC, 0x26, 0x1A, 0x7D, 0xF1, 0x70, + 0x1C, 0x23, 0x94, 0xF0, 0x8A, 0x4A, 0xDB, 0x79, 0x9B, 0x9F, 0x1B, 0x7E, 0xB7, 0xF4, 0x8E, 0x5C, + 0x7F, 0xC0, 0x9D, 0x85, 0x61, 0x51, 0x48, 0x4E, 0x79, 0xAD, 0x4A, 0xC6, 0xF4, 0x4E, 0xBF, 0xCB, + 0xBF, 0xB4, 0x46, 0x83, 0x1A, 0x4E, 0xA8, 0x21, 0x22, 0x2F, 0xEA, 0x7C, 0x49, 0xE1, 0xC9, 0x2B, + 0x58, 0xAF, 0xF7, 0x60, 0x54, 0xC8, 0x82, 0x24, 0xD8, 0xBE, 0xE7, 0x9E, 0xF5, 0x69, 0x70, 0xE5, + 0xDB, 0xD3, 0xF3, 0x34, 0xDF, 0x3F, 0x88, 0x4B, 0x60, 0x46, 0x8B, 0x84, 0xEC, 0x23, 0x66, 0x73, + 0x2D, 0xDD, 0xB9, 0x13, 0x75, 0xDD, 0x56, 0x10, 0x3A, 0x38, 0x4F, 0xE3, 0x94, 0x4C, 0xD1, 0x0C, + 0x3C, 0xF2, 0x1D, 0xF9, 0x7F, 0xC2, 0x26, 0x9E, 0xE3, 0xD2, 0xD9, 0xBE, 0x8B, 0xCB, 0x53, 0xE7, + 0x5A, 0x4C, 0x01, 0x13, 0x42, 0x60, 0xC7, 0x04, 0x37, 0x70, 0x04, 0x3E, 0x2B, 0x82, 0x43, 0x8C, + 0xCC, 0x97, 0xF4, 0x65, 0x35, 0xFB, 0x08, 0x11, 0xD9, 0x0B, 0x09, 0x67, 0x45, 0x23, 0xAA, 0xCC, + 0x3D, 0x07, 0x26, 0x64, 0xE3, 0x44, 0xEA, 0x3C, 0x2D, 0xBE, 0xE4, 0x49, 0xB9, 0x3B, 0x94, 0xDE, + 0x3B, 0x19, 0x90, 0x3D, 0x30, 0x81, 0x25, 0xB8, 0xE4, 0x1E, 0x74, 0xED, 0xF1, 0xB5, 0x40, 0x6C, + 0x2B, 0x8E, 0x02, 0xDF, 0xB1, 0x4B, 0xA9, 0xE0, 0x48, 0x97, 0x24, 0xE5, 0x55, 0xAE, 0x36, 0x35, + 0xB4, 0x5D, 0x55, 0xA7, 0x7C, 0x6E, 0xB8, 0x53, 0x91, 0xA4, 0xBB, 0x47, 0x49, 0x03, 0xD3, 0x00, + 0xF0, 0x26, 0x7E, 0x52, 0x69, 0x4B, 0xE2, 0x2C, 0xF8, 0x06, 0x0D, 0x3A, 0xEE, 0xA6, 0xBD, 0x0F, + 0x1F, 0xA2, 0xBE, 0x1D, 0xDE, 0x82, 0x36, 0xA5, 0x1A, 0xFD, 0x81, 0x48, 0xC1, 0x91, 0xEB, 0x69, + 0x53, 0x08, 0x9B, 0xBB, 0x0C, 0x2B, 0xE5, 0x04, 0x7A, 0x6A, 0xE3, 0xA2, 0x24, 0x69, 0x4E, 0xA5, + 0xDE, 0x7C, 0xB4, 0x3D, 0x85, 0x7D, 0x78, 0x28, 0xEC, 0x99, 0xF4, 0x7E, 0x53, 0xEE, 0x8A, 0x3E, + 0x69, 0xAD, 0xA1, 0x2D, 0xCF, 0x9F, 0x2C, 0xF1, 0x57, 0xA9, 0x73, 0xA4, 0x76, 0x92, 0xBC, 0xBA, + 0x14, 0xA2, 0x7A, 0x97, 0x7E, 0x91, 0x49, 0xAB, 0x33, 0x8F, 0xA3, 0x9C, 0x67, 0xCA, 0xA9, 0xB1, + 0x17, 0xE8, 0xBC, 0x33, 0x59, 0x17, 0x1D, 0x20, 0xDC, 0xE5, 0xA9, 0xA7, 0x3F, 0x95, 0x74, 0xB4, + 0x0C, 0xBB, 0x0E, 0xDB, 0x5F, 0x5F, 0x7D, 0x78, 0x25, 0xFB, 0x55, 0x46, 0x39, 0x5D, 0x0B, 0x69, + 0x1A, 0x35, 0xEF, 0xAA, 0x8A, 0x4C, 0x4E, 0x5B, 0x5F, 0x09, 0x09, 0xA1, 0x87, 0x79, 0x9B, 0x45, + 0xEF, 0x1E, 0xA5, 0x65, 0x63, 0x86, 0x8B, 0x48, 0x53, 0x8D, 0xE7, 0x64, 0xEC, 0x51, 0x6F, 0x04, + 0xDF, 0x90, 0x5B, 0x18, 0x43, 0x03, 0x35, 0x9D, 0x5B, 0xFC, 0x97, 0x19, 0xB6, 0x52, 0x78, 0xD4, + 0x8E, 0xF0, 0x18, 0xCD, 0x03, 0x32, 0xDF, 0x99, 0x52, 0xD2, 0x81, 0x3D, 0xC1, 0xC7, 0x00, 0xCA, + 0x1A, 0xB7, 0xA8, 0x34, 0x4B, 0x3F, 0x28, 0x86, 0x4C, 0x53, 0xC6, 0x08, 0xEE, 0x26, 0x96, 0xB4, + 0x4D, 0xC9, 0x39, 0xA3, 0x8F, 0xC8, 0x99, 0x06, 0x7B, 0xDF, 0x2D, 0x45, 0xAF, 0xCB, 0x82, 0xA4, + 0xCF, 0xB0, 0x38, 0xBF, 0x79, 0x3A, 0x04, 0x79, 0x26, 0x19, 0xAC, 0xD4, 0x49, 0x30, 0x8B, 0xD0, + 0xC3, 0x3B, 0x72, 0xB2, 0xCE, 0x5D, 0x46, 0x16, 0x0B, 0x8B, 0xCD, 0x90, 0x96, 0x40, 0x5D, 0x1D, + 0x12, 0x38, 0x0D, 0xBB, 0x0B, 0x88, 0x37, 0x0B, 0x8B, 0xD9, 0x1F, 0x7B, 0x88, 0x65, 0xD9, 0xED, + 0x19, 0x66, 0x34, 0xE9, 0x9C, 0xDF, 0x17, 0xF9, 0x37, 0xB1, 0x52, 0xA8, 0x98, 0x7B, 0xE8, 0x76, + 0xB7, 0x56, 0x5E, 0x62, 0xB6, 0x78, 0xFF, 0x99, 0xE9, 0x5A, 0x5A, 0xE4, 0x73, 0xF4, 0x70, 0x97, + 0x8A, 0xB7, 0xF3, 0x63, 0x22, 0x7C, 0x07, 0xB5, 0xE5, 0x6F, 0xEB, 0xFC, 0x2B, 0x5D, 0xBC, 0xCE, + 0x3C, 0x01, 0xF8, 0x08, 0x3D, 0xFE, 0x32, 0x29, 0x65, 0x1E, 0xBB, 0xE2, 0xAB, 0xDA, 0x73, 0xAA, + 0xB4, 0x20, 0xCA, 0x17, 0x95, 0xC9, 0xFE, 0x08, 0x86, 0x6C, 0xC8, 0x32, 0x77, 0x26, 0x3A, 0x26, + 0xD5, 0xB9, 0x36, 0xBC, 0xF9, 0x81, 0x7F, 0xD7, 0xB0, 0x66, 0x12, 0x4C, 0xB4, 0xCA, 0x44, 0x08, + 0xC9, 0x24, 0xDE, 0x87, 0x7F, 0x7A, 0x61, 0xE4, 0x1A, 0x45, 0xB8, 0xF3, 0x90, 0x28, 0xBE, 0xD7, + 0x36, 0xF8, 0x17, 0x5B, 0xA3, 0x32, 0xFF, 0xCF, 0x37, 0x7F, 0x1A, 0x54, 0x74, 0x63, 0xF6, 0xC1, + 0xA7, 0x09, 0xC7, 0x08, 0xB6, 0x75, 0x16, 0x09, 0xED, 0x9A, 0xBF, 0x17, 0x58, 0x21, 0x88, 0x27, + 0xD5, 0xC3, 0x8D, 0x9B, 0x81, 0x4C, 0x28, 0x5C, 0x34, 0x89, 0xC5, 0x80, 0x0B, 0x40, 0xA2, 0xA5, + 0x90, 0x1C, 0x4D, 0x1A, 0xF7, 0x72, 0x25, 0x3E, 0x47, 0x21, 0x0D, 0xDC, 0xE2, 0xDE, 0xCC, 0x45, + 0x3D, 0x64, 0xB3, 0x2B, 0xF4, 0xF6, 0x51, 0x78, 0x3C, 0x6A, 0xF3, 0x6F, 0xFF, 0x7F, 0xB0, 0x76, + 0x21, 0x42, 0x87, 0x47, 0x32, 0xD6, 0x0C, 0x7D, 0x65, 0x9F, 0xE3, 0x08, 0x2A, 0x49, 0xE6, 0x67, + 0x9E, 0x7B, 0x76, 0x14, 0x50, 0x9D, 0xD7, 0x1E, 0xB8, 0xF3, 0x88, 0xE6, 0x75, 0x86, 0x07, 0x1E, + 0xA7, 0x2D, 0x6C, 0x20, 0xE8, 0x49, 0x25, 0x07, 0x28, 0x0C, 0xF8, 0xFA, 0x62, 0x6F, 0x38, 0xCC, + 0xA5, 0x44, 0x73, 0x4E, 0xF4, 0x7B, 0xE3, 0x1A, 0x7C, 0x99, 0x3B, 0xA0, 0xC2, 0x98, 0xD3, 0xEC, + 0xCE, 0x10, 0x75, 0x12, 0x2C, 0x70, 0x24, 0xBC, 0xE7, 0xF5, 0x83, 0x96, 0xC2, 0x51, 0xDC, 0xA9, + 0x97, 0x2F, 0x32, 0xD8, 0xF3, 0x0B, 0x03, 0x1C, 0x93, 0x44, 0xC4, 0xEB, 0x21, 0xB3, 0xB0, 0x9A, + 0x64, 0x94, 0x04, 0xAD, 0xCE, 0x91, 0x44, 0x04, 0xE4, 0xE6, 0xB2, 0xE1, 0xBC, 0x75, 0xB2, 0xC2, + 0x6B, 0x46, 0xD1, 0xEE, 0x88, 0x80, 0xE8, 0x2C, 0x2D, 0x10, 0x95, 0x9A, 0x03, 0x30, 0xDF, 0x51, + 0x74, 0x94, 0xDA, 0x67, 0x1F, 0xB5, 0x95, 0x23, 0x16, 0xC0, 0x46, 0x57, 0xF1, 0x37, 0xBC, 0xE2, + 0x99, 0x2C, 0xA0, 0xFC, 0xEA, 0x24, 0x5B, 0xEE, 0x5E, 0x2A, 0x2B, 0xF3, 0xA2, 0x0A, 0x94, 0x27, + 0xF4, 0x7D, 0x4D, 0x83, 0xCA, 0xCE, 0xAA, 0xE0, 0xA9, 0xDB, 0x9C, 0xF8, 0xFF, 0x25, 0xBD, 0x62, + 0xD8, 0x99, 0xA7, 0x26, 0x36, 0x75, 0x62, 0x99, 0x77, 0x83, 0x49, 0x02, 0x3B, 0xC7, 0x5F, 0x37, + 0x64, 0x48, 0xCF, 0x9A, 0x16, 0x0E, 0xBC, 0xCA, 0x0A, 0xF4, 0x0E, 0xDA, 0x5D, 0xFB, 0xDB, 0xE7, + 0xBF, 0x51, 0x6E, 0x8B, 0x37, 0xCB, 0x4F, 0x0C, 0x73, 0x36, 0xC8, 0x0F, 0x2A, 0x70, 0x79, 0xFA, + 0x77, 0xB1, 0x5D, 0xBB, 0xC7, 0x52, 0x39, 0x7C, 0x50, 0x73, 0x5F, 0x8F, 0xB5, 0x28, 0xEC, 0x48, + 0x26, 0x14, 0xF0, 0x41, 0xD1, 0x32, 0x6C, 0x1D, 0x44, 0xA1, 0xF0, 0xEF, 0xE8, 0x69, 0xA4, 0x1E, + 0x00, 0x45, 0xF8, 0x52, 0xA5, 0x31, 0x5D, 0xD3, 0x55, 0x6C, 0xCA, 0xB0, 0x51, 0x0E, 0x69, 0xA1, + 0x47, 0x12, 0xC3, 0xFD, 0x9D, 0x99, 0x45, 0x2B, 0x95, 0x8E, 0x79, 0x51, 0x1D, 0x86, 0x5D, 0x06, + 0x37, 0xCC, 0x19, 0xD3, 0xB2, 0xD4, 0x7A, 0x1E, 0x1E, 0xD1, 0x30, 0x40, 0x6D, 0x9B, 0x08, 0x77, + 0xE5, 0xB3, 0x48, 0xFA, 0x1B, 0x8A, 0x4D, 0x26, 0x8F, 0x9E, 0x50, 0x78, 0xE2, 0x4D, 0x3A, 0x3E, + 0x86, 0x27, 0x50, 0x05, 0x27, 0x05, 0x29, 0x83, 0x72, 0x46, 0x58, 0x34, 0x24, 0xDA, 0x11, 0x33, + 0xA6, 0x4F, 0x10, 0xF3, 0xF3, 0xAB, 0x00, 0x27, 0x1F, 0x02, 0x71, 0x8B, 0xC9, 0x68, 0x9B, 0x12, + 0xDE, 0x24, 0x4F, 0x85, 0x8D, 0xD3, 0xB3, 0xFC, 0xF4, 0xA4, 0x53, 0xD0, 0x2F, 0x57, 0x07, 0xEC, + 0x28, 0xD7, 0x2E, 0x07, 0xCD, 0xEF, 0xDC, 0x6F, 0xC2, 0xA8, 0x48, 0x52, 0x15, 0xFA, 0x57, 0x26, + 0xA8, 0xA3, 0x30, 0x10, 0xE1, 0x4D, 0xD2, 0x33, 0xCF, 0x0B, 0xF8, 0x73, 0x36, 0xE6, 0xE4, 0x6A, + 0xED, 0x1C, 0xCD, 0xCB, 0xD1, 0xC8, 0x36, 0x3E, 0x68, 0xE7, 0xF4, 0xD2, 0xFE, 0xE6, 0x4C, 0x5B, + 0xED, 0xE8, 0x85, 0xA3, 0x0D, 0x1C, 0xB3, 0xBC, 0x6A, 0x2B, 0x8B, 0x59, 0xD3, 0x32, 0x49, 0xE2, + 0x22, 0x08, 0x8B, 0x22, 0xB2, 0x6D, 0x9B, 0x9A, 0xA2, 0x2F, 0xA2, 0xE1, 0x54, 0x73, 0xDD, 0x9C, + 0xED, 0x58, 0xD8, 0x5C, 0xFD, 0x7B, 0x55, 0xFC, 0x0B, 0xC6, 0x23, 0x7D, 0x80, 0x77, 0x11, 0x2A, + 0xCA, 0x2D, 0x93, 0x90, 0x3D, 0xEB, 0xF3, 0xDE, 0xCD, 0xF0, 0x3A, 0x37, 0x6F, 0x19, 0xA4, 0x0E, + 0x37, 0x54, 0x17, 0x51, 0xCE, 0x0A, 0x53, 0x48, 0xFD, 0x29, 0x6F, 0x97, 0x5E, 0xD7, 0x65, 0x58, + 0x8D, 0xAB, 0x38, 0x68, 0xD3, 0x10, 0xE2, 0x19, 0xAA, 0x91, 0x79, 0xB4, 0xD7, 0x0C, 0x6D, 0x29, + 0xA2, 0xA9, 0x64, 0x36, 0x08, 0x19, 0x5D, 0xB2, 0x5F, 0x5D, 0x01, 0x24, 0x5E, 0xFD, 0x59, 0x7D, + 0x92, 0x29, 0xBB, 0xFE, 0xC5, 0xEA, 0x29, 0x90, 0x6B, 0x59, 0x6D, 0x1C, 0x53, 0xE4, 0xA0, 0x9D, + 0xD2, 0x2C, 0x83, 0xBA, 0x2F, 0xC4, 0xAE, 0x30, 0x65, 0xEC, 0xB4, 0x7F, 0x3E, 0x3E, 0xA4, 0x22, + 0x92, 0xA2, 0xF2, 0xA9, 0xEF, 0x9B, 0xB4, 0x1D, 0x76, 0xF9, 0xA1, 0x92, 0x99, 0xA9, 0xED, 0x2D, + 0x77, 0x0D, 0xAA, 0x1A, 0xEB, 0x5A, 0x65, 0x6F, 0x09, 0x76, 0x6A, 0x9A, 0x52, 0x32, 0x8D, 0x7F, + 0x09, 0x1F, 0x2B, 0x82, 0xA2, 0x7F, 0xF7, 0xF6, 0x90, 0xD6, 0xF2, 0x49, 0x21, 0x47, 0xF9, 0x99, + 0x25, 0xCB, 0x00, 0x8A, 0x6A, 0xBC, 0x4D, 0x3B, 0xB8, 0x0E, 0x68, 0x22, 0x70, 0x67, 0x23, 0x23, + 0x82, 0xAE, 0xCB, 0xCD, 0x6E, 0x2B, 0xDA, 0x78, 0x8A, 0x9B, 0x66, 0x9D, 0x2B, 0x81, 0x8A, 0xCC, + 0x0D, 0x25, 0x26, 0x1E, 0xA4, 0xF7, 0xF5, 0xB0, 0xB0, 0xD3, 0x9F, 0xA5, 0x5F, 0x4C, 0xB8, 0xBC, + 0xAA, 0x25, 0xAF, 0xC5, 0x92, 0xE9, 0x76, 0x0F, 0x64, 0x1D, 0x34, 0x51, 0xAC, 0x2D, 0x52, 0x04, + 0x49, 0xFA, 0xB2, 0xD5, 0x1E, 0x2E, 0x2B, 0x9E, 0xF3, 0xB6, 0xB7, 0x23, 0xC9, 0xFB, 0xC8, 0x93, + 0x65, 0xAF, 0xCF, 0x17, 0xBA, 0x6B, 0x99, 0x5C, 0xB4, 0xC3, 0xD8, 0x74, 0x8D, 0x3B, 0xF1, 0xEB, + 0x14, 0x15, 0x8A, 0x05, 0xCD, 0x09, 0x75, 0xF8, 0x70, 0x05, 0xE7, 0xEF, 0xA3, 0x7D, 0xCC, 0xDC, + 0x56, 0x84, 0xB0, 0x45, 0xED, 0x6D, 0xF1, 0xCB, 0x5F, 0x4B, 0x3F, 0x2F, 0x20, 0x8B, 0xC3, 0x52, + 0xB1, 0x77, 0xF8, 0xEC, 0x4E, 0x51, 0xD2, 0xAD, 0x87, 0x54, 0xE3, 0xF1, 0xC5, 0xCA, 0x43, 0x34, + 0xEB, 0x9F, 0x4F, 0x20, 0x14, 0x7F, 0xF9, 0x36, 0x05, 0x9C, 0xBB, 0x2B, 0xE1, 0x1B, 0x01, 0x2C, + 0x8F, 0xEB, 0x08, 0x16, 0x64, 0x15, 0x8F, 0x70, 0xDF, 0xEE, 0x56, 0xCB, 0x6D, 0x75, 0x51, 0x4D, + 0x6F, 0xF6, 0xE4, 0x0D, 0x56, 0x31, 0xAB, 0xCF, 0xD5, 0x27, 0xC6, 0x2B, 0x80, 0xE0, 0x5C, 0xFD, + 0xFB, 0x76, 0x7F, 0x8B, 0x73, 0x78, 0x50, 0x4C, 0xE2, 0x4E, 0x4F, 0xF4, 0x32, 0x72, 0x97, 0xBB, + 0x07, 0x01, 0x63, 0x1E, 0x7E, 0xFD, 0xDA, 0xA6, 0x99, 0x00, 0x0E, 0x32, 0x8D, 0x66, 0xCE, 0xF6, + 0x6B, 0x18, 0xF0, 0x08, 0xDE, 0x37, 0x33, 0x4A, 0x89, 0x7D, 0x17, 0x96, 0xB0, 0xB6, 0x59, 0x37, + 0x2A, 0xAF, 0xF0, 0x72, 0x81, 0xA9, 0x49, 0xEB, 0x40, 0xF4, 0x96, 0x85, 0x6A, 0x71, 0xAC, 0x38, + 0xDD, 0x25, 0xFA, 0xF8, 0x70, 0xDE, 0x0A, 0xA5, 0x48, 0x98, 0xB0, 0x7D, 0x78, 0x7A, 0x4D, 0xFD, + 0xC4, 0x09, 0x8F, 0x7C, 0xAF, 0x39, 0x0F, 0xEA, 0xEA, 0xA8, 0x13, 0xD9, 0x80, 0x53, 0x58, 0x0B, + 0x2B, 0x53, 0x27, 0x55, 0x27, 0xCE, 0xBC, 0x5F, 0x2F, 0x46, 0xC6, 0x0D, 0xBA, 0xE4, 0x1F, 0x1E, + 0x49, 0x67, 0x69, 0x2D, 0xDA, 0xB5, 0x29, 0xB0, 0x80, 0xAA, 0xF2, 0x2E, 0xE7, 0xE7, 0x3D, 0x62, + 0x44, 0x21, 0xB5, 0xD8, 0xF6, 0xA8, 0x88, 0x4D, 0x93, 0x0D, 0x4D, 0x51, 0xC3, 0xA9, 0x42, 0x6D, + 0x25, 0x52, 0xBA, 0x0E, 0x71, 0x66, 0xAA, 0xED, 0xF2, 0xAF, 0xDC, 0xFC, 0xDB, 0xEF, 0xC4, 0x01, + 0x51, 0x44, 0xF8, 0x90, 0x62, 0x32, 0x70, 0xB2, 0x85, 0x08, 0x05, 0x5E, 0x27, 0xE3, 0x6C, 0xD7, + 0x6B, 0x02, 0x40, 0x78, 0x33, 0x22, 0xD2, 0x1A, 0xCA, 0xFA, 0x28, 0x89, 0x9B, 0x61, 0xD5, 0x97, + 0x78, 0xEA, 0xEC, 0x05, 0x91, 0x03, 0xB5, 0xE8, 0x1E, 0x3D, 0xC3, 0xEF, 0xEA, 0xBF, 0x1E, 0x0E, + 0x38, 0x0B, 0xAA, 0x18, 0x81, 0xBF, 0x0C, 0x95, 0x4A, 0xBD, 0x0E, 0xF0, 0xE5, 0x72, 0xAE, 0xE8, + 0x3A, 0x7F, 0x0E, 0x5D, 0x0E, 0x45, 0x46, 0xB3, 0xCB, 0xCE, 0xF3, 0x8D, 0x8E, 0x3B, 0x77, 0xA8, + 0x0F, 0x1E, 0x9E, 0xB9, 0x5C, 0xD4, 0xE6, 0x4F, 0xCC, 0xFB, 0x07, 0x04, 0xE2, 0xEF, 0xC4, 0xBB, + 0x65, 0x87, 0x8C, 0xFA, 0x54, 0x25, 0x17, 0xC6, 0xF0, 0x96, 0xC6, 0x9E, 0x08, 0xE3, 0x71, 0xD6, + 0xD5, 0x2B, 0xB0, 0x92, 0x10, 0x6F, 0x1D, 0xF6, 0xB4, 0x6E, 0xFC, 0x5E, 0x3C, 0x8F, 0x49, 0x7C, + 0xD2, 0xA7, 0x52, 0xCC, 0xAA, 0xDE, 0xDF, 0x1B, 0x2B, 0x85, 0x29, 0x76, 0xC0, 0x04, 0xAC, 0xF1, + 0xD2, 0x13, 0x60, 0x6F, 0xE7, 0x1D, 0xAE, 0xE8, 0xA4, 0x1E, 0xA1, 0xC1, 0x24, 0x9B, 0xD4, 0xC3, + 0x7C, 0xFC, 0x64, 0x14, 0x80, 0xE6, 0x57, 0x0D, 0x3A, 0x93, 0x57, 0xBF, 0xC4, 0x24, 0x2B, 0xCE, + 0xDC, 0x2E, 0xD6, 0xDE, 0x80, 0x90, 0x8B, 0xB0, 0x6D, 0xF2, 0xDF, 0x65, 0x34, 0x7C, 0xCC, 0xF4, + 0x43, 0xBE, 0x37, 0x84, 0xBB, 0x98, 0x8A, 0x9D, 0x29, 0x03, 0x01, 0xDB, 0x90, 0x8C, 0x0D, 0x8A, + 0x20, 0xDC, 0x28, 0x1E, 0x3B, 0x14, 0x30, 0xD7, 0xFB, 0x65, 0x2A, 0x63, 0x69, 0x01, 0xCE, 0xA7, + 0xA7, 0x09, 0xDB, 0x25, 0xD2, 0x4F, 0x37, 0x21, 0x1F, 0x8A, 0x1D, 0x7F, 0x10, 0xC0, 0x01, 0x44, + 0x28, 0x18, 0x43, 0x99, 0x11, 0x0F, 0x49, 0x21, 0x1A, 0x5A, 0x39, 0x76, 0x6A, 0x33, 0xBB, 0x4F, + 0x2E, 0x16, 0xE2, 0xF9, 0x36, 0x59, 0xB4, 0xA7, 0x17, 0x6B, 0x47, 0xF1, 0x52, 0x6B, 0x4B, 0xF0, + 0x2D, 0x79, 0x83, 0x73, 0x13, 0x65, 0xF0, 0x15, 0x43, 0xA3, 0xCD, 0xD7, 0xE8, 0xB5, 0x7B, 0x42, + 0xFA, 0xB4, 0xFF, 0xCF, 0x87, 0xB5, 0x3E, 0x3D, 0xE2, 0xDD, 0x69, 0x0F, 0xA2, 0xD3, 0xC9, 0x13, + 0xD2, 0xBC, 0xB0, 0x98, 0xE4, 0xBD, 0x3D, 0x89, 0xE3, 0x10, 0xB3, 0xB3, 0x6F, 0x6B, 0x94, 0xF3, + 0x5A, 0x2E, 0xB4, 0x9A, 0x1E, 0x01, 0x6C, 0x73, 0xC9, 0xF3, 0x18, 0x4A, 0xC4, 0x9C, 0xC9, 0x93, + 0xE2, 0x52, 0x6F, 0xD5, 0x54, 0x49, 0x52, 0xA6, 0xD2, 0xF7, 0x07, 0x88, 0xBC, 0xCD, 0x9E, 0x6E, + 0x7B, 0x91, 0x26, 0x25, 0x81, 0x36, 0x5A, 0x56, 0xCF, 0x53, 0xCC, 0x67, 0xA7, 0xEB, 0x35, 0x4A, + 0x65, 0x5D, 0x95, 0xF2, 0xCE, 0x96, 0x07, 0x4D, 0xF0, 0x90, 0xE6, 0x04, 0x07, 0x0D, 0xAC, 0x76, + 0xA6, 0x41, 0xC7, 0xD7, 0xD4, 0x58, 0xD9, 0x37, 0xD7, 0x8A, 0x6D, 0x12, 0x9F, 0xAC, 0x08, 0x49, + 0x97, 0x63, 0x46, 0x1D, 0x93, 0xD0, 0x04, 0xF9, 0xA1, 0x21, 0xE0, 0x71, 0x4F, 0x70, 0xD5, 0xF4, + 0xB5, 0xD1, 0x64, 0x8F, 0xAE, 0x3B, 0x81, 0x85, 0x55, 0x42, 0x02, 0x4B, 0x83, 0x2A, 0xAE, 0xE0, + 0x11, 0x7B, 0xF1, 0x9E, 0x39, 0x7E, 0x26, 0x1D, 0x77, 0x5B, 0x6B, 0x27, 0x64, 0x8F, 0x47, 0x74, + 0x95, 0x6A, 0xF9, 0xDC, 0xA2, 0x5C, 0xDB, 0x31, 0xC6, 0xD8, 0x04, 0xDE, 0x3D, 0x00, 0x2D, 0xDF, + 0xCD, 0xF8, 0x9A, 0x4C, 0xEE, 0xF5, 0x43, 0xA4, 0xD9, 0x20, 0x75, 0x74, 0xA0, 0xDF, 0x85, 0x10, + 0xEA, 0xF4, 0xF9, 0x52, 0x4C, 0xF8, 0xC0, 0xD1, 0xA4, 0xA1, 0x52, 0x97, 0xA7, 0x9C, 0x79, 0x10, + 0x4D, 0x56, 0x36, 0x50, 0xF4, 0xB0, 0xC9, 0xA2, 0x9A, 0xF4, 0xC1, 0x69, 0x3F, 0xA0, 0x5A, 0x90, + 0xBA, 0xA2, 0x97, 0xBD, 0x66, 0x6C, 0x08, 0x53, 0x54, 0xF4, 0xB6, 0x79, 0x67, 0x7A, 0x30, 0xC0, + 0xB1, 0x1D, 0x9D, 0x14, 0xBA, 0x73, 0x49, 0xC3, 0xE0, 0xD9, 0xD4, 0x01, 0xBB, 0x19, 0x44, 0x51, + 0xFB, 0xAE, 0x29, 0xB9, 0x9C, 0x67, 0x65, 0x4A, 0xE2, 0x60, 0x9F, 0xEF, 0x34, 0x05, 0x0F, 0xA5, + 0x7B, 0x65, 0xE4, 0x6F, 0x9F, 0xB2, 0x0D, 0x83, 0xF0, 0x89, 0xAC, 0x31, 0xAB, 0x4A, 0x6C, 0xEA, + 0x3C, 0xD3, 0xFF, 0x40, 0x5B, 0xBB, 0xE7, 0x6B, 0x44, 0xE8, 0xFF, 0xAE, 0x6A, 0x1D, 0xFB, 0x6E, + 0xC0, 0x28, 0x04, 0x8F, 0x85, 0xA6, 0x48, 0x4F, 0x81, 0xFB, 0x79, 0x21, 0x3F, 0xB9, 0x4E, 0x30, + 0xEE, 0xFE, 0x65, 0x19, 0xC0, 0x6F, 0x84, 0xA2, 0xEB, 0xAB, 0xE0, 0xCA, 0x1D, 0x18, 0x09, 0x7B, + 0x92, 0x8E, 0xFB, 0x5C, 0x08, 0x8A, 0x36, 0xFF, 0x97, 0x58, 0x10, 0x37, 0x83, 0x88, 0xCE, 0xD9, + 0xF7, 0x59, 0x49, 0x5B, 0x53, 0xF3, 0xC8, 0xAF, 0xEA, 0x9A, 0x48, 0x63, 0xC8, 0xD6, 0xB9, 0x45, + 0x70, 0x50, 0x10, 0x1D, 0x5A, 0x67, 0x4B, 0xFA, 0xB7, 0xA9, 0x47, 0xC3, 0x97, 0x6A, 0xC6, 0xE7, + 0x06, 0x86, 0x22, 0xC9, 0xE2, 0x27, 0x99, 0x84, 0x19, 0x08, 0xBE, 0x24, 0x9C, 0xEF, 0xA5, 0x35, + 0x2C, 0xBA, 0x3C, 0xA5, 0xA3, 0x7C, 0xAC, 0xB3, 0xAF, 0x04, 0xCC, 0x45, 0x0F, 0xEE, 0x26, 0xF3, + 0x55, 0x27, 0x1F, 0x73, 0x1F, 0xD3, 0x5E, 0x55, 0x90, 0xFF, 0xE7, 0x77, 0x0C, 0x8F, 0x90, 0xB1, + 0x24, 0x22, 0x5C, 0x07, 0xE8, 0xDB, 0xEE, 0x60, 0x77, 0x1F, 0xB3, 0x5D, 0x84, 0x44, 0xEF, 0xC3, + 0x99, 0xD1, 0x56, 0x44, 0xCE, 0xE4, 0x0E, 0xB8, 0xAE, 0x46, 0x47, 0xE7, 0xFA, 0x79, 0x96, 0x2C, + 0x63, 0x5D, 0x7E, 0x86, 0xD6, 0x0F, 0x97, 0xB2, 0x6C, 0xC5, 0xFA, 0x8A, 0xC1, 0xF8, 0x65, 0xD3, + 0xA0, 0x83, 0xC1, 0xDD, 0x8D, 0xE2, 0x6F, 0xF6, 0xC3, 0xA4, 0x73, 0x27, 0xDE, 0x6F, 0x4E, 0x04, + 0xDB, 0x18, 0xC9, 0x1D, 0x56, 0xC5, 0x31, 0xAA, 0xC5, 0x10, 0x8D, 0xEE, 0x79, 0xC9, 0x6D, 0x79, + 0x05, 0x83, 0x30, 0x71, 0x08, 0x46, 0xA1, 0x3E, 0xF7, 0xEB, 0x20, 0x0C, 0xA4, 0x79, 0x7C, 0x0E, + 0x12, 0x62, 0x15, 0x5D, 0x18, 0x37, 0xB4, 0x7D, 0xF3, 0x6F, 0x2A, 0x83, 0xC7, 0x26, 0xB1, 0x03, + 0xD1, 0x52, 0x30, 0x1F, 0x0E, 0x69, 0x96, 0x44, 0x16, 0xC4, 0x4B, 0x07, 0x5B, 0xE3, 0xC6, 0x58, + 0xFC, 0xB9, 0xAB, 0x64, 0x1C, 0x3C, 0x56, 0x79, 0x63, 0xBF, 0xCF, 0x5F, 0x43, 0x10, 0x49, 0xEA, + 0x96, 0x67, 0xA0, 0xBD, 0x8A, 0xFA, 0xE1, 0xB9, 0xEF, 0xF3, 0x2C, 0x27, 0x0C, 0xFC, 0xEE, 0x4E, + 0x86, 0xD7, 0xD4, 0x8C, 0x1E, 0xD5, 0x21, 0x7B, 0x58, 0xB2, 0x1C, 0xC9, 0x38, 0x59, 0xD1, 0x34, + 0x5A, 0x88, 0x75, 0xE5, 0x95, 0x7E, 0x22, 0xA5, 0x25, 0x75, 0xB6, 0xDC, 0xC1, 0xF7, 0x22, 0x38, + 0x75, 0x19, 0xBD, 0xE2, 0xF3, 0x45, 0xBF, 0x6F, 0x09, 0x44, 0xD4, 0x1F, 0xDF, 0x6C, 0x7C, 0x5A, + 0x5A, 0xA2, 0x9D, 0x58, 0xB5, 0x6E, 0xA3, 0x95, 0xC4, 0x98, 0x4B, 0xF2, 0x14, 0x78, 0xD8, 0x92, + 0xC8, 0x6A, 0xDF, 0x8F, 0xC1, 0xC8, 0xB3, 0x6B, 0xC4, 0x23, 0x61, 0xC3, 0x2D, 0xAB, 0x42, 0x27, + 0x00, 0xFC, 0x5F, 0xD5, 0x41, 0x6F, 0x05, 0xD0, 0x84, 0xA1, 0x78, 0xE4, 0x14, 0x32, 0x3A, 0x17, + 0xCA, 0x34, 0xAF, 0x2C, 0x09, 0x25, 0xB6, 0x85, 0x5D, 0xCE, 0xF7, 0x90, 0x50, 0x50, 0x00, 0x6C, + 0xE1, 0xAA, 0x35, 0x23, 0xC3, 0xAE, 0x51, 0xC1, 0xD4, 0x35, 0x79, 0xF2, 0xE2, 0xAA, 0x46, 0xE5, + 0x9F, 0xF0, 0xDE, 0xE4, 0x88, 0xB8, 0x61, 0x0B, 0x6A, 0x48, 0x22, 0x40, 0x11, 0x48, 0x5C, 0x80, + 0xF6, 0xBD, 0x59, 0xB5, 0x27, 0x0E, 0x61, 0x29, 0x1E, 0xAB, 0xD3, 0x15, 0x27, 0x37, 0x19, 0x93, + 0x9E, 0x85, 0x6B, 0xFB, 0xB2, 0x06, 0x3F, 0x0A, 0xE2, 0xED, 0x28, 0x60, 0x20, 0x35, 0x82, 0xFB, + 0x54, 0xA1, 0xD1, 0x4D, 0xBC, 0xC4, 0x67, 0x5B, 0x2A, 0x4E, 0x71, 0xF4, 0x18, 0x2D, 0xCD, 0x8A, + 0x8E, 0xE4, 0x7E, 0x41, 0xCA, 0xA1, 0xC1, 0x03, 0x3C, 0x40, 0x49, 0xEB, 0x74, 0xEA, 0xFC, 0x08, + 0x30, 0x99, 0x9E, 0x7D, 0x30, 0x11, 0x7F, 0xA2, 0x67, 0x67, 0xB4, 0xCE, 0x7B, 0x65, 0xF5, 0xF8, + 0xC7, 0xBF, 0x24, 0xFF, 0x88, 0x48, 0xE9, 0xCD, 0xFB, 0xF1, 0x2D, 0xBA, 0xB1, 0xC0, 0x50, 0x5D, + 0x0B, 0xE5, 0x23, 0xDC, 0x43, 0x52, 0x64, 0x76, 0xDB, 0xC4, 0x74, 0xD9, 0x80, 0xDA, 0x72, 0x45, + 0x08, 0xCC, 0x80, 0xA3, 0x8C, 0xD5, 0x99, 0x64, 0x51, 0x5A, 0xFE, 0x02, 0xA9, 0xBB, 0x8C, 0xF5, + 0x0B, 0xC6, 0x88, 0x76, 0xD5, 0x07, 0x6E, 0x63, 0x3C, 0xDC, 0x59, 0x2C, 0x05, 0xC6, 0xAE, 0x7D, + 0x5B, 0xC2, 0xF5, 0x4D, 0x16, 0x74, 0x47, 0xCD, 0x05, 0xB8, 0xC8, 0x31, 0x94, 0x4C, 0x8E, 0xB8, + 0x50, 0xCD, 0xE8, 0x2C, 0x7B, 0x52, 0x60, 0xF7, 0x89, 0xF9, 0xC3, 0x25, 0x52, 0x94, 0x17, 0x23, + 0xC9, 0x07, 0xA4, 0x7F, 0xBA, 0x15, 0xB8, 0x20, 0x39, 0xAA, 0x6E, 0xF9, 0xF7, 0x1F, 0xCD, 0x8C, + 0xF6, 0xA3, 0xF9, 0x34, 0x02, 0xDB, 0xC6, 0x10, 0x7A, 0x28, 0x33, 0x09, 0x5E, 0x65, 0x68, 0x08, + 0xF2, 0xC2, 0x84, 0xCD, 0x72, 0xA1, 0x69, 0xB5, 0xA2, 0x37, 0x70, 0xC6, 0xA8, 0x32, 0x1F, 0x71, + 0x8C, 0xCD, 0x30, 0x1A, 0xDD, 0x58, 0x7D, 0x39, 0x09, 0x92, 0xDD, 0x20, 0x14, 0x03, 0x00, 0xA8, + 0xCF, 0xF0, 0x90, 0x0C, 0x85, 0x30, 0xC3, 0xB0, 0xDE, 0xF5, 0xF5, 0xE1, 0x69, 0x73, 0x40, 0xF3, + 0xE1, 0xF5, 0x7C, 0x32, 0xDE, 0x8D, 0xD3, 0x9D, 0x3F, 0xD0, 0xCD, 0xF5, 0xEE, 0xAB, 0x52, 0xB1, + 0x91, 0x02, 0x08, 0xF1, 0x36, 0xFF, 0x4F, 0x89, 0xB1, 0x99, 0x2F, 0x5A, 0x28, 0x1B, 0x90, 0x86, + 0x06, 0x30, 0x72, 0x3D, 0x18, 0xAA, 0x6F, 0x35, 0x1E, 0x9E, 0x28, 0x4F, 0x30, 0x5A, 0x84, 0xA5, + 0x86, 0x12, 0x33, 0x3C, 0xE3, 0xA8, 0xAD, 0x13, 0xE5, 0xB9, 0x6D, 0xBF, 0x65, 0x55, 0xB8, 0x2A, + 0x27, 0x90, 0x3F, 0xC4, 0x9A, 0x2B, 0x4D, 0x5A, 0x69, 0xD2, 0xC6, 0x6C, 0x2F, 0xBC, 0x18, 0xC8, + 0x98, 0x8E, 0x4C, 0xDD, 0xCA, 0x3A, 0x48, 0x80, 0x32, 0x61, 0x8C, 0x81, 0x82, 0x4A, 0x88, 0x8A, + 0x91, 0x67, 0xEF, 0xE4, 0xD8, 0x89, 0xBE, 0x4B, 0x83, 0x7A, 0x2B, 0x58, 0x23, 0x4F, 0xF9, 0xC9, + 0xAB, 0xE1, 0x44, 0xAA, 0x5A, 0xB5, 0x9D, 0x39, 0x71, 0x60, 0xF5, 0xA4, 0xCD, 0x9F, 0x2F, 0x76, + 0x76, 0xCC, 0xAB, 0xA0, 0x7B, 0xA9, 0xC5, 0xCF, 0xFD, 0xF1, 0xD5, 0x88, 0x15, 0x32, 0x6C, 0x92, + 0x2D, 0x42, 0x65, 0x06, 0xA2, 0xA7, 0xE2, 0xE6, 0xA7, 0x25, 0xA8, 0x74, 0xD1, 0x83, 0x6A, 0x97, + 0x06, 0x0F, 0x06, 0x59, 0x57, 0x89, 0xF6, 0xFE, 0x6B, 0xE5, 0x1D, 0x7B, 0x3C, 0xF8, 0xF7, 0x5F, + 0xCB, 0x36, 0x44, 0x12, 0x3E, 0x53, 0xD2, 0x89, 0xCE, 0x44, 0x4B, 0x1B, 0x7D, 0x42, 0xC4, 0x62, + 0xFB, 0xE7, 0x33, 0x48, 0x09, 0xED, 0xB9, 0x80, 0xA7, 0xF5, 0x4F, 0x95, 0xD0, 0xB0, 0xFE, 0xA6, + 0xB8, 0xA8, 0x40, 0xF5, 0x4B, 0x0D, 0x43, 0xF8, 0xE4, 0x4C, 0x64, 0x88, 0x5E, 0xF7, 0x7E, 0x6A, + 0x1D, 0x15, 0x25, 0x50, 0x1E, 0x3B, 0x67, 0xC3, 0xF5, 0x62, 0xA3, 0xD0, 0x99, 0x82, 0xB2, 0xFE, + 0xFB, 0xA7, 0xD2, 0x56, 0x70, 0x89, 0xAA, 0x2F, 0x99, 0x62, 0xCF, 0xE6, 0xE9, 0xCA, 0x1C, 0xE3, + 0x91, 0x28, 0x55, 0x4B, 0xE9, 0x7A, 0xD1, 0xC2, 0xA5, 0x89, 0x61, 0x8C, 0x1E, 0x0C, 0x22, 0x96, + 0xEF, 0x19, 0x2A, 0x10, 0x79, 0xCD, 0x3A, 0x58, 0x39, 0xA5, 0xEE, 0xAF, 0xD5, 0x70, 0x6F, 0xA9, + 0x81, 0xCF, 0xC9, 0x77, 0xC5, 0x43, 0x9D, 0x4A, 0xAA, 0xD1, 0xC1, 0x01, 0x2E, 0x6A, 0xD7, 0xD0, + 0x9F, 0xDE, 0x67, 0x0B, 0xB6, 0xA1, 0x4D, 0xBD, 0xE6, 0x16, 0xDD, 0xEC, 0x4A, 0x63, 0xD8, 0xBD, + 0x41, 0xD7, 0x4F, 0xC5, 0xE5, 0x43, 0x38, 0x72, 0xA5, 0x95, 0x37, 0x4F, 0x87, 0x4C, 0xAF, 0x78, + 0x90, 0x0F, 0x76, 0x0E, 0x49, 0xE7, 0x11, 0xF9, 0x29, 0x4E, 0x5E, 0xC8, 0x2A, 0x02, 0xC7, 0x2F, + 0x65, 0x81, 0x11, 0x97, 0xF1, 0x84, 0x9F, 0x99, 0xA8, 0x03, 0xE0, 0x69, 0x1A, 0xE3, 0x06, 0x40, + 0x22, 0xD0, 0xE0, 0x5D, 0xFE, 0x3E, 0xE9, 0xEA, 0x90, 0xA0, 0xE2, 0x0F, 0x13, 0x01, 0x1B, 0xC1, + 0xBC, 0x63, 0xDD, 0x84, 0x02, 0x1D, 0xC7, 0x35, 0x90, 0xBC, 0xEF, 0x19, 0x48, 0x5F, 0x68, 0xB6, + 0x67, 0x72, 0x26, 0xEA, 0x2B, 0x01, 0x94, 0xE5, 0x37, 0xA4, 0x44, 0x68, 0x0F, 0xD1, 0x3E, 0x28, + 0x8E, 0x43, 0xA5, 0x39, 0xE7, 0xFF, 0xCC, 0x8D, 0x27, 0x93, 0x3F, 0x59, 0x24, 0x3B, 0x93, 0x08, + 0x51, 0x5A, 0x9F, 0x96, 0x04, 0x4D, 0x94, 0xE5, 0xCD, 0xFB, 0x90, 0x24, 0x23, 0x0C, 0xBB, 0x44, + 0x3C, 0xEC, 0xB4, 0x48, 0x62, 0xFC, 0x86, 0xA8, 0x21, 0xA1, 0xF4, 0xA9, 0xF9, 0x29, 0x13, 0xA3, + 0x83, 0x82, 0xF0, 0xF9, 0x51, 0x20, 0x9C, 0x6C, 0x01, 0xB7, 0xEA, 0x10, 0xE8, 0xF6, 0xC5, 0x85, + 0x9B, 0xAE, 0xA3, 0x21, 0x30, 0x44, 0xE3, 0xE8, 0x29, 0xE2, 0x96, 0x97, 0x53, 0x66, 0x70, 0x44, + 0x61, 0xB8, 0xDB, 0xA6, 0xED, 0xF5, 0x7A, 0x1E, 0x82, 0xC2, 0x42, 0x53, 0x27, 0xD7, 0x49, 0x77, + 0x29, 0xCA, 0x6F, 0x41, 0x3A, 0xDB, 0xB2, 0x3B, 0xD6, 0xF8, 0x1F, 0xC5, 0xD2, 0x83, 0xEE, 0xD1, + 0xFA, 0xF2, 0x79, 0x54, 0x8D, 0xB3, 0x36, 0x34, 0xA9, 0x07, 0x8E, 0x10, 0xB2, 0xEE, 0x7E, 0x55, + 0x89, 0x79, 0x6E, 0x3B, 0xF0, 0xD6, 0x6A, 0xB7, 0x78, 0x7D, 0xF6, 0xB3, 0x4E, 0xAA, 0xFA, 0x36, + 0x12, 0x64, 0xBE, 0x82, 0x33, 0x74, 0xAC, 0x5F, 0x9B, 0x17, 0xA2, 0x5B, 0x9E, 0x10, 0xCE, 0x89, + 0xC2, 0x30, 0x20, 0x63, 0x60, 0xA0, 0x89, 0xA5, 0x26, 0xD6, 0x88, 0xF4, 0x5D, 0x14, 0xB9, 0xC1, + 0x4C, 0x13, 0xBB, 0x39, 0xED, 0x4E, 0x16, 0x32, 0x4C, 0xDF, 0x82, 0xA4, 0xEA, 0xA6, 0x21, 0xA7, + 0xA7, 0x20, 0xF8, 0xD4, 0x0F, 0xA7, 0x76, 0x5B, 0x31, 0x62, 0xCF, 0xD6, 0xFF, 0x92, 0x9A, 0xBA, + 0xDE, 0xAF, 0x4A, 0xA2, 0xB7, 0x82, 0x10, 0x96, 0x5A, 0x15, 0x6A, 0x55, 0xE7, 0x71, 0x16, 0x3E, + 0x25, 0x4F, 0x64, 0x47, 0x44, 0x60, 0xBC, 0x3D, 0x4A, 0x77, 0x1F, 0xC8, 0x1B, 0xF6, 0x9A, 0x0D, + 0x6E, 0x7E, 0x25, 0x5E, 0x28, 0x29, 0x19, 0x40, 0xAE, 0x27, 0x83, 0x05, 0x7C, 0xF8, 0xBA, 0x3D, + 0x96, 0x5C, 0x39, 0x9C, 0xEE, 0x9B, 0xDF, 0xD2, 0x9A, 0xAC, 0xAF, 0x36, 0x45, 0xB4, 0x65, 0x11, + 0x2E, 0x4F, 0xAF, 0xC5, 0xFF, 0xAE, 0x69, 0xA7, 0x78, 0x39, 0x6B, 0x5D, 0x35, 0x79, 0x06, 0x28, + 0x19, 0x9E, 0x35, 0x6A, 0xDE, 0x2D, 0x15, 0xA3, 0x1A, 0x12, 0x32, 0xCF, 0x76, 0x45, 0xA8, 0x8A, + 0xA4, 0xB2, 0x3D, 0xEC, 0xFC, 0x17, 0x1E, 0x90, 0x31, 0x7D, 0x79, 0xED, 0x3E, 0x87, 0x79, 0x51, + 0x29, 0xDF, 0x90, 0x94, 0x24, 0x0E, 0x41, 0x68, 0x73, 0xA5, 0xED, 0x20, 0xF8, 0x28, 0x48, 0xCC, + 0xCC, 0x46, 0x3B, 0x20, 0xBF, 0x1A, 0xDB, 0x03, 0x78, 0xE4, 0x5A, 0xE2, 0xA1, 0xA4, 0x86, 0x3D, + 0x47, 0xA3, 0x19, 0x6F, 0xE3, 0x30, 0xF9, 0x59, 0xF6, 0xEB, 0xE6, 0xEB, 0x7A, 0x65, 0x30, 0xF1, + 0x5A, 0xDF, 0xA8, 0x41, 0x87, 0x01, 0x19, 0x6B, 0x1B, 0xC8, 0x4B, 0xFA, 0x79, 0x89, 0x69, 0xC7, + 0xA2, 0xD3, 0xD8, 0xF3, 0x7F, 0xE2, 0x1C, 0x32, 0x98, 0x42, 0x23, 0xD1, 0x47, 0x50, 0x6D, 0x91, + 0x46, 0xB3, 0xB4, 0xB6, 0xE3, 0x17, 0x23, 0xC1, 0x97, 0x07, 0x9A, 0x77, 0x8F, 0x68, 0x8A, 0x0B, + 0xA8, 0x4B, 0x81, 0x2D, 0xF4, 0x9C, 0x20, 0x67, 0x2D, 0xC5, 0x36, 0xF7, 0x43, 0xB2, 0xE7, 0x5D, + 0xD3, 0xD9, 0x44, 0x34, 0x6B, 0xFF, 0x9E, 0x47, 0x12, 0xCB, 0xBD, 0x2E, 0x0A, 0x86, 0x6A, 0xFE, + 0x94, 0x82, 0x46, 0xC6, 0x44, 0xB2, 0xB3, 0x75, 0x5C, 0x2E, 0x08, 0xA5, 0xBE, 0x98, 0x3D, 0x98, + 0x08, 0x07, 0xA8, 0x77, 0x0F, 0x78, 0xB6, 0xF0, 0x82, 0x30, 0x52, 0xEF, 0xC5, 0x65, 0xDA, 0xA7, + 0x63, 0x52, 0xF1, 0x6D, 0x64, 0x1C, 0xBC, 0x9E, 0xEA, 0x38, 0x7A, 0x76, 0x01, 0xC8, 0x76, 0x93, + 0xEC, 0x39, 0x56, 0x20, 0x2A, 0x39, 0xC7, 0x91, 0x57, 0x7C, 0x5A, 0xFC, 0x25, 0x60, 0xE0, 0x3D, + 0x01, 0x59, 0xB9, 0x3C, 0xFC, 0x85, 0xD3, 0x5D, 0x75, 0x13, 0xDB, 0x47, 0x5B, 0xF7, 0xBD, 0x96, + 0x09, 0xDB, 0x97, 0xBE, 0x96, 0x97, 0xE1, 0xCB, 0x4A, 0x11, 0xE4, 0xEE, 0xCE, 0xC5, 0x1F, 0x53, + 0xAA, 0x5F, 0xCF, 0x0C, 0x37, 0xBF, 0xC3, 0xEC, 0xDA, 0x21, 0xA6, 0xA9, 0x5D, 0xCF, 0x84, 0xBF, + 0xC3, 0x30, 0x3C, 0x0D, 0x1C, 0x11, 0x5F, 0x63, 0x94, 0x88, 0x05, 0xBF, 0x33, 0xA5, 0xD2, 0x75, + 0xDD, 0xD9, 0x20, 0xA1, 0x4F, 0x11, 0x75, 0x29, 0xA9, 0x72, 0x60, 0x35, 0xF1, 0x90, 0xDA, 0xFE, + 0x4D, 0xFD, 0xB2, 0x10, 0xD4, 0x3D, 0x3E, 0xBF, 0x1F, 0xA1, 0xC4, 0x0F, 0x5B, 0x36, 0x6D, 0x8A, + 0x51, 0xBF, 0x87, 0xAA, 0x12, 0xC7, 0xC4, 0xF4, 0x1B, 0x0B, 0xFF, 0xDB, 0x1B, 0x2B, 0xEF, 0x9C, + 0x2D, 0xC5, 0x8B, 0x70, 0xD2, 0x3B, 0xFE, 0xF5, 0xB4, 0x9D, 0x08, 0x46, 0x67, 0xDD, 0xAF, 0x41, + 0x5B, 0xC5, 0x16, 0x8F, 0xD7, 0x51, 0x4D, 0x1C, 0x71, 0x15, 0x14, 0xA7, 0x7B, 0x43, 0x3F, 0x58, + 0x58, 0x80, 0x70, 0xDE, 0x3D, 0x9B, 0x55, 0x39, 0xA4, 0x8D, 0x59, 0xF6, 0xC8, 0xAA, 0x81, 0xA0, + 0x78, 0x45, 0xE5, 0x44, 0xAC, 0xCF, 0xD1, 0x01, 0x52, 0x3C, 0x6C, 0x98, 0x52, 0xE6, 0xC2, 0x10, + 0xA9, 0x48, 0x40, 0xF6, 0xB1, 0xD5, 0xFF, 0xB3, 0x6F, 0xC5, 0xCC, 0x30, 0xF4, 0x81, 0xF8, 0x7F, + 0xAD, 0x95, 0xED, 0xB9, 0x06, 0xEB, 0x70, 0x49, 0xFD, 0xA1, 0x67, 0x33, 0xBC, 0x5A, 0x0F, 0x0F, + 0x83, 0x8C, 0x02, 0x91, 0x7D, 0xA1, 0x74, 0x3A, 0x9E, 0x13, 0x4D, 0x50, 0x51, 0x2E, 0xA4, 0xD1, + 0x51, 0xF3, 0x9C, 0x8F, 0x85, 0x6F, 0xED, 0x10, 0xD7, 0x1A, 0x49, 0xE4, 0x80, 0x94, 0xC0, 0xAA, + 0x4B, 0x0C, 0x7A, 0x4D, 0xFD, 0x69, 0x89, 0x20, 0x01, 0xDD, 0xBE, 0xFF, 0xFA, 0xF4, 0x15, 0xDB, + 0xD6, 0x8D, 0xB3, 0x3D, 0x62, 0xD4, 0xFF, 0x36, 0x24, 0xF5, 0x88, 0x67, 0xEF, 0xEB, 0x65, 0x6B, + 0xB6, 0x69, 0x0C, 0x53, 0xA7, 0x1B, 0x6A, 0x47, 0xC3, 0xB8, 0x54, 0xBE, 0xE5, 0x65, 0xA8, 0x75, + 0xC1, 0xAE, 0xC7, 0x15, 0x35, 0x84, 0x2C, 0xB9, 0x8E, 0x97, 0x24, 0xDF, 0x52, 0x30, 0x1C, 0x4E, + 0xE5, 0x1E, 0xF3, 0x35, 0x8B, 0xD7, 0xFE, 0x27, 0x6C, 0x80, 0xFE, 0x20, 0xA0, 0x0E, 0x28, 0xC9, + 0xA3, 0x15, 0xA6, 0x52, 0x77, 0x93, 0x79, 0x1F, 0x0E, 0xDC, 0xF0, 0x44, 0x2B, 0x27, 0x67, 0x9D, + 0x50, 0x99, 0xF8, 0x6D, 0xA7, 0x78, 0x76, 0x71, 0x9D, 0xBB, 0x94, 0xA1, 0x7D, 0x5C, 0xBA, 0x9A, + 0x66, 0xC3, 0xF9, 0x92, 0x9F, 0x42, 0x20, 0xC1, 0x9A, 0xBC, 0xC2, 0x5E, 0x91, 0xFD, 0x8D, 0xD1, + 0x96, 0xDC, 0x41, 0x1F, 0xA0, 0x4C, 0xCC, 0x92, 0x7C, 0x81, 0x88, 0x04, 0xC6, 0xF2, 0xEE, 0x49, + 0xA6, 0xBE, 0x61, 0x2F, 0xF2, 0x07, 0x15, 0x79, 0x53, 0x7E, 0x1A, 0x0C, 0xA0, 0x32, 0x1E, 0x7D, + 0x69, 0x2E, 0x48, 0xA8, 0x34, 0x27, 0xF2, 0x35, 0x93, 0xE8, 0x10, 0x25, 0x6E, 0xC7, 0x07, 0xAD, + 0xB9, 0xA0, 0x56, 0x11, 0xFF, 0xBD, 0x19, 0x97, 0x39, 0x68, 0x1C, 0xB9, 0xF5, 0x53, 0x6B, 0x37, + 0x1C, 0x05, 0xFF, 0xF4, 0x93, 0x69, 0x9C, 0x3B, 0x7C, 0x35, 0xF7, 0xFC, 0x94, 0xFF, 0x3A, 0x1F, + 0x62, 0x5C, 0xAF, 0x4F, 0x69, 0x24, 0xE4, 0xA9, 0x14, 0xF5, 0x3F, 0xA6, 0x68, 0x53, 0x8B, 0x42, + 0x6F, 0xE4, 0xEE, 0x24, 0xFA, 0x7D, 0xB7, 0x71, 0x8A, 0xF0, 0x9F, 0x6E, 0xD3, 0x2B, 0x74, 0xBD, + 0x89, 0xA6, 0x79, 0x38, 0x32, 0xAB, 0x54, 0x60, 0xEA, 0x64, 0x1E, 0xB3, 0xFC, 0x6C, 0x67, 0x91, + 0x6E, 0x0E, 0xBE, 0xB2, 0xFA, 0x74, 0x32, 0x60, 0x74, 0x2E, 0x24, 0x2B, 0x0F, 0x15, 0x03, 0xBC, + 0x75, 0xCC, 0x8F, 0xAD, 0xA6, 0xDF, 0xCE, 0x51, 0xBC, 0x22, 0x68, 0x24, 0x4C, 0x60, 0xA0, 0x19, + 0xB0, 0x1B, 0x90, 0x21, 0xB7, 0x3B, 0x8C, 0xDE, 0xAB, 0xB8, 0x60, 0xDE, 0x78, 0x4E, 0x28, 0x9D, + 0x80, 0xFD, 0x09, 0x9C, 0xC4, 0xFB, 0xCC, 0xAC, 0x58, 0x89, 0xE3, 0xC2, 0x37, 0x54, 0x7F, 0xEE, + 0x5B, 0x1F, 0x9E, 0xF6, 0x7C, 0xF6, 0xA5, 0xA5, 0xEF, 0x91, 0x9D, 0xC1, 0x27, 0xBA, 0xBA, 0x17, + 0xAA, 0xDF, 0x03, 0x33, 0x16, 0x7A, 0xD2, 0x85, 0x3A, 0x33, 0xE0, 0x99, 0xA4, 0xAB, 0xC3, 0x0E, + 0xD4, 0x4B, 0x21, 0x4D, 0x0D, 0x73, 0x1A, 0x46, 0x44, 0xA9, 0x0E, 0x6E, 0xD1, 0xA3, 0x1D, 0x5E, + 0x37, 0x8A, 0xF1, 0x56, 0x11, 0xD1, 0xF2, 0xE5, 0x62, 0x0F, 0x1E, 0xDC, 0x76, 0x2D, 0x25, 0x04, + 0xFB, 0x34, 0x4D, 0x27, 0x9B, 0x01, 0xF0, 0x73, 0xA5, 0xBA, 0x9C, 0x1D, 0x2A, 0x00, 0x91, 0x21, + 0x31, 0x01, 0x87, 0x2D, 0x91, 0x53, 0xE4, 0xFE, 0x88, 0xB4, 0x47, 0xF1, 0xA4, 0xC5, 0x21, 0x9C, + 0x48, 0x88, 0x81, 0x1E, 0x83, 0x9F, 0x2E, 0x1A, 0xE8, 0xC5, 0x59, 0xBC, 0x3F, 0x43, 0xFF, 0xC4, + 0x06, 0xF3, 0x5C, 0x04, 0x46, 0x66, 0x20, 0xDC, 0xC0, 0xC3, 0x95, 0x88, 0x54, 0xC7, 0x83, 0x3D, + 0x4C, 0xA8, 0x6D, 0x92, 0x9A, 0x77, 0x53, 0xAE, 0x92, 0x62, 0x0B, 0xDD, 0x68, 0xA9, 0xB7, 0x7F, + 0xAC, 0x21, 0xB0, 0x82, 0xBF, 0x53, 0x18, 0x31, 0x6F, 0x5D, 0xE5, 0xD4, 0x08, 0x50, 0x1D, 0xBE, + 0x4D, 0xDC, 0xAC, 0xE3, 0x5A, 0xF9, 0x05, 0xBB, 0x50, 0x61, 0x1D, 0x3C, 0xF2, 0x46, 0xD6, 0x07, + 0x17, 0x89, 0x34, 0xCB, 0x77, 0x95, 0x9E, 0xBD, 0x97, 0xEB, 0x3A, 0x20, 0x50, 0x3A, 0xCC, 0x2E, + 0xC4, 0xFA, 0xDC, 0x99, 0xB6, 0xB0, 0x24, 0xBF, 0xDA, 0x49, 0x04, 0x9D, 0xF2, 0xFE, 0xB1, 0x87, + 0x67, 0x9B, 0x30, 0x81, 0x55, 0x69, 0x88, 0xD3, 0x0C, 0x67, 0x9F, 0x7C, 0x06, 0x56, 0x5B, 0x40, + 0x7F, 0x73, 0xF4, 0x58, 0x75, 0xD4, 0x2D, 0xE6, 0xA0, 0xA9, 0xE0, 0x53, 0xFD, 0xB2, 0xF1, 0x60, + 0xDB, 0x82, 0x2F, 0x10, 0x4A, 0x0D, 0x8F, 0xD5, 0x27, 0x4F, 0x72, 0xAF, 0x2D, 0x03, 0x22, 0xA0, + 0x72, 0xA8, 0x56, 0xD3, 0x8F, 0xBD, 0x04, 0x00, 0x45, 0x6D, 0xB0, 0x64, 0xB3, 0x0D, 0x63, 0x8F, + 0x58, 0xF1, 0xA0, 0xE8, 0x04, 0x23, 0xF0, 0x5A, 0x07, 0x61, 0x0E, 0xDF, 0x96, 0xCB, 0x98, 0x58, + 0x73, 0x90, 0xDF, 0xBB, 0x05, 0x30, 0x7D, 0x39, 0x19, 0xBA, 0x46, 0x8C, 0x2C, 0xA8, 0xBC, 0xA1, + 0x12, 0xBA, 0x8B, 0x01, 0xC5, 0x0C, 0xC4, 0x60, 0x53, 0x6F, 0xD1, 0xE2, 0x03, 0x63, 0x88, 0xD5, + 0x54, 0x0D, 0xCD, 0xD6, 0xEB, 0x7F, 0xF8, 0x1D, 0xEF, 0x50, 0x53, 0x5D, 0xC6, 0x65, 0x75, 0xB5, + 0x5D, 0xD9, 0x62, 0xAC, 0xE7, 0x94, 0x2D, 0xA7, 0xF2, 0x50, 0x7A, 0x68, 0x9B, 0x75, 0x4E, 0xC0, + 0xD9, 0x31, 0xB9, 0x7E, 0x99, 0xA5, 0x28, 0xB4, 0x7D, 0x64, 0xF4, 0x51, 0xBE, 0x1A, 0xBA, 0xCD, + 0xBD, 0xCC, 0xE4, 0xE1, 0x04, 0xEA, 0xBA, 0x1C, 0x43, 0x1D, 0x6C, 0x85, 0xF7, 0xEB, 0xA2, 0x14, + 0x07, 0xDB, 0x41, 0xD0, 0x77, 0x7A, 0x9C, 0x46, 0xF8, 0xC7, 0xF2, 0xE6, 0x9F, 0x09, 0x8D, 0x86, + 0x0C, 0x1B, 0xFC, 0x41, 0xD5, 0xD1, 0x7E, 0x19, 0xF1, 0x8C, 0xE5, 0x1B, 0xCB, 0x8F, 0x16, 0xF5, + 0x65, 0x48, 0xAC, 0x57, 0x1A, 0xB1, 0x5A, 0x12, 0xD9, 0xBD, 0xA6, 0xF7, 0x32, 0x3C, 0x26, 0x1A, + 0x29, 0x05, 0xB0, 0x18, 0x16, 0xE9, 0xEB, 0xF9, 0x06, 0x74, 0xCA, 0x3B, 0xB0, 0x20, 0x6B, 0x78, + 0x8F, 0xE2, 0x33, 0x0A, 0x3D, 0xC7, 0x90, 0x2C, 0x28, 0x8F, 0x5C, 0x4A, 0xB8, 0x1E, 0x37, 0x3D, + 0x24, 0xF5, 0xF1, 0x05, 0x72, 0x13, 0xB9, 0xBD, 0xAC, 0x32, 0xA5, 0x68, 0x68, 0xFF, 0x7E, 0x64, + 0xD2, 0x84, 0xA4, 0x04, 0xF5, 0xE7, 0x2D, 0xF9, 0xA0, 0xDB, 0x58, 0x80, 0x5F, 0x46, 0xFE, 0xB9, + 0x81, 0x4C, 0x40, 0x23, 0x93, 0x09, 0x44, 0xC7, 0x5B, 0xB7, 0x1E, 0x09, 0xB9, 0x78, 0x75, 0xAE, + 0xD6, 0xFE, 0xB7, 0x33, 0x4E, 0xE7, 0x8A, 0x24, 0x2F, 0x3B, 0xB7, 0x2A, 0xC2, 0x76, 0x60, 0x6B, + 0x70, 0x23, 0xA3, 0x87, 0x2F, 0xFA, 0xE2, 0x57, 0xDA, 0x4D, 0x10, 0xB9, 0x64, 0x65, 0xE5, 0x68, + 0x3C, 0x83, 0xB9, 0x1D, 0xA5, 0x1B, 0xF3, 0xEC, 0x60, 0x6A, 0x75, 0x6D, 0x2D, 0x7D, 0xE5, 0x25, + 0x5A, 0x4E, 0x4E, 0xB4, 0xF1, 0xFE, 0xA4, 0x42, 0xB2, 0x90, 0x7F, 0xA7, 0xEF, 0x50, 0xB9, 0xAC, + 0xB6, 0x55, 0xE1, 0xD5, 0x96, 0x5C, 0x71, 0x8F, 0x62, 0xAD, 0xC3, 0x2B, 0xC9, 0xD8, 0x02, 0xCE, + 0xD5, 0x59, 0xC1, 0xB6, 0x64, 0x20, 0x63, 0xE3, 0xE6, 0x61, 0x15, 0x01, 0x8A, 0xE7, 0xD1, 0xB0, + 0xBA, 0xD9, 0x4E, 0x22, 0x1E, 0x7C, 0x12, 0x1B, 0xBC, 0xF3, 0x01, 0x01, 0x3D, 0x50, 0xC9, 0x72, + 0xC4, 0x61, 0xF1, 0xC8, 0x46, 0x7D, 0x59, 0x0B, 0x7F, 0x93, 0x2E, 0x2F, 0xF1, 0x37, 0xBD, 0x0A, + 0x4B, 0x0B, 0x5A, 0xD6, 0x6B, 0xAE, 0x58, 0x07, 0x00, 0xD8, 0x28, 0x20, 0x45, 0xD7, 0x5A, 0xED, + 0x3F, 0xFE, 0x71, 0x98, 0xD9, 0xAB, 0x05, 0x4A, 0xB1, 0xC5, 0xEA, 0x43, 0x42, 0xC0, 0x4D, 0xDD, + 0xAD, 0x0A, 0x6F, 0xA0, 0x54, 0x21, 0x13, 0x8F, 0x7B, 0x87, 0x05, 0x7A, 0x9D, 0x53, 0x7E, 0x69, + 0xD3, 0x0E, 0x7E, 0x05, 0xAF, 0x6B, 0x67, 0xB0, 0x74, 0x62, 0x7F, 0x1D, 0x9E, 0x6B, 0x79, 0x41, + 0x28, 0x05, 0x67, 0xC9, 0xF2, 0xA3, 0x04, 0x53, 0xC6, 0xB4, 0x11, 0x8A, 0x1F, 0xC2, 0xC3, 0xBA, + 0x68, 0xBC, 0x71, 0x43, 0x32, 0x64, 0x58, 0x92, 0x06, 0x84, 0x73, 0x2C, 0xE6, 0x67, 0x3E, 0x87, + 0x34, 0x5F, 0x3D, 0xC8, 0x79, 0xE4, 0xD6, 0xBE, 0x35, 0xA0, 0x47, 0x32, 0x8C, 0xE8, 0x56, 0x71, + 0x9E, 0x16, 0xA7, 0x41, 0x24, 0xC7, 0x54, 0x09, 0xC6, 0xD9, 0xC2, 0x8A, 0x4B, 0x13, 0xC4, 0xD0, + 0x5A, 0x0C, 0xFF, 0x96, 0xA1, 0xE9, 0xE4, 0xD9, 0x8D, 0x16, 0x26, 0x16, 0xDD, 0x64, 0xE7, 0x82, + 0x86, 0xB3, 0xD0, 0x4C, 0x34, 0x64, 0x07, 0x3C, 0x01, 0x7A, 0xB4, 0x85, 0xC0, 0xF7, 0xED, 0x36, + 0x77, 0x10, 0x7C, 0x56, 0xD7, 0xBB, 0x1E, 0x8A, 0x64, 0x91, 0x26, 0x4F, 0x18, 0x80, 0x3E, 0xB1, + 0x21, 0xCD, 0x56, 0x44, 0x9C, 0xA1, 0x9A, 0x54, 0xCA, 0x0E, 0x23, 0xC5, 0xF9, 0x2E, 0x18, 0x00, + 0xD8, 0x82, 0xD5, 0xBC, 0x53, 0x3A, 0xD9, 0xA1, 0xBB, 0x44, 0xAD, 0xB1, 0x9C, 0xA3, 0x0F, 0x48, + 0x90, 0x09, 0xC6, 0x17, 0xC3, 0xF0, 0x23, 0x1C, 0x72, 0x5D, 0x8C, 0xDD, 0x8F, 0xD9, 0x9B, 0x3C, + 0x8A, 0x8F, 0xBC, 0x4C, 0x60, 0x6F, 0x52, 0x5A, 0x87, 0x6F, 0xA6, 0x53, 0x04, 0x84, 0x29, 0x72, + 0x4C, 0x47, 0xDE, 0x86, 0x11, 0xBC, 0x4A, 0x6D, 0x10, 0xC3, 0xD4, 0x2F, 0xAA, 0x99, 0x33, 0x8F, + 0x74, 0x71, 0x41, 0x42, 0xFA, 0x7C, 0xA6, 0x4F, 0x34, 0xDA, 0xF2, 0xC5, 0x5D, 0xAE, 0x7A, 0x6C, + 0x16, 0xB1, 0xCF, 0x34, 0x87, 0x8D, 0xAF, 0x4A, 0x37, 0x19, 0x04, 0xA7, 0x5B, 0x40, 0x67, 0x10, + 0xFC, 0xA4, 0xDE, 0xD3, 0x43, 0xA5, 0xE0, 0x54, 0x15, 0xB5, 0x47, 0x64, 0x7E, 0xCA, 0x7E, 0x60, + 0x6D, 0x4C, 0x26, 0xBA, 0x18, 0xB7, 0x24, 0xFB, 0x5F, 0xB4, 0x4C, 0x0C, 0x06, 0x7F, 0xAD, 0xEB, + 0xA1, 0xE9, 0xF0, 0xFB, 0x11, 0xBD, 0xEF, 0xFA, 0x4F, 0xB5, 0x4A, 0xA1, 0xE7, 0x09, 0xA5, 0xB6, + 0xD5, 0x8D, 0xA7, 0x42, 0xEF, 0xE4, 0x30, 0x3F, 0x2E, 0xD1, 0x49, 0xA0, 0x06, 0xE6, 0x62, 0xE8, + 0xC7, 0x7D, 0x10, 0x26, 0xB4, 0xF2, 0x94, 0x8C, 0x68, 0x9B, 0x2E, 0xAE, 0x1B, 0x98, 0xB2, 0x1B, + 0x20, 0x6C, 0xB2, 0x3C, 0x41, 0xA7, 0xE0, 0x4B, 0xDE, 0xFA, 0xA6, 0xCE, 0x91, 0xCA, 0xBC, 0x18, + 0x86, 0x46, 0x07, 0x0D, 0x0A, 0x3D, 0xB7, 0x07, 0x89, 0xE5, 0x93, 0xB6, 0x32, 0xFF, 0xD9, 0x78, + 0xA4, 0x60, 0xF5, 0xAB, 0x7B, 0x62, 0x63, 0x6B, 0x5F, 0x6A, 0xA1, 0x5E, 0x7C, 0x30, 0x75, 0x26, + 0xD2, 0xA9, 0xE1, 0x01, 0x08, 0x8C, 0x96, 0xB3, 0xE0, 0x13, 0x05, 0xDA, 0x0E, 0xBB, 0x08, 0x1C, + 0x51, 0xE6, 0x44, 0xC3, 0x02, 0xA8, 0x98, 0x92, 0x71, 0x49, 0x60, 0x28, 0x33, 0xEF, 0xE5, 0x10, + 0x41, 0x21, 0x0A, 0x14, 0x6D, 0x54, 0x42, 0x1B, 0x42, 0xA9, 0x29, 0x16, 0xDB, 0x1F, 0x71, 0x63, + 0x9E, 0x4A, 0x35, 0xD7, 0xC3, 0x2F, 0x41, 0x66, 0xB2, 0x85, 0xD6, 0xA4, 0x2A, 0x9C, 0xA0, 0x6F, + 0x8D, 0x58, 0x43, 0x85, 0xE6, 0x46, 0x53, 0xDD, 0x5C, 0x2C, 0x4B, 0xC5, 0xC7, 0xDE, 0x79, 0x48, + 0xAB, 0x0F, 0x48, 0x23, 0xCF, 0x01, 0x64, 0xA3, 0x0D, 0xE1, 0x5B, 0x14, 0xC5, 0xB2, 0x04, 0x0D, + 0xE4, 0x41, 0xB5, 0x28, 0x7F, 0xD2, 0xAD, 0x3A, 0x9E, 0xF0, 0x31, 0x82, 0x58, 0xA8, 0xED, 0x9C, + 0x53, 0x1C, 0x2F, 0x17, 0x53, 0x66, 0xCE, 0x20, 0x10, 0x1D, 0xAC, 0x53, 0x11, 0x82, 0xD3, 0xA8, + 0x4F, 0x6F, 0xFE, 0x94, 0x3C, 0xF1, 0x57, 0x6F, 0x89, 0xD8, 0xF3, 0x1F, 0x2E, 0xD2, 0x19, 0x0C, + 0x6A, 0x9D, 0x3D, 0x1A, 0xBE, 0x47, 0x16, 0x17, 0x4A, 0x7C, 0xD9, 0xB8, 0xE5, 0x09, 0x5A, 0x34, + 0x85, 0x8A, 0x6A, 0x23, 0x5B, 0x0D, 0x3D, 0x02, 0xCC, 0x1C, 0x29, 0x26, 0xBE, 0x93, 0x80, 0x13, + 0x2D, 0x39, 0x1F, 0x19, 0xDE, 0xF9, 0xF7, 0x08, 0x1A, 0x6E, 0x3A, 0x2A, 0x7D, 0x96, 0x13, 0x09, + 0x1B, 0x85, 0x79, 0x41, 0xE8, 0x92, 0xA8, 0x47, 0x55, 0x3E, 0x47, 0xFA, 0x15, 0x8E, 0x13, 0xAE, + 0x44, 0x83, 0xE2, 0xC7, 0xC7, 0x9F, 0x5F, 0x6D, 0x91, 0xEA, 0xDE, 0x60, 0x22, 0x27, 0x49, 0xAE, + 0xC3, 0x7F, 0xB8, 0x8D, 0x68, 0xEA, 0x1B, 0x04, 0xA3, 0x92, 0x06, 0x01, 0x85, 0xED, 0xA9, 0xF9, + 0x36, 0x45, 0x37, 0xC8, 0x3D, 0x93, 0x08, 0x08, 0x58, 0xCA, 0x16, 0xFB, 0x41, 0x0B, 0x26, 0x3D, + 0x35, 0xE0, 0x6D, 0x59, 0xD4, 0x98, 0x4E, 0x4C, 0xE8, 0x0B, 0x96, 0x90, 0x2D, 0x85, 0x3A, 0x8B, + 0xCB, 0x4B, 0x10, 0x5D, 0xDF, 0xE6, 0x60, 0x2E, 0x55, 0x95, 0x0B, 0x88, 0xAA, 0xCB, 0x91, 0xE1, + 0xB4, 0x9C, 0xAF, 0x41, 0xF2, 0x28, 0xAC, 0x21, 0xC6, 0x8D, 0xEB, 0x96, 0x3F, 0xC5, 0xEF, 0xA7, + 0x34, 0x91, 0xAA, 0x72, 0xCE, 0x1D, 0xA5, 0xEA, 0xF3, 0x9E, 0xE4, 0xBE, 0x08, 0x5F, 0xD1, 0xD9, + 0xC6, 0xD2, 0x4F, 0x9D, 0xC1, 0xE1, 0xA1, 0x75, 0x99, 0x2A, 0xCA, 0x00, 0x82, 0x1B, 0x64, 0x94, + 0xB8, 0x8F, 0x2B, 0xEB, 0x6C, 0xEE, 0x99, 0x54, 0x78, 0x4B, 0x17, 0x98, 0x62, 0xB5, 0x99, 0x20, + 0x26, 0x33, 0x50, 0x92, 0xE8, 0xD0, 0xF3, 0xBA, 0x40, 0x89, 0x95, 0x65, 0x58, 0x4C, 0x75, 0x8A, + 0xA0, 0xEB, 0x0C, 0xA1, 0xCA, 0x1E, 0x7E, 0x25, 0x5B, 0x14, 0x0F, 0x9D, 0xB5, 0xB5, 0x29, 0xC2, + 0x78, 0xF8, 0xD4, 0x9E, 0x5F, 0xF1, 0x83, 0x68, 0xCC, 0x18, 0x73, 0x55, 0x3C, 0xAD, 0xED, 0x2D, + 0x71, 0xA6, 0xDF, 0x99, 0x2E, 0x74, 0x74, 0xAE, 0xFA, 0xA1, 0xEB, 0x47, 0x88, 0x75, 0x9B, 0xCD, + 0x93, 0x82, 0xE4, 0x0E, 0x05, 0x14, 0x5D, 0x47, 0x38, 0x28, 0x86, 0x82, 0x68, 0x4A, 0xD0, 0x57, + 0x82, 0x62, 0xC7, 0x55, 0x26, 0x08, 0xF3, 0x38, 0xD7, 0x33, 0x3D, 0x69, 0x89, 0x5F, 0xEA, 0x7F, + 0x24, 0xBC, 0xF0, 0x05, 0x93, 0x92, 0xD6, 0xFB, 0xA5, 0x2B, 0x08, 0x52, 0x7D, 0x71, 0x0B, 0xA9, + 0x9F, 0x16, 0x93, 0x61, 0x0B, 0x89, 0x2C, 0x69, 0xDC, 0x2A, 0xFF, 0xC9, 0xB9, 0x3A, 0x76, 0xF0, + 0xF4, 0x37, 0x0D, 0x9D, 0x3A, 0xDC, 0xA5, 0xA7, 0x27, 0x05, 0x2B, 0xFC, 0x62, 0x80, 0x41, 0x1B, + 0x1E, 0x32, 0x64, 0xBE, 0x46, 0xA4, 0xF5, 0x32, 0xE0, 0xBC, 0x48, 0xA7, 0xDE, 0xAE, 0x87, 0xBE, + 0x14, 0x26, 0x9D, 0xC6, 0x91, 0xA1, 0x56, 0x8A, 0xBD, 0x3A, 0xC9, 0x08, 0x34, 0x8C, 0xB5, 0x32, + 0xFE, 0x9E, 0x45, 0x55, 0x97, 0x70, 0xD6, 0xC6, 0x3F, 0x12, 0xD7, 0xA2, 0x82, 0x6C, 0xA0, 0x28, + 0x34, 0xDA, 0x6C, 0xCA, 0x19, 0xC4, 0x86, 0x41, 0x82, 0x79, 0x96, 0xA1, 0x3A, 0x77, 0x81, 0x9A, + 0x43, 0x33, 0xF6, 0xF4, 0x89, 0x16, 0x45, 0x8D, 0xAA, 0xA9, 0xF9, 0xD5, 0x9A, 0xCB, 0x6C, 0xE2, + 0xF3, 0x2C, 0xB9, 0xD9, 0x3F, 0x6F, 0x2B, 0x34, 0x80, 0xE4, 0x59, 0x76, 0x3A, 0x44, 0x64, 0x00, + 0x73, 0x8A, 0x0A, 0x2C, 0xDA, 0x39, 0xE3, 0xB0, 0x1A, 0x5C, 0xC4, 0xAF, 0x22, 0x8F, 0xEA, 0xBD, + 0xAD, 0x30, 0x1A, 0xC5, 0xA5, 0xCC, 0x66, 0x8A, 0x9C, 0x42, 0xE3, 0x11, 0x48, 0xFF, 0x5E, 0x2C, + 0x46, 0xC9, 0xA2, 0x3B, 0x74, 0x18, 0x35, 0xF9, 0x25, 0x1F, 0xFA, 0xCA, 0xF8, 0xA5, 0x5C, 0x45, + 0x3F, 0x05, 0x15, 0xA8, 0x23, 0xDC, 0x6F, 0x25, 0xC1, 0x29, 0xEF, 0x8B, 0xD8, 0xC0, 0x6C, 0x49, + 0xC2, 0x44, 0xB7, 0xED, 0xA7, 0x18, 0x86, 0xF2, 0xCB, 0x71, 0xA9, 0x70, 0x2C, 0xD7, 0xFE, 0x7A, + 0x7C, 0xCC, 0x68, 0xAD, 0xA6, 0x02, 0xDC, 0x85, 0xA3, 0xC9, 0x54, 0xB4, 0x46, 0xC4, 0x39, 0xBF, + 0xB3, 0x6F, 0x13, 0xDB, 0xE8, 0x9C, 0xC8, 0x6B, 0xF6, 0xF5, 0x2B, 0xBE, 0x5D, 0xAB, 0xBA, 0xEE, + 0x8D, 0xDC, 0x39, 0xE5, 0x79, 0x3A, 0x9C, 0x74, 0x77, 0xD7, 0x34, 0x01, 0xC7, 0x50, 0x2C, 0x75, + 0xB0, 0x07, 0x64, 0x8C, 0xDE, 0x74, 0x14, 0xCB, 0x10, 0x15, 0xB4, 0x4C, 0x28, 0x13, 0x0D, 0x62, + 0x55, 0xDF, 0xF0, 0xD5, 0xF7, 0x3C, 0x42, 0x4A, 0xAA, 0x49, 0x3F, 0x68, 0x75, 0x9E, 0xD9, 0xA8, + 0x15, 0x7A, 0x32, 0xBD, 0x5A, 0xDB, 0x9F, 0x7E, 0x0A, 0x35, 0xAA, 0x21, 0x89, 0x5A, 0xE2, 0x91, + 0xA2, 0xE4, 0xE4, 0x66, 0x24, 0x4F, 0x43, 0x18, 0x36, 0xF8, 0xF7, 0x04, 0xFA, 0x90, 0x87, 0x38, + 0x21, 0xDF, 0x38, 0xAC, 0x0E, 0x58, 0x78, 0x2F, 0xFE, 0x87, 0x97, 0x4F, 0x8E, 0x3E, 0x31, 0x14, + 0x98, 0x5B, 0xA7, 0x21, 0xAC, 0x33, 0x7F, 0xE9, 0x3D, 0xD6, 0xE4, 0x7D, 0x17, 0x35, 0x2B, 0xA6, + 0x71, 0x3A, 0xEE, 0x47, 0x28, 0x1B, 0x2F, 0x93, 0xCE, 0x4F, 0xFE, 0x3D, 0x3E, 0xA4, 0x03, 0xB4, + 0x8F, 0xE0, 0x91, 0x1C, 0x82, 0x45, 0x2D, 0xD3, 0xA8, 0xC7, 0xE9, 0xF3, 0x9A, 0x1F, 0x0C, 0x0B, + 0x9F, 0x5E, 0x0C, 0x02, 0x37, 0x3F, 0xDE, 0x18, 0xB0, 0x93, 0x65, 0xD1, 0xB0, 0xCF, 0x4D, 0x6F, + 0x7C, 0x32, 0x8F, 0xFA, 0xFC, 0x41, 0x0E, 0x6E, 0xCE, 0x72, 0xEB, 0xDB, 0x9A, 0xB1, 0xAC, 0x5B, + 0xF5, 0x1A, 0x13, 0xE0, 0x43, 0x89, 0xA1, 0x22, 0xC8, 0x3A, 0x6A, 0x3D, 0xB8, 0x3F, 0x06, 0x57, + 0xBC, 0x61, 0xA7, 0x1F, 0x5E, 0x14, 0x4F, 0xE9, 0x83, 0x9A, 0xEA, 0xD2, 0xD9, 0x7A, 0xF4, 0x07, + 0x30, 0x95, 0x35, 0xEB, 0xBC, 0x81, 0x48, 0xDB, 0x08, 0xFA, 0xFF, 0xCF, 0x8B, 0xE5, 0x60, 0xCA, + 0x4D, 0xBE, 0x9C, 0x78, 0xA9, 0x89, 0x1D, 0xCE, 0xE1, 0x44, 0xCC, 0x21, 0x87, 0xDA, 0x6F, 0x40, + 0xC9, 0xFF, 0xC0, 0xA3, 0x5E, 0x96, 0x5D, 0x02, 0x6E, 0x1E, 0x61, 0x86, 0x9D, 0xC1, 0x53, 0x99, + 0x73, 0x25, 0xD0, 0x03, 0x51, 0x0B, 0xED, 0x42, 0xFD, 0x60, 0x89, 0x6C, 0x08, 0xA3, 0x3E, 0xEF, + 0xDA, 0xC9, 0x87, 0x1B, 0x44, 0x0F, 0x89, 0xCF, 0xA3, 0x69, 0xF3, 0xB9, 0x64, 0x99, 0x88, 0x30, + 0x44, 0x6B, 0xDB, 0xC7, 0x78, 0x89, 0x6A, 0x9A, 0x09, 0x2C, 0x3A, 0xE7, 0xF4, 0x5A, 0x81, 0x04, + 0x31, 0x41, 0x34, 0x7A, 0x5A, 0x8C, 0x27, 0xEF, 0xBC, 0xAF, 0x96, 0x2F, 0xDF, 0xF4, 0x49, 0xB0, + 0x14, 0xF7, 0xF0, 0x7A, 0x80, 0x69, 0x11, 0x24, 0xEB, 0x67, 0xCB, 0x5A, 0x35, 0x06, 0xE9, 0x81, + 0x60, 0xA4, 0x5A, 0xDE, 0x14, 0x89, 0x20, 0x8E, 0xF0, 0x87, 0x18, 0x45, 0x2B, 0xDE, 0xA7, 0x57, + 0x4D, 0x48, 0xD1, 0x9F, 0xC2, 0xD4, 0x16, 0x39, 0x4B, 0xF8, 0x43, 0xEC, 0x07, 0x05, 0xD1, 0xCF, + 0xC1, 0xFD, 0x46, 0x65, 0x7F, 0x0F, 0x0A, 0x18, 0x8A, 0xDB, 0x99, 0x0F, 0x93, 0xA7, 0x51, 0x6D, + 0x07, 0x01, 0xF6, 0xC3, 0x35, 0xE8, 0xA1, 0xDE, 0x03, 0xBF, 0x99, 0x8C, 0x9C, 0xDA, 0x52, 0xE5, + 0xEE, 0x9A, 0x4B, 0xD0, 0x76, 0x23, 0x97, 0x2E, 0x6C, 0x82, 0x48, 0x50, 0x20, 0x1D, 0xBB, 0x0B, + 0xA2, 0x4D, 0x8A, 0x27, 0x13, 0x44, 0x0E, 0xFD, 0x35, 0xDE, 0xC6, 0x5D, 0x35, 0xD7, 0x98, 0xE6, + 0x98, 0x61, 0x3C, 0x7F, 0xF5, 0xFE, 0x7E, 0x58, 0xDE, 0x02, 0x5E, 0x9C, 0x5E, 0x8B, 0xDD, 0x63, + 0x51, 0x4C, 0x2A, 0x2B, 0xF5, 0x9E, 0xAB, 0x6C, 0x9A, 0x46, 0xDE, 0x4D, 0x94, 0x6F, 0xEB, 0x5C, + 0x57, 0xB1, 0xBE, 0xC5, 0x95, 0x32, 0x11, 0x9E, 0x26, 0xD9, 0xBA, 0x3A, 0xA2, 0xE3, 0x3F, 0x61, + 0xE4, 0x98, 0x87, 0xC1, 0xF6, 0xD7, 0xFB, 0x52, 0x9C, 0x44, 0xB4, 0x33, 0xB9, 0xF5, 0x42, 0x22, + 0xDD, 0x94, 0xB1, 0x85, 0x72, 0x51, 0xFE, 0x07, 0x78, 0xE0, 0x12, 0x7D, 0xE7, 0xD4, 0xC2, 0x80, + 0xCC, 0xAE, 0x91, 0x76, 0x52, 0xC0, 0xC7, 0x1A, 0x00, 0x81, 0xC0, 0xF2, 0x7B, 0x73, 0x6E, 0xB1, + 0x5D, 0xA3, 0x0F, 0xB5, 0x3D, 0x44, 0xA6, 0x1F, 0x8C, 0x48, 0x56, 0x1B, 0x74, 0x4C, 0x4B, 0xC5, + 0x15, 0x45, 0x98, 0xC3, 0x2C, 0x99, 0x73, 0xA6, 0x8B, 0xBA, 0x0F, 0x44, 0xD6, 0x0F, 0x86, 0x96, + 0xE5, 0xDD, 0x2B, 0xF2, 0x00, 0x81, 0xD0, 0x78, 0x6D, 0x72, 0x01, 0x72, 0xCF, 0x34, 0x94, 0xAD, + 0x41, 0x14, 0x87, 0xFD, 0xAF, 0x6F, 0x34, 0xE6, 0x12, 0x83, 0x34, 0x2B, 0x7E, 0x28, 0xF8, 0x08, + 0x47, 0x13, 0xDE, 0x44, 0x11, 0x85, 0x63, 0x12, 0xF1, 0xD6, 0x74, 0x91, 0xDB, 0x22, 0x1C, 0x99, + 0x0C, 0xE2, 0x1F, 0x27, 0x07, 0x76, 0x66, 0x29, 0x71, 0x0A, 0xB9, 0x39, 0x94, 0x2C, 0x85, 0x87, + 0x5F, 0xF7, 0xD6, 0x51, 0xF3, 0x6C, 0x35, 0x79, 0xB7, 0x2D, 0x59, 0x3A, 0x5C, 0x2B, 0x32, 0x89, + 0x1C, 0xCB, 0x7A, 0x93, 0x06, 0xA2, 0xD9, 0x9F, 0xE3, 0xD0, 0xB0, 0x2E, 0x1A, 0xEF, 0x48, 0xEF, + 0x55, 0xE5, 0x7F, 0x05, 0x4F, 0x77, 0x13, 0xD1, 0x10, 0x41, 0x0C, 0x97, 0xA3, 0x54, 0x20, 0x59, + 0x37, 0xF4, 0x82, 0xED, 0x88, 0x89, 0xED, 0x8A, 0xEB, 0x94, 0x37, 0x80, 0x0A, 0xF3, 0x98, 0xBF, + 0x7C, 0x8C, 0x2C, 0xF2, 0xF8, 0x26, 0xE6, 0x80, 0xAA, 0x9B, 0x4B, 0x59, 0x91, 0x78, 0xB6, 0xBC, + 0xE3, 0x73, 0xE8, 0x16, 0x96, 0x33, 0x37, 0xFC, 0xA7, 0x79, 0x9F, 0xBC, 0xDC, 0x77, 0x53, 0x1C, + 0xFC, 0x58, 0x1B, 0xF1, 0x8B, 0x3A, 0xCA, 0x82, 0x6C, 0x98, 0x3A, 0x57, 0x3D, 0xA3, 0xE7, 0xD8, + 0x24, 0x38, 0x8F, 0xF9, 0xA8, 0x8A, 0x98, 0x24, 0x25, 0x01, 0xD8, 0xDE, 0x49, 0x6D, 0x1F, 0x0D, + 0x23, 0x93, 0x43, 0xB3, 0xBB, 0xA8, 0x56, 0x2A, 0xF3, 0x5E, 0xC7, 0x32, 0x9D, 0xB7, 0x2D, 0xEE, + 0x4F, 0xA9, 0xA2, 0x7D, 0x1F, 0x66, 0xD0, 0x25, 0x38, 0xA0, 0x0A, 0x5A, 0x08, 0x86, 0x4D, 0x7E, + 0xBD, 0x65, 0x8A, 0x42, 0xC2, 0xA2, 0xAB, 0xE9, 0x93, 0x7B, 0x0E, 0xA8, 0xDB, 0x49, 0x93, 0xDB, + 0xA6, 0x09, 0xD8, 0x29, 0x58, 0xAA, 0x9C, 0x4B, 0x21, 0x6B, 0x26, 0xA8, 0x8A, 0x3F, 0x2C, 0x01, + 0x4A, 0x0C, 0x7F, 0x0C, 0x11, 0xCE, 0x8F, 0xA7, 0x25, 0xB0, 0xB6, 0x2D, 0x90, 0x0D, 0x87, 0xE4, + 0xD7, 0x19, 0xE6, 0xCE, 0x90, 0x3B, 0xA5, 0x57, 0xBB, 0x44, 0x62, 0xD0, 0x86, 0xEA, 0x44, 0xB3, + 0xE2, 0xF2, 0x46, 0x73, 0x12, 0xC5, 0xB2, 0x65, 0xA1, 0x9F, 0xF3, 0xF8, 0x42, 0x0E, 0x8A, 0x3F, + 0xE6, 0x5D, 0x64, 0x49, 0x53, 0xAA, 0xDD, 0xB4, 0xF4, 0x95, 0x4B, 0x03, 0xE2, 0x33, 0xA0, 0xEE, + 0xE3, 0x8C, 0x3F, 0xAC, 0xF6, 0x16, 0xA4, 0x13, 0x3E, 0xEC, 0x30, 0x23, 0x57, 0x36, 0x66, 0x07, + 0x30, 0x66, 0x7F, 0xEA, 0x97, 0xE7, 0x2B, 0x30, 0xFC, 0xBB, 0xC5, 0x45, 0xB5, 0x70, 0x36, 0xED, + 0x7F, 0x9D, 0xB4, 0x2D, 0xEF, 0xF8, 0x6D, 0x36, 0xCC, 0x63, 0x2D, 0xEA, 0x2E, 0x7E, 0x93, 0xD0, + 0xC3, 0xC7, 0x22, 0xFC, 0x8B, 0x86, 0x76, 0xF6, 0x6B, 0x29, 0x2D, 0x3F, 0xC9, 0xD9, 0x23, 0x0B, + 0x4E, 0x51, 0x81, 0x95, 0xED, 0xD7, 0x15, 0x7F, 0xA8, 0x6A, 0x50, 0x4C, 0x40, 0x94, 0xD3, 0x4C, + 0xF6, 0x8E, 0xAA, 0x8C, 0x1D, 0x51, 0xC9, 0xF3, 0x68, 0x76, 0xF7, 0xB7, 0xF6, 0x0E, 0x11, 0x35, + 0x63, 0xFD, 0x99, 0x19, 0xEF, 0xE0, 0xE8, 0x39, 0x52, 0xB0, 0x6B, 0xB8, 0x2A, 0x00, 0xEC, 0x6F, + 0x95, 0xAE, 0x27, 0xE6, 0x9C, 0x7B, 0x96, 0x11, 0x39, 0xA2, 0xE3, 0xD8, 0xC1, 0x5E, 0xAB, 0x6E, + 0xDF, 0x53, 0xB4, 0x5F, 0x6E, 0x2A, 0x57, 0x5D, 0x20, 0x43, 0xB6, 0x01, 0x70, 0x2F, 0x47, 0xF3, + 0xE3, 0xF7, 0xAD, 0xDB, 0x45, 0xFE, 0xC2, 0x38, 0xF1, 0xC6, 0x6E, 0xF8, 0xE4, 0xAA, 0xB9, 0x01, + 0x48, 0xA3, 0x90, 0xA9, 0xA1, 0x82, 0x36, 0x8E, 0xFC, 0xAA, 0x18, 0xFA, 0x2C, 0x41, 0xCE, 0x9D, + 0x87, 0xFB, 0xE6, 0x5B, 0x17, 0xDB, 0x44, 0x24, 0xF8, 0x89, 0x5C, 0x1D, 0xC9, 0x81, 0xC6, 0x45, + 0x35, 0x4E, 0xB9, 0x13, 0xEF, 0xFE, 0x20, 0xBE, 0x84, 0x52, 0xC6, 0xED, 0x84, 0x0A, 0x12, 0x08, + 0xDE, 0xC5, 0x91, 0x2A, 0x60, 0x67, 0xC3, 0x8D, 0xB1, 0xDD, 0x4B, 0x92, 0x69, 0x3C, 0x95, 0xAA, + 0x05, 0x47, 0x13, 0x25, 0xA8, 0x54, 0xB9, 0x96, 0x75, 0x55, 0x9B, 0xDB, 0xD7, 0x7F, 0xE9, 0x80, + 0xCE, 0x00, 0x9A, 0x88, 0x9E, 0xFD, 0x94, 0xAF, 0x6F, 0x17, 0x6E, 0x82, 0x8B, 0x15, 0x33, 0x41, + 0xBD, 0xA8, 0x57, 0xC1, 0xC0, 0x4E, 0x66, 0xD4, 0x50, 0x93, 0xDA, 0x24, 0xD9, 0x77, 0x91, 0x5F, + 0xDC, 0x7B, 0x89, 0x5B, 0x81, 0xA1, 0x38, 0xA5, 0xD2, 0xAE, 0x1E, 0x7B, 0xD4, 0xE1, 0x24, 0x62, + 0xBF, 0xC5, 0x45, 0xF8, 0x24, 0xB4, 0xE1, 0x08, 0x20, 0x88, 0x66, 0x39, 0x22, 0xB9, 0x2F, 0xCB, + 0x08, 0x4B, 0x72, 0xBD, 0x58, 0x1B, 0x46, 0x66, 0x39, 0x37, 0x75, 0x21, 0x32, 0x82, 0xBD, 0x8D, + 0x0D, 0x5D, 0x07, 0xB5, 0xE0, 0xD3, 0x5D, 0x58, 0x77, 0x12, 0x54, 0x17, 0x85, 0xAA, 0x20, 0x7C, + 0x6A, 0x38, 0x77, 0x02, 0x50, 0xBE, 0x11, 0x3D, 0x5A, 0xED, 0x60, 0xB0, 0x90, 0x40, 0x13, 0x8F, + 0x51, 0xD7, 0xDE, 0x34, 0xA4, 0xDB, 0xFB, 0xAF, 0x18, 0x87, 0xA5, 0xF2, 0x32, 0x0D, 0x28, 0xF2, + 0x4F, 0xF5, 0xD7, 0xEE, 0x94, 0x0C, 0xB8, 0xD8, 0x66, 0x3B, 0xFF, 0xAE, 0xC2, 0xD0, 0xE0, 0xAD, + 0x03, 0x9F, 0x28, 0x81, 0x30, 0xCE, 0xC0, 0x8A, 0x7C, 0x2F, 0x6D, 0xD3, 0xE5, 0x9F, 0x85, 0x7A, + 0xB1, 0x9D, 0xBF, 0x69, 0x30, 0x4D, 0x15, 0x5C, 0xA5, 0x82, 0xAB, 0x3F, 0xC2, 0x16, 0x95, 0xDC, + 0xEB, 0x54, 0x31, 0xBA, 0x80, 0x01, 0x14, 0x55, 0x52, 0x12, 0x60, 0x95, 0x0E, 0x9E, 0x5A, 0x61, + 0xA4, 0x8D, 0x51, 0x04, 0x61, 0x5D, 0xAC, 0x55, 0x51, 0x0B, 0xC8, 0xAA, 0x19, 0xF0, 0x08, 0x04, + 0x1D, 0x21, 0x41, 0x2D, 0xD1, 0xA5, 0xE5, 0xD5, 0x86, 0x46, 0x26, 0xF1, 0x5A, 0x4D, 0x71, 0x2E, + 0xDE, 0xC3, 0xD6, 0x18, 0x04, 0x6C, 0x6C, 0x8B, 0x7F, 0x7B, 0x27, 0xE1, 0xE4, 0xDC, 0x57, 0x87, + 0xDA, 0xD2, 0x16, 0x12, 0x66, 0x7F, 0x58, 0x87, 0x00, 0x05, 0xCE, 0x20, 0x2C, 0xCE, 0x3E, 0x9E, + 0xF7, 0x48, 0x55, 0xF1, 0x05, 0x41, 0x45, 0xDE, 0x18, 0xF9, 0x80, 0x81, 0x69, 0x14, 0x0A, 0x1F, + 0xD0, 0x34, 0x79, 0x33, 0x92, 0x8F, 0x69, 0x53, 0x0F, 0xEC, 0x55, 0xB2, 0x4F, 0xC5, 0xEA, 0xA4, + 0x82, 0x56, 0x81, 0x39, 0xF5, 0xA1, 0xD5, 0x81, 0x85, 0x39, 0x79, 0x19, 0x0B, 0xD6, 0xE8, 0xBD, + 0xFD, 0x3C, 0x10, 0x4A, 0x62, 0x92, 0x52, 0x80, 0x5A, 0x3E, 0x6A, 0x22, 0x07, 0x70, 0x5A, 0x02, + 0x2C, 0x60, 0x90, 0x12, 0x47, 0xBF, 0x36, 0x83, 0xCF, 0x4A, 0xB1, 0xD6, 0x36, 0x58, 0xD9, 0x63, + 0xD3, 0x4C, 0x37, 0x5C, 0xF0, 0xAC, 0x17, 0xA5, 0x69, 0xFC, 0x9E, 0xE5, 0xD1, 0xBE, 0x7E, 0x37, + 0x64, 0xDA, 0x8B, 0xC5, 0xE5, 0xAF, 0x8B, 0xCF, 0xE9, 0x62, 0x78, 0x6F, 0xDA, 0xAD, 0x85, 0x4F, + 0x16, 0x75, 0xA2, 0xC4, 0x90, 0x3F, 0xD1, 0xAF, 0x3E, 0x8C, 0x1A, 0x8F, 0x30, 0x7A, 0x66, 0x6C, + 0x63, 0x4F, 0xBE, 0xD2, 0x0E, 0xF6, 0xD4, 0x3D, 0xA1, 0x06, 0x7B, 0x27, 0xDA, 0x01, 0xAF, 0xAD, + 0xB1, 0xD2, 0xAD, 0x12, 0x6A, 0xA9, 0x8C, 0x4A, 0x33, 0x81, 0x59, 0xFC, 0x6A, 0x41, 0xC3, 0xBE, + 0x7C, 0xD6, 0x1F, 0xDF, 0x09, 0xCB, 0x90, 0x7F, 0xD3, 0x07, 0x8E, 0xAA, 0x27, 0xD7, 0x5B, 0xAF, + 0xA0, 0x8A, 0x25, 0x96, 0xEE, 0x09, 0x2F, 0x81, 0x41, 0x0D, 0x94, 0x85, 0xA6, 0xDD, 0x73, 0x03, + 0xA9, 0xE5, 0x01, 0x3E, 0x15, 0xC1, 0x5F, 0xCD, 0x2C, 0x61, 0x39, 0xF8, 0x87, 0x6E, 0x49, 0xC3, + 0x41, 0x18, 0x67, 0x90, 0x79, 0x11, 0xD7, 0x3D, 0x11, 0xDE, 0x30, 0xAC, 0x78, 0xD6, 0xED, 0x86, + 0x51, 0x6E, 0x8C, 0xFE, 0xF8, 0x66, 0xAD, 0x7B, 0x7F, 0x17, 0x1F, 0x14, 0x53, 0x36, 0xE9, 0xE0, + 0xE6, 0xD3, 0xA9, 0x30, 0x1A, 0x24, 0x72, 0x2A, 0x94, 0x38, 0x05, 0x94, 0x38, 0x30, 0xBA, 0x6D, + 0x9E, 0x4A, 0x63, 0x22, 0xFF, 0x1A, 0xD8, 0xC2, 0x67, 0x8F, 0x33, 0x34, 0xC8, 0x2E, 0x9F, 0x6A, + 0x9A, 0xDA, 0x76, 0x40, 0x97, 0xCA, 0x53, 0x16, 0x0F, 0x9B, 0xA8, 0xF6, 0x97, 0x92, 0x06, 0x48, + 0xF9, 0x18, 0x72, 0x76, 0xE2, 0x64, 0x00, 0x2C, 0xC8, 0xFE, 0xCA, 0x24, 0xC8, 0x5F, 0x32, 0x71, + 0xD5, 0x20, 0xB3, 0xD3, 0xFB, 0xAE, 0x19, 0x6B, 0xC3, 0x60, 0xC8, 0xA7, 0xDE, 0x3A, 0x7F, 0x4E, + 0x76, 0x8A, 0xEB, 0x2D, 0x5D, 0x9E, 0xFE, 0x3D, 0x5C, 0xC6, 0x36, 0x79, 0xB5, 0xD6, 0xED, 0xC9, + 0x8B, 0x29, 0x1F, 0x98, 0x39, 0x09, 0x2E, 0x44, 0x10, 0x91, 0x77, 0x64, 0xA0, 0x15, 0x67, 0xFC, + 0x79, 0x33, 0xD6, 0x9D, 0x43, 0x26, 0x2B, 0x17, 0xFC, 0x32, 0x57, 0x5C, 0x71, 0x17, 0xDC, 0x43, + 0x51, 0x3D, 0x33, 0xEE, 0x6C, 0xC9, 0x28, 0xA5, 0x61, 0xFD, 0x0B, 0x41, 0xA3, 0x9D, 0xD6, 0x9A, + 0xEC, 0xE4, 0x5B, 0x64, 0x81, 0x34, 0x76, 0xFE, 0x79, 0x47, 0xB0, 0x21, 0x64, 0xF7, 0x55, 0xB9, + 0x6B, 0x53, 0x96, 0xD4, 0xC3, 0xAC, 0x39, 0x7A, 0x93, 0xA3, 0xDC, 0x15, 0x20, 0xBC, 0xDB, 0x44, + 0xA2, 0x3F, 0xF9, 0x1B, 0x28, 0xE9, 0x49, 0x9B, 0x57, 0x3F, 0xE0, 0x1D, 0xA9, 0x6A, 0x47, 0x4C, + 0x4A, 0xFC, 0x6D, 0x38, 0xBA, 0xBA, 0x71, 0x4A, 0xE4, 0x28, 0x67, 0x20, 0x27, 0x8F, 0xCB, 0xFB, + 0x29, 0xE8, 0x94, 0xD2, 0xFC, 0x59, 0xB6, 0x72, 0x7F, 0x76, 0x6B, 0x1E, 0xBE, 0x17, 0x68, 0xBB, + 0x32, 0x19, 0xCA, 0x17, 0x3F, 0x74, 0x03, 0x34, 0xC6, 0x54, 0x2E, 0xF9, 0x0E, 0x3B, 0x22, 0xC7, + 0x08, 0xF9, 0x66, 0x9B, 0x52, 0x0E, 0x28, 0x34, 0x6C, 0x88, 0x98, 0x2B, 0x8D, 0xFF, 0xD9, 0xA7, + 0xC4, 0xB6, 0x47, 0x4B, 0x54, 0xE2, 0x1D, 0x39, 0x2B, 0x9A, 0x83, 0x6F, 0x8D, 0x6A, 0xC9, 0x3E, + 0x13, 0xE9, 0xF7, 0xE4, 0xF1, 0x90, 0xA3, 0x2A, 0x20, 0x94, 0x15, 0x65, 0xFB, 0x00, 0x52, 0x6D, + 0xD4, 0xA2, 0x5E, 0x70, 0xE1, 0xD4, 0x7E, 0x89, 0x89, 0x86, 0x73, 0x77, 0xF5, 0x08, 0x67, 0xA2, + 0x7B, 0x4C, 0x64, 0xE5, 0x3A, 0x29, 0x5A, 0x22, 0x6B, 0xBD, 0x2E, 0xC4, 0xA7, 0x90, 0x5B, 0xEF, + 0x3B, 0x8E, 0x08, 0x3C, 0x84, 0xC6, 0x26, 0x6F, 0xED, 0xAB, 0x5F, 0xA5, 0xEE, 0x72, 0x40, 0xF0, + 0xEF, 0x51, 0x10, 0x80, 0x28, 0xD1, 0x13, 0xE6, 0xBA, 0x69, 0x68, 0x71, 0xD0, 0x3C, 0x25, 0x90, + 0x24, 0x8B, 0x0D, 0x1D, 0x84, 0xEE, 0xB7, 0xB4, 0x1F, 0x6E, 0xD2, 0x63, 0x7C, 0xC2, 0xE4, 0x01, + 0x53, 0x8B, 0x98, 0xCF, 0x7B, 0x9A, 0xFE, 0x86, 0x9E, 0xA0, 0xC0, 0xEE, 0x58, 0xBD, 0xB1, 0x72, + 0x55, 0x07, 0xDF, 0x08, 0xF3, 0x62, 0x7F, 0x68, 0x57, 0x37, 0xB8, 0x00, 0x94, 0x57, 0x41, 0x54, + 0x11, 0xB1, 0x70, 0xC0, 0xC9, 0x44, 0x9F, 0xC0, 0xD0, 0xED, 0x21, 0x19, 0xF5, 0x49, 0x9E, 0xF2, + 0x0F, 0x75, 0xB5, 0x05, 0x77, 0xBF, 0x07, 0x02, 0x72, 0x6C, 0x92, 0xAF, 0xEB, 0xA7, 0xDC, 0x79, + 0x71, 0x81, 0x27, 0x4E, 0x6C, 0xEE, 0x9C, 0xB7, 0xB2, 0x8A, 0x7D, 0x96, 0xE5, 0x83, 0x7C, 0x23, + 0x65, 0x59, 0x4D, 0xFB, 0xE6, 0x13, 0x5F, 0xA3, 0x12, 0x58, 0x53, 0x6F, 0xAD, 0xF9, 0xBA, 0x1B, + 0xBB, 0x22, 0x0D, 0x26, 0xA3, 0x4B, 0x91, 0x39, 0x3E, 0xBD, 0x88, 0x1E, 0xBA, 0x89, 0x19, 0xC4, + 0x23, 0x44, 0x36, 0xA8, 0xAC, 0x28, 0xD1, 0xA0, 0xDD, 0x41, 0x3C, 0xBB, 0x9F, 0x09, 0x70, 0xD8, + 0xDD, 0x2D, 0xA8, 0x57, 0x7E, 0xFB, 0x39, 0x46, 0x70, 0x71, 0xC0, 0xCE, 0x03, 0x31, 0x64, 0x66, + 0x9A, 0x41, 0x8C, 0x98, 0x78, 0xCC, 0x41, 0xCD, 0x5D, 0xE7, 0x8F, 0x2C, 0x89, 0x6F, 0xA0, 0x3D, + 0x60, 0x80, 0x83, 0xD7, 0xBE, 0xF9, 0x19, 0xB7, 0x0F, 0xE5, 0x30, 0x81, 0xF5, 0x57, 0x31, 0x67, + 0xEF, 0x5D, 0x91, 0x4B, 0xF5, 0x6A, 0x7B, 0xEB, 0x0A, 0xA7, 0x0B, 0x6B, 0x2D, 0x59, 0x47, 0x19, + 0xB9, 0x04, 0xEC, 0xC5, 0x81, 0xEA, 0xE8, 0x35, 0x47, 0x0B, 0xCC, 0xDA, 0x67, 0x4B, 0x26, 0x12, + 0x28, 0x1C, 0x61, 0x6A, 0x7D, 0xB8, 0xBB, 0xF5, 0x02, 0x31, 0x61, 0x9D, 0x65, 0x11, 0xCA, 0x04, + 0x38, 0x6C, 0xAE, 0xC0, 0x0A, 0x4E, 0x89, 0xFF, 0x5E, 0x1F, 0x2B, 0xCE, 0x25, 0xEC, 0x4E, 0x5B, + 0x3C, 0xEB, 0x3D, 0x39, 0xB3, 0x0E, 0x21, 0xBB, 0xF3, 0x0F, 0xE8, 0xE8, 0xDD, 0x4C, 0xDD, 0x0B, + 0x76, 0x02, 0x9D, 0x1E, 0xFD, 0x35, 0x84, 0xA9, 0x78, 0xC0, 0x9C, 0x9B, 0xBF, 0x1A, 0x78, 0x77, + 0x8D, 0x1F, 0x4C, 0x6B, 0x01, 0x86, 0x09, 0x9E, 0x7E, 0x28, 0x98, 0x38, 0x95, 0x88, 0x6D, 0xB3, + 0x5A, 0xA8, 0x61, 0xA9, 0xE9, 0x7A, 0xEA, 0x89, 0x81, 0x26, 0xAD, 0x31, 0x51, 0x24, 0xB5, 0xBA, + 0x68, 0x73, 0x17, 0xCF, 0x0A, 0x0D, 0x88, 0x3A, 0x19, 0x1F, 0x67, 0x76, 0xD9, 0xF2, 0x3C, 0x70, + 0xF7, 0x69, 0x48, 0x54, 0x81, 0x2F, 0x26, 0x43, 0x7F, 0x2B, 0x9F, 0x17, 0x08, 0xE1, 0x1D, 0x95, + 0xE3, 0xF6, 0x1C, 0x67, 0x98, 0xBA, 0x71, 0x40, 0x68, 0x43, 0xD6, 0x2E, 0x8D, 0xD8, 0xFC, 0xE7, + 0x6E, 0x9C, 0xDE, 0x80, 0xC0, 0xEB, 0x8F, 0x9C, 0x3B, 0xA5, 0x3E, 0x20, 0x16, 0xFD, 0x82, 0xE1, + 0x9F, 0x36, 0x0D, 0x06, 0x52, 0x75, 0xD7, 0x0F, 0x26, 0x1E, 0x9E, 0x45, 0x73, 0xA9, 0x4B, 0x99, + 0x42, 0xF2, 0xB7, 0x3B, 0x13, 0x93, 0x1F, 0xA2, 0x52, 0xE3, 0x8D, 0xDF, 0x75, 0xE7, 0xFB, 0x45, + 0xE8, 0xF2, 0xE4, 0xE2, 0xD4, 0xBE, 0x66, 0x1D, 0x5F, 0x6D, 0x57, 0xEC, 0x2A, 0xBB, 0x6E, 0x65, + 0xF8, 0xE2, 0xCB, 0xCA, 0xCF, 0xF4, 0xB5, 0x94, 0x92, 0x0F, 0x2C, 0x5D, 0x30, 0x19, 0x23, 0x4F, + 0x31, 0xE2, 0x48, 0x39, 0x63, 0x05, 0x8A, 0x83, 0x1B, 0x95, 0x01, 0x3F, 0x2B, 0xCC, 0x94, 0x37, + 0xE4, 0x0C, 0x8C, 0xCA, 0xAE, 0x79, 0x97, 0x9C, 0x9D, 0x00, 0x16, 0xE7, 0x5E, 0x45, 0x32, 0x21, + 0xFD, 0x99, 0x0D, 0x9A, 0x34, 0x37, 0x32, 0xF3, 0x09, 0xDC, 0xA2, 0xA6, 0x3F, 0x7D, 0x31, 0xAE, + 0x65, 0x42, 0x18, 0x3A, 0x60, 0x7E, 0x47, 0xB6, 0xEE, 0x91, 0xED, 0x2D, 0x9C, 0xF4, 0xCE, 0xE8, + 0x5D, 0x9A, 0x14, 0x74, 0x5D, 0x67, 0xCA, 0x9D, 0x71, 0xA5, 0x10, 0x91, 0x73, 0x93, 0x27, 0xC4, + 0x3D, 0x88, 0xE9, 0x3C, 0x6A, 0x88, 0x1F, 0xD5, 0xBC, 0x5E, 0x03, 0xAD, 0x83, 0x0C, 0x7C, 0x6E, + 0x0C, 0xAA, 0x09, 0x36, 0x1B, 0x91, 0x5F, 0xDC, 0xE4, 0x6A, 0x13, 0xC5, 0xA5, 0xFF, 0xF4, 0x26, + 0x6F, 0x82, 0x6B, 0xBA, 0xBE, 0xEF, 0x0D, 0xF6, 0x2D, 0x4B, 0x3D, 0xC3, 0x29, 0x4C, 0xAA, 0xC8, + 0x2D, 0xBF, 0x7B, 0x64, 0x1B, 0xB2, 0x1E, 0xC4, 0xA7, 0x7A, 0x1A, 0xB4, 0x19, 0xEA, 0x24, 0xBC, + 0x58, 0x36, 0x8E, 0xF2, 0xBC, 0x97, 0x4D, 0x50, 0x1D, 0x1D, 0xE6, 0xB3, 0x40, 0xBA, 0x50, 0xA6, + 0x09, 0xA7, 0x5E, 0xCE, 0x9F, 0x92, 0x25, 0x95, 0xB1, 0x16, 0xAF, 0xC2, 0x4B, 0x69, 0xB1, 0xE2, + 0x96, 0x6F, 0x25, 0xC5, 0x53, 0x37, 0x45, 0x40, 0x09, 0x4B, 0x8B, 0x8C, 0x11, 0xBB, 0x36, 0x05, + 0x95, 0xFF, 0x84, 0xC2, 0x3F, 0x35, 0x2E, 0x74, 0xE6, 0x3E, 0xF4, 0x72, 0x53, 0xCA, 0xCB, 0xC5, + 0x8D, 0xE7, 0x52, 0x8B, 0x12, 0x45, 0xF2, 0xA7, 0x37, 0x79, 0xFD, 0xDA, 0xD6, 0x59, 0xB8, 0x7E, + 0x9F, 0x5A, 0xBF, 0x43, 0x5D, 0xB4, 0x4F, 0xB6, 0xC8, 0x88, 0x9B, 0x05, 0xE7, 0x52, 0xE8, 0xD0, + 0x8A, 0xE7, 0xD5, 0xAE, 0xCE, 0x81, 0x54, 0xE8, 0xCF, 0x85, 0x6E, 0xC7, 0x57, 0x36, 0xC7, 0x89, + 0x9F, 0x5D, 0xA0, 0xBB, 0x96, 0x3E, 0x40, 0x7D, 0x5D, 0x52, 0xDE, 0xEC, 0xC5, 0x8A, 0x23, 0x16, + 0xA5, 0xA7, 0xB1, 0xE4, 0x0D, 0xEB, 0xEC, 0xEC, 0x28, 0xC2, 0xFF, 0x9A, 0x2A, 0xBF, 0x9B, 0x84, + 0x6B, 0x02, 0xC8, 0xBC, 0x4D, 0x12, 0x89, 0x0C, 0x3F, 0x7E, 0x24, 0xB4, 0xB5, 0xC8, 0x0F, 0x37, + 0xEB, 0xC3, 0x30, 0xFD, 0xBE, 0x77, 0xF1, 0x3E, 0x0A, 0x02, 0x18, 0x3A, 0x63, 0xC1, 0x24, 0x63, + 0x5B, 0x27, 0xA9, 0x9B, 0x24, 0x04, 0xE1, 0xD6, 0x48, 0x9A, 0xA6, 0x50, 0xCF, 0xF1, 0x1C, 0x95, + 0xA5, 0x25, 0xAD, 0x5E, 0x85, 0x4C, 0x81, 0xD2, 0x73, 0x95, 0x4D, 0x65, 0x76, 0x87, 0x57, 0x99, + 0xC1, 0x01, 0x13, 0x84, 0x89, 0xFF, 0x07, 0xCF, 0x4D, 0x4A, 0x1B, 0xDA, 0xA9, 0x9F, 0xD8, 0x1A, + 0x96, 0xCA, 0xC0, 0x25, 0x6C, 0x71, 0xE9, 0xB8, 0xA4, 0xB5, 0x1A, 0xF6, 0x8C, 0xEC, 0x67, 0xA9, + 0xBB, 0xFB, 0xF2, 0x76, 0x8A, 0xB6, 0xBD, 0xDB, 0x6E, 0xFB, 0x67, 0xB6, 0x12, 0x91, 0x06, 0x6A, + 0xE6, 0x34, 0x5F, 0x4A, 0x19, 0x6B, 0x45, 0xDC, 0x1A, 0x3E, 0xD4, 0x5A, 0xBB, 0x18, 0x71, 0x30, + 0xF1, 0x8A, 0x8D, 0x9B, 0x88, 0x39, 0x49, 0x03, 0x89, 0x83, 0xF6, 0xEE, 0x4E, 0x14, 0x39, 0xCE, + 0xF5, 0x14, 0x4F, 0x81, 0x34, 0x40, 0xB0, 0x74, 0x95, 0xA2, 0xF3, 0x31, 0x0F, 0xC6, 0x40, 0x3F, + 0x68, 0x08, 0x23, 0x6F, 0x87, 0x71, 0x27, 0x37, 0xB3, 0xEC, 0xA2, 0x53, 0x62, 0x44, 0x4C, 0xB6, + 0x7A, 0xAE, 0xC6, 0x23, 0x31, 0x25, 0x2B, 0xF3, 0xDA, 0xF6, 0xBB, 0x97, 0x2C, 0xFF, 0xF5, 0x76, + 0x86, 0xD2, 0x45, 0x3E, 0xBE, 0x63, 0xA8, 0xAF, 0xB2, 0x59, 0xA8, 0x54, 0x6C, 0x7D, 0xF2, 0x1F, + 0x74, 0x16, 0x08, 0xA4, 0x73, 0x01, 0x1A, 0xFF, 0x3E, 0xA8, 0x15, 0xC5, 0xFB, 0xD0, 0x70, 0x8E, + 0x05, 0x1C, 0xC4, 0x9C, 0x15, 0xF7, 0x2F, 0xE4, 0x2A, 0x30, 0xDE, 0x42, 0x4A, 0x6A, 0x0F, 0x4B, + 0x64, 0xAF, 0xBC, 0x11, 0xE4, 0xA3, 0x1D, 0x1F, 0x77, 0xC9, 0xCB, 0x53, 0x8E, 0xB8, 0x6C, 0x02, + 0xA0, 0xC1, 0xE4, 0x45, 0x04, 0x52, 0xC3, 0x6F, 0x19, 0xDC, 0xAE, 0x35, 0x10, 0xF9, 0x56, 0xC3, + 0x4B, 0xB6, 0x16, 0x48, 0x37, 0x69, 0xFC, 0x14, 0x7A, 0xDC, 0xD8, 0x8F, 0x13, 0x56, 0x45, 0x50, + 0x24, 0xE7, 0x40, 0x7E, 0x39, 0xFB, 0x58, 0x8E, 0x00, 0x00, 0xBB, 0xDB, 0xD5, 0xDD, 0xAA, 0x79, + 0xF7, 0xD7, 0x52, 0x30, 0x17, 0xC5, 0xB4, 0xEC, 0xBD, 0x98, 0xB8, 0x7C, 0xB5, 0x68, 0x1B, 0xE3, + 0x24, 0x44, 0x00, 0x73, 0xCF, 0x84, 0xDA, 0x30, 0x14, 0x1F, 0xB0, 0xF5, 0x3B, 0xBD, 0x45, 0x37, + 0x6F, 0x97, 0x4F, 0xCA, 0x6E, 0x9C, 0x1F, 0xC4, 0xBC, 0x2B, 0x21, 0x6B, 0x11, 0x52, 0x3B, 0xF3, + 0x62, 0xEB, 0x7C, 0xF6, 0x0A, 0xFA, 0x1F, 0xD5, 0xAC, 0x4F, 0x65, 0xEA, 0x60, 0x84, 0xC8, 0xFD, + 0x6A, 0xAA, 0xF4, 0x11, 0x71, 0x96, 0x34, 0x93, 0x96, 0x6F, 0xC2, 0xC3, 0xA0, 0x11, 0xC7, 0xFA, + 0x35, 0x69, 0x8B, 0xDB, 0x37, 0xBD, 0xC3, 0x50, 0x0D, 0xED, 0x31, 0x1B, 0x79, 0x8D, 0xA8, 0xB7, + 0x2E, 0xA4, 0x41, 0x5F, 0x7F, 0xE7, 0x69, 0x0A, 0x56, 0xE8, 0x27, 0x8D, 0x89, 0x67, 0x11, 0x8E, + 0xBE, 0xC2, 0x24, 0x5C, 0x2B, 0x76, 0x60, 0xBD, 0x7E, 0xF9, 0x53, 0x89, 0x8D, 0x39, 0x49, 0x73, + 0x9B, 0xA5, 0x60, 0x7F, 0x4A, 0x68, 0x61, 0x9A, 0x05, 0x30, 0xB0, 0x49, 0xDF, 0xBA, 0x66, 0xDA, + 0x75, 0xBD, 0x83, 0xF9, 0x12, 0x45, 0x2D, 0xA8, 0x42, 0xC8, 0xB8, 0x93, 0xBA, 0x83, 0xE4, 0x9B, + 0x9E, 0x1A, 0x00, 0x3B, 0xC8, 0x3C, 0xE5, 0x8B, 0x2B, 0x3D, 0x48, 0x09, 0x5E, 0xCB, 0x9A, 0xF3, + 0x92, 0xC2, 0xCC, 0x53, 0x13, 0xF4, 0x63, 0xEE, 0x63, 0x96, 0x78, 0xD8, 0x47, 0x6F, 0x7A, 0xEF, + 0x52, 0xE9, 0x16, 0x98, 0xE9, 0x31, 0xDB, 0x10, 0x42, 0x5D, 0xC2, 0xD9, 0x16, 0x0E, 0x02, 0x98, + 0x2F, 0x34, 0x52, 0x47, 0x96, 0xFB, 0x69, 0x43, 0x68, 0x0E, 0xB5, 0xE8, 0xCC, 0x40, 0x44, 0xE6, + 0x0B, 0x8B, 0x10, 0xAA, 0xCF, 0x42, 0xDB, 0xDF, 0x30, 0xA5, 0x1F, 0x0F, 0x39, 0xC0, 0xC5, 0xBA, + 0xF2, 0x1F, 0x20, 0x47, 0xEC, 0xA0, 0x4D, 0x42, 0x12, 0x24, 0x68, 0xE8, 0x9C, 0xF9, 0x0D, 0xCE, + 0x50, 0xAA, 0x53, 0x98, 0x09, 0x85, 0x63, 0x6A, 0x93, 0x51, 0xAF, 0x55, 0x4B, 0x72, 0x43, 0x68, + 0xDE, 0x79, 0xA8, 0x8D, 0x8C, 0xF8, 0x4D, 0x51, 0x89, 0xD1, 0xDF, 0x54, 0x33, 0x9B, 0xB9, 0x1F, + 0x99, 0xAF, 0xD9, 0x19, 0xE1, 0xBF, 0x8F, 0x70, 0x64, 0xBE, 0x3C, 0xF8, 0x72, 0x8E, 0x07, 0x70, + 0x95, 0x7A, 0xC7, 0x58, 0x0E, 0x0B, 0x7F, 0xC0, 0xE9, 0x4B, 0xF3, 0x93, 0x57, 0x0C, 0xC5, 0x95, + 0x52, 0x2D, 0x5B, 0x05, 0x33, 0xE7, 0x88, 0x06, 0xB9, 0x92, 0x1C, 0xBD, 0x48, 0xBA, 0x10, 0xFE, + 0x52, 0x24, 0xF8, 0x31, 0x84, 0xA7, 0x61, 0x80, 0x60, 0xAC, 0x45, 0x57, 0xAD, 0x14, 0x8F, 0xC8, + 0xF8, 0xAD, 0xE1, 0x94, 0x98, 0x90, 0xA4, 0xB5, 0x78, 0xCB, 0xF2, 0x7A, 0x5F, 0x96, 0x6B, 0xED, + 0xB2, 0xC9, 0x99, 0x7F, 0x85, 0xF3, 0x9B, 0xC1, 0x82, 0xFF, 0x8E, 0x4F, 0xF8, 0x51, 0xDA, 0x14, + 0x7B, 0x7F, 0x65, 0xA4, 0x58, 0xD8, 0x93, 0xCB, 0xBF, 0x55, 0xF4, 0xA9, 0x65, 0xA5, 0x28, 0xC9, + 0x84, 0xAA, 0xD9, 0xAF, 0xD3, 0x40, 0x34, 0xB9, 0xA1, 0x3D, 0xE9, 0xE5, 0x7E, 0x29, 0xE7, 0x62, + 0x78, 0xD5, 0xC7, 0xB0, 0x18, 0x42, 0xB5, 0xD5, 0x18, 0x53, 0xAF, 0x8F, 0x48, 0x72, 0x84, 0x38, + 0x8E, 0xA8, 0xF9, 0xDC, 0xA2, 0x6E, 0xAD, 0x42, 0x13, 0x18, 0x3B, 0xAF, 0x16, 0x37, 0xCB, 0xDE, + 0xC4, 0x4B, 0xE9, 0xFA, 0x94, 0x6C, 0x99, 0x95, 0x69, 0xC5, 0xCF, 0x8D, 0x85, 0xC9, 0x0D, 0x7B, + 0xBC, 0x13, 0x77, 0xF2, 0xBA, 0xBE, 0x6C, 0x75, 0x06, 0x97, 0xF0, 0xA4, 0x34, 0x6F, 0xB9, 0x3D, + 0x65, 0xCC, 0xF5, 0xAE, 0x37, 0x9D, 0x8E, 0x2F, 0xF9, 0xC1, 0xFE, 0x2E, 0x4A, 0x52, 0x58, 0x09, + 0xB6, 0x0E, 0x9A, 0x44, 0xA3, 0x44, 0xA4, 0x60, 0x2E, 0x51, 0x84, 0x8F, 0xA7, 0x54, 0xE5, 0x71, + 0xAD, 0x61, 0x43, 0x96, 0x6A, 0x42, 0x95, 0x4F, 0x6C, 0x59, 0xEE, 0x92, 0xA8, 0x2E, 0x10, 0xF1, + 0x0A, 0x8F, 0xCD, 0x85, 0xDE, 0x1A, 0x1C, 0x4C, 0x50, 0x47, 0x5A, 0x28, 0x04, 0x9C, 0x98, 0x2D, + 0x90, 0x26, 0x0A, 0xC1, 0x2B, 0xE7, 0xC7, 0xF8, 0x19, 0xFC, 0xCE, 0x32, 0xB1, 0x13, 0x69, 0x24, + 0xA1, 0x20, 0x4D, 0x57, 0xBF, 0x50, 0x2B, 0xEE, 0x80, 0x22, 0xF6, 0xD6, 0x49, 0x8A, 0xD1, 0xC4, + 0x62, 0x81, 0xDA, 0x80, 0xB2, 0x3C, 0xD0, 0x7E, 0xC3, 0xA2, 0x76, 0x50, 0x50, 0x3E, 0xFC, 0xBC, + 0xFC, 0xAD, 0xAB, 0xDB, 0xA5, 0xF6, 0xA0, 0x4F, 0x55, 0xF3, 0xF3, 0xF5, 0xCA, 0x22, 0x21, 0x16, + 0x10, 0x9D, 0x75, 0xFE, 0x62, 0x46, 0x38, 0x83, 0x5E, 0xEA, 0xE4, 0xF8, 0x44, 0xD5, 0x87, 0x74, + 0x68, 0x70, 0xAD, 0x79, 0x6F, 0x1F, 0x06, 0xAC, 0x80, 0x6B, 0x33, 0x2E, 0x86, 0x19, 0xF3, 0x31, + 0xCA, 0xC4, 0x67, 0x2C, 0x9E, 0x82, 0xA3, 0xD8, 0xED, 0xB0, 0x03, 0x2C, 0x10, 0xB0, 0x66, 0xDE, + 0xD9, 0xD5, 0x7F, 0xBC, 0x6B, 0xB2, 0x74, 0xF2, 0xAD, 0x51, 0x2F, 0xA2, 0xAB, 0x0A, 0x0B, 0xF2, + 0xEA, 0xA3, 0x70, 0xD8, 0x5F, 0x9C, 0x9A, 0x13, 0x6D, 0x5E, 0x90, 0x7C, 0xFD, 0x7A, 0x64, 0x71, + 0x78, 0x7A, 0xD6, 0xAF, 0x1B, 0x25, 0x72, 0xC9, 0xEA, 0x0A, 0xBC, 0x6A, 0x72, 0x60, 0x9E, 0x85, + 0x95, 0x11, 0x64, 0x45, 0x9E, 0x54, 0xD2, 0x31, 0x8E, 0xCB, 0xEE, 0x6A, 0xC1, 0x2F, 0xD7, 0x07, + 0xF1, 0xC5, 0xB5, 0xE5, 0x2B, 0x7B, 0xDE, 0x66, 0x74, 0x66, 0x97, 0x38, 0x1A, 0xBF, 0x13, 0x98, + 0xF8, 0xDD, 0xF6, 0x1B, 0x64, 0x80, 0x1A, 0xF6, 0x35, 0x04, 0x51, 0xD6, 0xF9, 0x61, 0x21, 0xB2, + 0x6E, 0x78, 0xCB, 0xB8, 0x09, 0xF5, 0xC1, 0xD3, 0xD8, 0xDD, 0xC6, 0xFB, 0x63, 0x47, 0x98, 0x90, + 0x1E, 0xAF, 0x77, 0xB1, 0xB9, 0xDF, 0x22, 0x7B, 0x8D, 0x6F, 0x0D, 0xE8, 0x83, 0x3B, 0xEF, 0x02, + 0x53, 0xA0, 0x02, 0xFC, 0xE9, 0xC3, 0xD9, 0xB4, 0x8E, 0xAF, 0xB5, 0xD3, 0x6F, 0x68, 0x9B, 0x35, + 0x5B, 0xE8, 0x79, 0x6D, 0x11, 0x8C, 0x21, 0xDB, 0xBB, 0xEE, 0x56, 0xBE, 0xC5, 0xFF, 0x7D, 0xE8, + 0x3E, 0xA1, 0xB7, 0xA5, 0x26, 0xEF, 0x14, 0x3F, 0x8D, 0x12, 0x97, 0xC4, 0x64, 0xDD, 0xD8, 0xA7, + 0xC5, 0x3E, 0xC5, 0x7F, 0x2A, 0x00, 0xC3, 0x67, 0x80, 0x19, 0xC8, 0x3D, 0xAD, 0x17, 0x2E, 0x54, + 0x94, 0xA9, 0x39, 0x43, 0xFF, 0xC2, 0x6F, 0x5F, 0x93, 0x8A, 0x3B, 0x43, 0x47, 0x47, 0xD4, 0xA8, + 0x3A, 0xA1, 0x91, 0x40, 0x45, 0x54, 0xB6, 0x83, 0x60, 0x5F, 0x71, 0x49, 0x45, 0x9E, 0x42, 0x7A, + 0x57, 0x85, 0x07, 0xE9, 0x45, 0x31, 0x35, 0xEF, 0x7B, 0x24, 0xEB, 0xA8, 0xE7, 0x11, 0xB1, 0x4E, + 0x97, 0x32, 0xD6, 0x93, 0xAA, 0x2B, 0x5F, 0xFD, 0x64, 0xC3, 0x48, 0x5E, 0xE3, 0xAB, 0x3F, 0x51, + 0x11, 0x86, 0x49, 0x41, 0x05, 0x3B, 0x0E, 0x29, 0x47, 0xA0, 0xBC, 0x31, 0x08, 0x3F, 0x2D, 0xDA, + 0x9F, 0x3D, 0x27, 0xA2, 0x09, 0x54, 0x98, 0x99, 0x5E, 0x05, 0x3B, 0x31, 0x09, 0x01, 0xF1, 0x57, + 0xAD, 0x5A, 0x27, 0x60, 0x38, 0x41, 0x64, 0x85, 0x2F, 0x2E, 0xCB, 0xA5, 0xB4, 0x33, 0x33, 0x35, + 0xE2, 0xCA, 0xD7, 0xF4, 0xCE, 0x30, 0xB5, 0x01, 0xA4, 0x9D, 0x99, 0x18, 0x24, 0x6A, 0xAB, 0x21, + 0x5F, 0x7D, 0xE2, 0xE9, 0x55, 0xF9, 0x8A, 0xDF, 0xE5, 0xF3, 0x88, 0x06, 0xD4, 0xC6, 0xEE, 0x35, + 0xAB, 0x93, 0xA0, 0x79, 0x5B, 0x1E, 0x5F, 0x02, 0xAC, 0x6A, 0xA0, 0xCE, 0x2C, 0xAC, 0xC8, 0xAF, + 0x8B, 0x8C, 0x20, 0xAA, 0x45, 0xC6, 0x83, 0x0C, 0xD0, 0x0C, 0x98, 0x8B, 0x8E, 0x56, 0x53, 0x63, + 0xCB, 0xCA, 0x8A, 0xD4, 0xF3, 0x59, 0x8A, 0xBA, 0xEB, 0xD5, 0x97, 0x86, 0x96, 0x18, 0x28, 0xDD, + 0xA1, 0xF4, 0xFB, 0x3E, 0xDC, 0xD5, 0x1E, 0xC3, 0x16, 0x54, 0x2F, 0x45, 0xD0, 0xED, 0xBC, 0xF9, + 0xDB, 0x53, 0xB5, 0x19, 0x45, 0xC2, 0x16, 0x75, 0xFD, 0x26, 0x35, 0xA6, 0x75, 0xAB, 0xFA, 0xBC, + 0xE4, 0x62, 0x45, 0xB1, 0xA2, 0x7F, 0x27, 0x9D, 0x2A, 0x1F, 0x18, 0xFA, 0x61, 0x2D, 0xD3, 0xB2, + 0x88, 0xDE, 0xF8, 0x42, 0xC3, 0x74, 0xB3, 0x78, 0xA0, 0x40, 0x31, 0x55, 0xCD, 0x40, 0x84, 0xE2, + 0x5E, 0x8F, 0x48, 0x4E, 0x84, 0x63, 0x40, 0xCF, 0xAD, 0x5F, 0xE1, 0x13, 0xAF, 0xAE, 0x45, 0x02, + 0x78, 0xAC, 0xD8, 0xC4, 0xBC, 0xE6, 0xD8, 0x78, 0x17, 0x85, 0x01, 0x49, 0xEC, 0x91, 0x40, 0x4A, + 0xF2, 0x0E, 0xC8, 0xBF, 0xA5, 0xF7, 0xFC, 0xCC, 0x4D, 0x95, 0x95, 0xDE, 0x57, 0xC3, 0x0E, 0xAE, + 0xD4, 0xC3, 0xC2, 0x8A, 0x9E, 0xA7, 0x83, 0x30, 0x70, 0xA7, 0x8A, 0xCB, 0xE3, 0x6E, 0x8D, 0x06, + 0x07, 0x9A, 0x2B, 0x7D, 0xEC, 0x1A, 0x9C, 0x8D, 0x6E, 0xEE, 0x12, 0xC1, 0x62, 0xB7, 0x7F, 0x51, + 0xCF, 0x77, 0x78, 0xBF, 0xB8, 0xF7, 0x48, 0xE2, 0x0A, 0x20, 0x50, 0x98, 0x7A, 0x16, 0xAF, 0x6A, + 0x62, 0x0C, 0xAC, 0x90, 0x78, 0x0B, 0x6C, 0xFF, 0xBC, 0x26, 0xA7, 0x23, 0x0D, 0xBA, 0x9E, 0x25, + 0x1E, 0x50, 0xD6, 0x3C, 0xBE, 0xA2, 0x72, 0x39, 0xC1, 0x4D, 0xC6, 0x9B, 0x07, 0xD2, 0x6D, 0x00, + 0xE1, 0xB6, 0x87, 0x2E, 0x15, 0x30, 0x56, 0x66, 0xEC, 0x7A, 0x9E, 0x30, 0x76, 0x21, 0x40, 0x1F, + 0x47, 0xB7, 0x7E, 0xDE, 0x7D, 0xB1, 0x22, 0x29, 0x9B, 0x19, 0x38, 0xC9, 0x20, 0x60, 0xAA, 0x54, + 0x2A, 0x84, 0xD6, 0x3F, 0x0F, 0x42, 0xA4, 0xF5, 0xE4, 0x92, 0x22, 0x93, 0x1F, 0xD6, 0x93, 0x44, + 0x47, 0xDA, 0x6E, 0x3D, 0x34, 0xEA, 0x80, 0xB2, 0xC4, 0x99, 0xD1, 0x4D, 0x5C, 0x95, 0x2A, 0x74, + 0xFC, 0x89, 0x33, 0x6A, 0xF3, 0x6E, 0x5F, 0x46, 0xC8, 0x1C, 0x91, 0x7C, 0x23, 0x4E, 0x18, 0x47, + 0x52, 0x83, 0xCE, 0x05, 0x1D, 0xAF, 0xF1, 0x76, 0x1A, 0x92, 0x48, 0x32, 0x29, 0x7D, 0xFF, 0x23, + 0xD6, 0xFB, 0x51, 0x5B, 0x79, 0x78, 0xFE, 0xD1, 0x78, 0xC2, 0x5B, 0x33, 0x9B, 0x5D, 0x45, 0xA2, + 0x12, 0xE9, 0x7F, 0x2A, 0x41, 0x8A, 0xFA, 0x57, 0xFF, 0x5A, 0x46, 0x31, 0x81, 0x9E, 0x94, 0x46, + 0x2B, 0x1D, 0x05, 0x35, 0x07, 0x6A, 0x0D, 0xAD, 0xF1, 0x06, 0x39, 0xE7, 0x98, 0x87, 0x81, 0x35, + 0xF0, 0xD9, 0x0D, 0x43, 0xEE, 0x81, 0xAF, 0x17, 0x29, 0xEA, 0x97, 0x81, 0x65, 0x0E, 0xE9, 0x96, + 0x62, 0x19, 0x28, 0x6B, 0x67, 0x4E, 0x29, 0xEC, 0x06, 0xF3, 0x34, 0x1E, 0xD4, 0xFE, 0xFE, 0x8D, + 0xE6, 0xE2, 0xB8, 0x37, 0x0A, 0x1B, 0x14, 0x22, 0x26, 0xAC, 0x6C, 0x8E, 0xA0, 0xFC, 0xD2, 0x47, + 0x14, 0x58, 0x33, 0x10, 0x81, 0xA7, 0x5F, 0x2F, 0xEB, 0x6B, 0x9C, 0x23, 0x40, 0xB3, 0x87, 0x3C, + 0x32, 0x28, 0xE1, 0xD8, 0x84, 0xB7, 0x9D, 0x6F, 0x55, 0xF6, 0x19, 0xF8, 0x4F, 0xC5, 0x88, 0xC8, + 0x27, 0xF3, 0x4F, 0xDA, 0x97, 0x4D, 0x40, 0xD5, 0xE4, 0x96, 0x68, 0xBC, 0x6E, 0x44, 0xD7, 0xAB, + 0xAC, 0x6A, 0x07, 0xEA, 0x44, 0x18, 0xA4, 0x16, 0x52, 0x72, 0x6A, 0x37, 0x9E, 0x6D, 0x2B, 0x8B, + 0x02, 0x7F, 0xC9, 0x85, 0xD9, 0x3D, 0x80, 0x39, 0x78, 0x39, 0x22, 0x89, 0x59, 0x62, 0xB7, 0xB9, + 0xF1, 0xDF, 0x2A, 0x63, 0x65, 0xF6, 0x16, 0x3B, 0xAD, 0xD2, 0x78, 0xB4, 0x4F, 0x0D, 0x59, 0xA6, + 0x76, 0xEE, 0xFC, 0x5C, 0xAB, 0x78, 0x58, 0x8E, 0xB8, 0x9B, 0xEB, 0x0F, 0xE4, 0x85, 0xB1, 0xED, + 0x1E, 0x5E, 0x14, 0xBD, 0x80, 0xF7, 0x6F, 0x90, 0xD1, 0x52, 0x86, 0x5F, 0xCC, 0xE3, 0x30, 0x15, + 0xE7, 0x33, 0x72, 0x3B, 0xCB, 0x2E, 0x5D, 0x79, 0x41, 0x0C, 0xF5, 0xD4, 0x99, 0x86, 0xB2, 0xB9, + 0x3F, 0xD4, 0x7D, 0x65, 0x86, 0x91, 0x39, 0xCC, 0x98, 0x3A, 0x58, 0xCB, 0x1F, 0x08, 0x36, 0xCA, + 0xD2, 0xE4, 0x7A, 0xD6, 0x5B, 0x88, 0x17, 0x82, 0x59, 0xC0, 0x0F, 0x2B, 0x68, 0x5E, 0x28, 0x3E, + 0x8B, 0x3C, 0x9F, 0x42, 0x24, 0x8C, 0xB1, 0x99, 0x74, 0x7A, 0xEB, 0x14, 0xB9, 0x93, 0xE2, 0x20, + 0x43, 0xEC, 0x7A, 0xF8, 0x02, 0xFC, 0x82, 0xC3, 0xF2, 0x4D, 0x07, 0xB9, 0x96, 0x89, 0xB4, 0x7F, + 0xBB, 0x09, 0x92, 0x36, 0xE9, 0xA6, 0x78, 0x69, 0xBE, 0xCB, 0xD2, 0x10, 0xCE, 0x0B, 0xDE, 0x90, + 0x6B, 0xF7, 0x69, 0x0D, 0x75, 0xC7, 0xF0, 0xDE, 0xB9, 0xDA, 0xF1, 0x9C, 0x9B, 0xF5, 0xFD, 0xAD, + 0x47, 0xE2, 0x2F, 0xC1, 0x08, 0x3A, 0x3F, 0x15, 0x1F, 0xD0, 0x0D, 0x8B, 0x48, 0xAA, 0xE2, 0x29, + 0xAD, 0x18, 0x95, 0x1A, 0x3C, 0x3B, 0x57, 0x97, 0xCB, 0x02, 0x6D, 0x39, 0xBD, 0x70, 0x68, 0x7B, + 0x93, 0xA9, 0xCB, 0x8B, 0x0C, 0x9D, 0x21, 0xDA, 0x61, 0x26, 0x16, 0x28, 0xCF, 0x16, 0x49, 0x22, + 0x56, 0xC9, 0xAA, 0x24, 0x88, 0xE1, 0x27, 0x5A, 0xC3, 0x98, 0xD2, 0xD8, 0x8B, 0xF5, 0xFD, 0x74, + 0x3A, 0xA3, 0xC4, 0xD2, 0x03, 0xA9, 0x60, 0x0A, 0xED, 0x92, 0xC2, 0x1A, 0x23, 0x09, 0x6E, 0xC1, + 0x22, 0xDE, 0x33, 0x7A, 0xEA, 0xF9, 0xAB, 0x79, 0xEC, 0x35, 0x40, 0x65, 0x82, 0x17, 0x80, 0x0E, + 0xC0, 0xE5, 0x30, 0x09, 0xD2, 0x72, 0x14, 0x47, 0xB2, 0x3B, 0xE1, 0xAE, 0xE8, 0xE5, 0x82, 0xCB, + 0xF6, 0x39, 0x12, 0x2F, 0x68, 0x08, 0x5E, 0xCA, 0x73, 0x7E, 0xB8, 0xA5, 0x1B, 0xE1, 0x6D, 0xA9, + 0x04, 0x76, 0x2D, 0xED, 0xB8, 0x40, 0xF5, 0x14, 0xA3, 0xC7, 0x05, 0x0D, 0xD0, 0x0E, 0x0B, 0x67, + 0x58, 0xB7, 0xD4, 0xD0, 0x3A, 0x91, 0xD9, 0x19, 0x01, 0xC1, 0x29, 0x46, 0xC9, 0xD3, 0x4D, 0x24, + 0xAA, 0x35, 0x39, 0x8B, 0x56, 0xC1, 0x21, 0x42, 0x03, 0xC0, 0x9C, 0x1B, 0x64, 0x60, 0xFE, 0x9A, + 0x7C, 0xA8, 0xA2, 0xCB, 0x29, 0x5C, 0xEB, 0x50, 0x35, 0x68, 0x78, 0xB5, 0xA0, 0xC1, 0xC4, 0xF2, + 0x67, 0x56, 0xB0, 0xFF, 0xDA, 0x11, 0xCA, 0xB8, 0x00, 0xBB, 0x71, 0x74, 0xFA, 0xFB, 0x99, 0x5C, + 0x00, 0x98, 0x08, 0xC1, 0x01, 0x16, 0x02, 0x15, 0x8B, 0x79, 0x4F, 0x5F, 0x61, 0x1F, 0x77, 0x41, + 0xFB, 0x65, 0x3F, 0x4F, 0xE5, 0x8A, 0x26, 0xC4, 0x3F, 0x56, 0x0B, 0xBA, 0x75, 0x5F, 0x17, 0xF4, + 0x16, 0xF9, 0x3C, 0x24, 0xF1, 0xC8, 0xFC, 0xF5, 0x14, 0x6A, 0x04, 0xD7, 0xC9, 0xAA, 0x33, 0xCB, + 0x9C, 0x23, 0xC3, 0xC6, 0x0D, 0x0E, 0x49, 0xD4, 0xE5, 0xDD, 0x9C, 0xAD, 0xF3, 0x5E, 0x28, 0x33, + 0xA2, 0x73, 0xFD, 0x8B, 0xBF, 0x67, 0xD8, 0xC7, 0xC2, 0xFF, 0x93, 0x04, 0xFB, 0x87, 0x8F, 0xE0, + 0x32, 0xDC, 0xC9, 0x3B, 0xFE, 0x5C, 0x12, 0x98, 0xDC, 0x8F, 0x57, 0x11, 0xC8, 0x6D, 0xC9, 0xD3, + 0x4A, 0xA4, 0x70, 0x32, 0x56, 0x79, 0x2E, 0x08, 0x48, 0x08, 0xB2, 0x74, 0x44, 0x27, 0x3A, 0x20, + 0xE5, 0x45, 0xC2, 0x2E, 0xD1, 0x7E, 0xDD, 0x65, 0xA1, 0x70, 0xDD, 0xF1, 0x6F, 0x4D, 0x3E, 0xA8, + 0x5B, 0x15, 0xB3, 0x41, 0x1E, 0xF4, 0x05, 0x27, 0x61, 0x26, 0x5E, 0xE0, 0xA6, 0x65, 0x74, 0x86, + 0xBA, 0x61, 0x10, 0xC3, 0xED, 0xFF, 0xD2, 0xAE, 0x4A, 0xEC, 0x91, 0xAD, 0xD2, 0x0F, 0x83, 0x48, + 0xCB, 0x6B, 0x7F, 0x2C, 0xA8, 0x85, 0xFC, 0xFA, 0xF4, 0x59, 0xD9, 0x24, 0x9C, 0x5D, 0x61, 0x52, + 0x34, 0xCA, 0x03, 0xF4, 0x2B, 0x1B, 0xF7, 0x38, 0x7B, 0xDA, 0x60, 0xF5, 0x4C, 0x83, 0x11, 0x3F, + 0x28, 0xE2, 0x9A, 0x37, 0x4D, 0x8C, 0xE3, 0x78, 0x9E, 0x3E, 0xC4, 0xE1, 0xEA, 0xD2, 0x9B, 0xF2, + 0x4B, 0x16, 0x51, 0xCF, 0xD6, 0x12, 0x5A, 0x4B, 0x03, 0x65, 0x40, 0xE2, 0xFF, 0xEF, 0x50, 0x51, + 0x4A, 0x29, 0x13, 0x96, 0xDB, 0x8E, 0x68, 0xCF, 0x61, 0x48, 0xA4, 0x67, 0x88, 0x5C, 0x0F, 0x9E, + 0xE6, 0x9D, 0xF3, 0x6F, 0xFB, 0x6E, 0xE4, 0xF2, 0xA1, 0xFA, 0xE9, 0x54, 0x98, 0x27, 0x69, 0x5E, + 0x51, 0x87, 0x1A, 0x55, 0x31, 0x6C, 0x1A, 0x59, 0x0A, 0xB7, 0x73, 0xA5, 0xD4, 0x92, 0x49, 0x84, + 0x75, 0x80, 0x37, 0x9C, 0xB6, 0x6E, 0x34, 0x60, 0xD3, 0x67, 0xC4, 0xFA, 0x74, 0x8E, 0x09, 0x56, + 0x99, 0x9F, 0x12, 0x0E, 0x7C, 0x2E, 0x59, 0xD0, 0xC7, 0x4A, 0xEC, 0xF7, 0x73, 0x72, 0xE5, 0x0E, + 0x8E, 0x62, 0x34, 0x62, 0x60, 0x82, 0xDC, 0x84, 0x20, 0x09, 0xAD, 0x28, 0xF5, 0xD5, 0x40, 0xD6, + 0xF4, 0x12, 0x24, 0xAD, 0x3B, 0xFE, 0x32, 0x41, 0xB6, 0x61, 0x99, 0x1E, 0xBD, 0xE4, 0x21, 0x97, + 0x39, 0x69, 0xF1, 0xD6, 0x8D, 0xD8, 0xDB, 0xB7, 0x26, 0xA3, 0x1D, 0x98, 0xB4, 0xAD, 0xC0, 0x5C, + 0xD5, 0x28, 0x2B, 0x93, 0xAD, 0xFC, 0x76, 0x17, 0x2F, 0x0D, 0xE3, 0xE4, 0x48, 0x54, 0xCD, 0x57, + 0xC8, 0xAA, 0xE9, 0x9D, 0xDB, 0xA8, 0xE7, 0xA5, 0x8D, 0x23, 0x0B, 0xC0, 0x2F, 0xAF, 0x1E, 0x78, + 0x8D, 0x78, 0x50, 0xCE, 0x8D, 0x6E, 0x12, 0xFB, 0xA2, 0x31, 0x65, 0x30, 0x19, 0x6C, 0x50, 0x7D, + 0x44, 0x2F, 0xDD, 0x71, 0xC8, 0xE7, 0xF4, 0x39, 0x7F, 0x78, 0x5E, 0x3D, 0x6C, 0xE3, 0x18, 0xB9, + 0xFF, 0x3B, 0xAD, 0xFF, 0x53, 0x13, 0x12, 0x8F, 0x30, 0xFB, 0x5C, 0x6D, 0xFF, 0x46, 0x97, 0xCF, + 0xEB, 0x32, 0x0B, 0xB0, 0x91, 0x2D, 0xBF, 0x6F, 0xAE, 0x6E, 0x01, 0x15, 0xF5, 0x71, 0x08, 0x42, + 0x1D, 0x6F, 0x1A, 0xF1, 0x4E, 0x71, 0x44, 0x6F, 0x73, 0xF3, 0x4C, 0x73, 0x32, 0x6A, 0x30, 0x99, + 0x29, 0xDF, 0x60, 0xA0, 0x80, 0xF3, 0x71, 0xE5, 0x84, 0xBB, 0x29, 0xC8, 0x0D, 0x7B, 0x34, 0xAF, + 0xDA, 0x0A, 0x65, 0xD6, 0x84, 0x62, 0xCB, 0x79, 0x86, 0x1A, 0x56, 0x94, 0xB6, 0x11, 0x97, 0x69, + 0xBA, 0x25, 0xFB, 0x5A, 0xB1, 0xB4, 0xC0, 0xB6, 0xCA, 0xF1, 0xFA, 0x7E, 0x75, 0xE4, 0x6D, 0xDA, + 0x9F, 0xE4, 0x56, 0x83, 0xE1, 0x9E, 0xFC, 0x83, 0x00, 0x43, 0x5B, 0xFC, 0x58, 0x43, 0x83, 0x95, + 0xB9, 0xFB, 0xE6, 0x58, 0x5E, 0xA9, 0xAA, 0x2A, 0x51, 0xB7, 0xE2, 0x83, 0x88, 0x0E, 0x88, 0xF4, + 0x30, 0x7F, 0x9B, 0xC4, 0x22, 0xE9, 0x1E, 0xA0, 0xB3, 0x8C, 0x14, 0x55, 0x6B, 0xC5, 0x0F, 0xA9, + 0x87, 0xF3, 0xC8, 0x1C, 0x95, 0x2A, 0x63, 0xB3, 0xE7, 0x1F, 0xE1, 0x23, 0x8B, 0x26, 0x2E, 0x73, + 0x22, 0x04, 0x2B, 0xE3, 0x1A, 0x23, 0x95, 0xA6, 0x8B, 0x18, 0x9B, 0x2E, 0x2D, 0xD8, 0xF2, 0x87, + 0x4E, 0x52, 0xFB, 0x72, 0x48, 0xDF, 0x01, 0xAC, 0x09, 0x47, 0x9C, 0xB5, 0xD2, 0xD0, 0xF0, 0xDB, + 0x5A, 0x8F, 0x0B, 0x8D, 0x6B, 0xFA, 0xF1, 0x0E, 0x47, 0xF4, 0x58, 0x86, 0xB7, 0xB6, 0x14, 0xC2, + 0x36, 0x23, 0x90, 0x14, 0xBF, 0xE2, 0x8F, 0x40, 0xFC, 0xC7, 0xC5, 0xAC, 0x84, 0x04, 0x0F, 0xC4, + 0x77, 0x6C, 0x9E, 0x4D, 0x9B, 0xB9, 0x56, 0xF2, 0xD0, 0x94, 0xE4, 0xDD, 0x31, 0x1C, 0xD7, 0x7C, + 0x0F, 0xE2, 0x55, 0xBA, 0xC0, 0x92, 0x88, 0xA6, 0xEF, 0xD6, 0x54, 0xE1, 0x38, 0x45, 0xE7, 0xD2, + 0xF6, 0x2F, 0x58, 0x4D, 0x7C, 0x67, 0xB0, 0xFC, 0xFB, 0xC9, 0xCE, 0xF3, 0x32, 0xFF, 0x13, 0xF2, + 0x57, 0xB4, 0x82, 0x46, 0x82, 0x25, 0x8F, 0x5E, 0x88, 0x26, 0x65, 0x76, 0x20, 0x31, 0xC2, 0x94, + 0x61, 0xCA, 0xFD, 0xFA, 0x0A, 0xAC, 0x16, 0x63, 0x4E, 0xA6, 0x5B, 0x68, 0xB9, 0x44, 0x26, 0xB2, + 0xCF, 0x69, 0xB4, 0x5E, 0xCE, 0x94, 0xE0, 0x6B, 0xE1, 0x24, 0x01, 0xA9, 0xEB, 0xBC, 0xDE, 0x40, + 0x65, 0x6F, 0x83, 0x15, 0x69, 0x5D, 0x09, 0xC2, 0xE3, 0x55, 0x0C, 0x1F, 0xAA, 0xC1, 0x07, 0x11, + 0xCE, 0xCB, 0xAB, 0xB5, 0xB7, 0xC4, 0x1F, 0x21, 0x0D, 0x59, 0x1D, 0xB0, 0x6D, 0x10, 0x43, 0xAC, + 0x8B, 0xE2, 0x54, 0x3D, 0x15, 0x60, 0xC7, 0x24, 0xF3, 0x78, 0x42, 0x57, 0xCE, 0x80, 0xE5, 0xB7, + 0x46, 0xF7, 0xA7, 0x81, 0x41, 0xA0, 0xDB, 0xF6, 0x30, 0x76, 0x94, 0x5A, 0x38, 0x18, 0x96, 0x0D, + 0x0E, 0x8A, 0x70, 0xA7, 0xFF, 0x1E, 0x45, 0xFB, 0x70, 0xA7, 0xD4, 0x29, 0x29, 0xDB, 0x4F, 0xAC, + 0x3B, 0xF6, 0x9F, 0xC2, 0x1E, 0xE1, 0xAC, 0xEC, 0xAD, 0x4B, 0xA3, 0x2D, 0xCF, 0x98, 0x3F, 0x92, + 0xD5, 0x7B, 0x58, 0xB2, 0xB2, 0xAB, 0x81, 0x4F, 0x56, 0x53, 0xB7, 0x0D, 0x15, 0xD3, 0x0F, 0x92, + 0xE7, 0x8F, 0x4E, 0xA0, 0x6A, 0x99, 0xBD, 0x2C, 0xB5, 0x81, 0x2B, 0xA1, 0x03, 0x87, 0x50, 0x07, + 0x30, 0xC3, 0x8C, 0xC7, 0x1C, 0x3F, 0x25, 0xFA, 0x66, 0x89, 0x70, 0x55, 0x86, 0xDF, 0x3D, 0xB7, + 0x90, 0x1B, 0x61, 0xB1, 0x0F, 0xD2, 0xC9, 0x62, 0xD1, 0x58, 0xE3, 0x4C, 0xC7, 0xCD, 0xB1, 0xA5, + 0x63, 0x7D, 0xF0, 0x0E, 0x23, 0x76, 0xC2, 0x66, 0x7D, 0x8C, 0x58, 0x41, 0xFE, 0x0E, 0x6B, 0x49, + 0x81, 0x23, 0x93, 0x2E, 0xDF, 0x91, 0x3D, 0x9F, 0x5E, 0xBB, 0xF0, 0x07, 0xA9, 0x94, 0xF7, 0xF0, + 0x0D, 0xD1, 0xF0, 0x99, 0x6E, 0xE7, 0x24, 0xEA, 0xA0, 0x04, 0x18, 0x4F, 0x8A, 0x2F, 0x8E, 0xA6, + 0x35, 0x3F, 0x35, 0xE8, 0x26, 0xFA, 0x21, 0xAD, 0x74, 0xDC, 0xA8, 0x7B, 0xEB, 0xF6, 0x6D, 0xD0, + 0x4E, 0x8D, 0x21, 0x11, 0x71, 0x71, 0x5F, 0xF6, 0x0E, 0xD7, 0xD7, 0x69, 0x2D, 0x41, 0xE3, 0xAB, + 0x8A, 0xAA, 0x20, 0x5A, 0x9D, 0xC5, 0x7D, 0x85, 0x63, 0xD3, 0xCD, 0xF5, 0x3D, 0xEE, 0x58, 0x69, + 0x48, 0xF0, 0x57, 0xB0, 0x64, 0xCA, 0x36, 0x2D, 0xF8, 0xF6, 0xE2, 0xA8, 0xDC, 0x7A, 0x33, 0xB5, + 0xE8, 0x44, 0x40, 0x88, 0x4A, 0xBA, 0x03, 0xA0, 0x4F, 0x49, 0xDB, 0x15, 0x65, 0x6A, 0xE5, 0xF3, + 0xFB, 0x01, 0x8A, 0x0B, 0x19, 0x6D, 0x92, 0x0E, 0x83, 0x6F, 0xFD, 0x6D, 0x54, 0xE4, 0x2C, 0xA6, + 0x07, 0xFF, 0x50, 0xAE, 0xE9, 0x25, 0x2F, 0xB2, 0x56, 0xD2, 0x71, 0xC8, 0x8C, 0x21, 0x06, 0xD7, + 0x13, 0x53, 0x65, 0x4C, 0xD2, 0xE7, 0xAE, 0x3D, 0xD5, 0x15, 0xD3, 0x0E, 0xAE, 0x23, 0x28, 0x4E, + 0xEF, 0x66, 0x35, 0xAF, 0x65, 0x3E, 0xAC, 0x29, 0x15, 0xBC, 0xC2, 0x9A, 0x96, 0xD8, 0x6B, 0xB5, + 0xAE, 0x54, 0xDC, 0xE8, 0x16, 0x31, 0xA3, 0xA6, 0x77, 0x19, 0x95, 0x22, 0x52, 0x06, 0x60, 0x39, + 0x1D, 0x72, 0x0A, 0x20, 0x40, 0x9F, 0x01, 0xFE, 0x69, 0x3D, 0xA0, 0xEF, 0xEE, 0x79, 0xFD, 0xC7, + 0x2B, 0x55, 0xE2, 0x51, 0x15, 0xDE, 0x11, 0x4D, 0x34, 0x8A, 0x1E, 0x03, 0x9E, 0xFB, 0xE0, 0xFD, + 0x77, 0x62, 0x14, 0xCD, 0x29, 0x69, 0x1C, 0x4B, 0x10, 0x27, 0x68, 0xC1, 0x7E, 0x3D, 0x20, 0xD0, + 0x11, 0xA2, 0x6A, 0x3E, 0xF9, 0xBF, 0x81, 0x0B, 0x16, 0xB1, 0x90, 0x22, 0x4A, 0x2D, 0x9C, 0x8E, + 0x71, 0xC1, 0x58, 0xB9, 0x65, 0x12, 0x93, 0xF9, 0x7B, 0x12, 0x89, 0x0E, 0x5E, 0x70, 0xD9, 0xF7, + 0xA9, 0x12, 0xF5, 0xA7, 0x9A, 0x35, 0xE1, 0x06, 0xB6, 0x3E, 0x09, 0x5B, 0x18, 0x10, 0x9F, 0x3D, + 0x33, 0xA3, 0x53, 0x2B, 0x82, 0xC9, 0x17, 0x1A, 0xF5, 0xF8, 0x32, 0x94, 0xA7, 0x37, 0x21, 0x7A, + 0x98, 0xE4, 0xFF, 0xEE, 0x26, 0x09, 0x74, 0x87, 0x96, 0xAA, 0xEE, 0x0D, 0xB4, 0x3D, 0xCE, 0x9A, + 0xEC, 0x4D, 0x2E, 0x57, 0x11, 0x76, 0xFF, 0x62, 0xA8, 0x03, 0xFC, 0xC6, 0x91, 0x3F, 0x73, 0x8E, + 0xF7, 0xB9, 0x34, 0xF1, 0xF1, 0x6E, 0x33, 0xCE, 0xF1, 0xEC, 0x48, 0xF6, 0x40, 0x01, 0x5C, 0xE6, + 0x42, 0x55, 0xA4, 0xFF, 0xEB, 0x13, 0xB4, 0xD7, 0x8B, 0x21, 0x88, 0xA0, 0xFE, 0xF1, 0x47, 0xA9, + 0x28, 0x36, 0x3A, 0x0E, 0x41, 0xDC, 0x07, 0x15, 0xAC, 0x5C, 0x41, 0x7D, 0x25, 0x11, 0x3D, 0x94, + 0xDF, 0x1D, 0x2C, 0x60, 0x52, 0x77, 0x10, 0x02, 0x8F, 0xB4, 0x97, 0x0E, 0x76, 0x26, 0x92, 0xFE, + 0xD9, 0xD5, 0x84, 0x6B, 0xD5, 0xA3, 0xDE, 0xE7, 0x37, 0xC8, 0x88, 0xAC, 0x06, 0xDD, 0x44, 0x90, + 0x7E, 0xC2, 0x95, 0xFB, 0x89, 0x73, 0x1D, 0x3E, 0x8A, 0xDA, 0x95, 0x5E, 0xBA, 0x26, 0x3B, 0xEB, + 0x2D, 0x49, 0xC3, 0x1F, 0xD2, 0x70, 0x76, 0x61, 0x41, 0x59, 0x0D, 0xF7, 0x88, 0x1E, 0x6E, 0x81, + 0xBD, 0x2B, 0x3E, 0xAF, 0x2C, 0x8D, 0xEC, 0x1F, 0x80, 0xBD, 0x81, 0x26, 0xE0, 0x3C, 0x99, 0x3A, + 0x41, 0xC7, 0x50, 0x3E, 0x37, 0xA0, 0x6B, 0xB0, 0x8A, 0x66, 0x74, 0x39, 0x37, 0x1E, 0xF8, 0x42, + 0x39, 0x40, 0xB3, 0x23, 0x73, 0xC3, 0x03, 0xBB, 0x3F, 0x63, 0x51, 0x08, 0x53, 0x82, 0x4D, 0x8D, + 0xE4, 0xC6, 0x08, 0xDE, 0xB8, 0x77, 0x77, 0xB2, 0x35, 0x24, 0x3D, 0x77, 0x49, 0x20, 0x3E, 0xF0, + 0x51, 0xD6, 0xE6, 0xD7, 0xD5, 0xFC, 0x36, 0xAB, 0x28, 0x8D, 0xE3, 0x09, 0x48, 0x10, 0x48, 0x02, + 0x7F, 0x53, 0x10, 0xB6, 0x28, 0xFB, 0x45, 0x86, 0xED, 0x71, 0x20, 0x28, 0xA9, 0x50, 0x50, 0xD0, + 0xB2, 0x6D, 0xAB, 0x97, 0x5F, 0xA1, 0x59, 0x88, 0xDB, 0x55, 0xF3, 0x1E, 0x16, 0x02, 0xC9, 0xF7, + 0xE2, 0x90, 0x8D, 0x5A, 0x8E, 0x89, 0x78, 0x2F, 0xD4, 0x4E, 0x7A, 0xAC, 0x87, 0x71, 0xF5, 0x88, + 0xFA, 0x67, 0xD2, 0x42, 0xBB, 0xA1, 0x01, 0x80, 0xD2, 0x57, 0x86, 0x45, 0x34, 0x41, 0x20, 0xDB, + 0xBD, 0x19, 0xA0, 0x5A, 0x73, 0x30, 0x4D, 0x0E, 0xC8, 0x4C, 0x73, 0x0A, 0x31, 0xE6, 0x49, 0x6A, + 0xE9, 0x67, 0xA0, 0x99, 0xD4, 0x67, 0x2C, 0x5A, 0x6C, 0x0F, 0x75, 0x67, 0x9E, 0xC5, 0xBD, 0xF9, + 0x66, 0xC6, 0x73, 0xC2, 0x72, 0xAC, 0x48, 0x50, 0x27, 0x63, 0x78, 0xD5, 0x90, 0x76, 0xF9, 0x8B, + 0xE9, 0x9E, 0x9B, 0xA3, 0x71, 0x2C, 0x92, 0x55, 0x37, 0xC0, 0xB7, 0x0E, 0x20, 0x66, 0xB8, 0x12, + 0xE2, 0x3F, 0xF7, 0x61, 0xE5, 0xBF, 0x94, 0xE2, 0x96, 0xA9, 0x42, 0x96, 0x21, 0xA5, 0x9B, 0xDC, + 0x23, 0xD2, 0x3A, 0x56, 0x1B, 0xBB, 0xAD, 0xF4, 0x54, 0x56, 0x8C, 0x37, 0x47, 0xC6, 0x2A, 0x35, + 0x4E, 0x5C, 0x18, 0xE0, 0xF3, 0x2F, 0xE5, 0x01, 0x4C, 0xA1, 0x0A, 0xB6, 0x24, 0xA1, 0x73, 0xDA, + 0x85, 0xC7, 0xE4, 0xE3, 0x99, 0x67, 0x22, 0x02, 0xCF, 0x51, 0x15, 0x75, 0xE3, 0x07, 0x2F, 0x6B, + 0xB3, 0xDE, 0x2F, 0x5D, 0x13, 0x40, 0xE8, 0x2B, 0xBC, 0x78, 0x55, 0x96, 0x1D, 0x15, 0x1E, 0x7D, + 0x9F, 0xD0, 0x3A, 0x5C, 0x7B, 0xC7, 0xF6, 0x1A, 0x6D, 0xBC, 0x69, 0x97, 0xF2, 0xC8, 0x78, 0xA1, + 0x20, 0x73, 0xFE, 0xDB, 0xF5, 0x57, 0xE2, 0x09, 0xC7, 0xF4, 0x1E, 0x85, 0x66, 0xDB, 0xEE, 0x4F, + 0x64, 0x3C, 0x48, 0x78, 0xB2, 0xF5, 0x2B, 0x01, 0x3E, 0x53, 0x80, 0x7D, 0xA8, 0xBC, 0x72, 0x47, + 0xF7, 0x10, 0x93, 0xA5, 0xA2, 0x82, 0x4C, 0x55, 0xF1, 0x78, 0xD3, 0xA9, 0xEC, 0xAC, 0x46, 0xD9, + 0x0D, 0x04, 0xC2, 0x12, 0x26, 0xC5, 0x5B, 0x2B, 0x1A, 0x2C, 0xAD, 0x58, 0xAC, 0x1D, 0x9D, 0x56, + 0x45, 0x15, 0xD2, 0xD0, 0xEA, 0x8E, 0xBE, 0xC6, 0xCB, 0x16, 0x9C, 0x17, 0x59, 0x23, 0x06, 0x52, + 0xA8, 0x41, 0x40, 0x19, 0xE0, 0xCC, 0x96, 0x4E, 0xA6, 0x43, 0x85, 0xA3, 0x4A, 0xCD, 0x67, 0xAD, + 0x48, 0xF0, 0x0D, 0x0A, 0xFF, 0xFC, 0x31, 0xE3, 0x8A, 0x4F, 0x50, 0xD9, 0xC7, 0xEE, 0x41, 0x51, + 0x66, 0xF2, 0x97, 0xA9, 0x07, 0x5B, 0xD7, 0x0E, 0xDB, 0xFD, 0x7C, 0x10, 0x98, 0xDB, 0x3C, 0xBD, + 0x41, 0x8E, 0x60, 0xDE, 0xB9, 0x0D, 0xDD, 0x9A, 0x19, 0x1E, 0xB9, 0x39, 0xD4, 0x2B, 0x13, 0x9B, + 0x56, 0xF9, 0x53, 0x42, 0x93, 0xBA, 0x2C, 0x1D, 0x12, 0x57, 0xED, 0xAD, 0xA2, 0xA3, 0xF0, 0x76, + 0xAD, 0x6F, 0x35, 0x6D, 0xDE, 0x9C, 0x42, 0xD1, 0x7D, 0x1E, 0x7D, 0xA8, 0x00, 0x16, 0x8E, 0x16, + 0xA2, 0x20, 0xE4, 0xC4, 0x3E, 0x8A, 0x77, 0x21, 0xC8, 0xD9, 0xD9, 0x5D, 0xF1, 0x29, 0x3F, 0x1E, + 0xCF, 0x1E, 0x2C, 0x84, 0x41, 0xC6, 0xB6, 0x76, 0x9D, 0x3F, 0xDB, 0x17, 0x5E, 0x4A, 0x40, 0x56, + 0x9A, 0xFD, 0xD0, 0xFE, 0xEB, 0xC9, 0xB9, 0xC0, 0x06, 0xC1, 0x06, 0x68, 0x32, 0x3C, 0x6A, 0xAA, + 0x5C, 0xF7, 0xEA, 0x5A, 0x58, 0x07, 0x64, 0xC4, 0x76, 0x30, 0x61, 0xD1, 0x1E, 0xB7, 0x0F, 0xDB, + 0x84, 0xFC, 0xA7, 0x10, 0xD5, 0x8B, 0xFE, 0xBA, 0x71, 0x6C, 0xB6, 0xD6, 0x5D, 0xBD, 0x26, 0x6E, + 0x22, 0xE9, 0x92, 0xB8, 0x3C, 0x13, 0xD4, 0xA9, 0xBF, 0x62, 0x12, 0x6D, 0xEC, 0x05, 0x46, 0xD1, + 0xC9, 0x8E, 0xFA, 0x14, 0x64, 0x6E, 0x06, 0xE6, 0x46, 0xE6, 0x38, 0xC0, 0x0B, 0x90, 0x3E, 0x2D, + 0xEB, 0x3C, 0x6B, 0x1D, 0x09, 0x01, 0x85, 0xD8, 0x2E, 0x76, 0x5E, 0x2F, 0x06, 0xA2, 0xE2, 0xB5, + 0x2C, 0xEC, 0xDE, 0xC6, 0x5A, 0x2C, 0xA7, 0x9F, 0xFA, 0x6C, 0xC7, 0x11, 0x78, 0x17, 0xFA, 0x72, + 0x87, 0x19, 0x2D, 0xEE, 0x17, 0x91, 0xB2, 0x34, 0x74, 0x53, 0x17, 0x64, 0xD1, 0x08, 0x33, 0x5B, + 0xD1, 0x19, 0x84, 0xAB, 0x4D, 0x65, 0x9C, 0x1B, 0xD9, 0x09, 0x85, 0x4B, 0x5F, 0xCD, 0xD5, 0xF9, + 0x8A, 0x0C, 0x0C, 0xE0, 0x3C, 0x8E, 0xC4, 0x1A, 0x8E, 0x4A, 0xA2, 0xE2, 0x7B, 0xF7, 0xED, 0x2F, + 0x58, 0x39, 0x52, 0x10, 0x82, 0x25, 0x48, 0xDD, 0xFB, 0xCF, 0x07, 0xF6, 0xAE, 0x94, 0xBA, 0xA7, + 0x41, 0xFE, 0x64, 0x3C, 0x3B, 0x65, 0x04, 0x71, 0x7E, 0x29, 0xCB, 0xF3, 0x59, 0xAD, 0xF5, 0x76, + 0xAF, 0x88, 0x0B, 0x4A, 0x75, 0xC3, 0x77, 0x53, 0x05, 0xA2, 0x36, 0x68, 0xFB, 0x80, 0xFF, 0x4C, + 0xF1, 0x0E, 0xA8, 0x12, 0x48, 0xC6, 0x6E, 0x3C, 0x7F, 0x91, 0x1D, 0x71, 0xE4, 0x98, 0x53, 0xC1, + 0x97, 0xAE, 0x61, 0x7A, 0xC5, 0xBD, 0x9D, 0x48, 0x2F, 0x5A, 0x40, 0x0D, 0xF1, 0x3A, 0x55, 0x76, + 0x51, 0x38, 0x4E, 0x81, 0xF5, 0x24, 0xD8, 0xF3, 0x9E, 0xDE, 0xAD, 0xE7, 0x69, 0x08, 0x78, 0xC5, + 0xBE, 0xB2, 0x78, 0x63, 0xE3, 0x27, 0xA1, 0x95, 0xD0, 0xAB, 0x08, 0xD7, 0x8E, 0x87, 0x8C, 0xB1, + 0xC3, 0xFE, 0xE0, 0x04, 0x5A, 0x02, 0xD6, 0x28, 0x27, 0x6D, 0x62, 0xA1, 0x5F, 0x5C, 0xC8, 0x00, + 0x96, 0x48, 0x3F, 0x54, 0xAA, 0x5B, 0x20, 0x9F, 0x9F, 0xE0, 0x58, 0xD4, 0x54, 0xB7, 0x05, 0x77, + 0x68, 0x44, 0x1C, 0x64, 0xEB, 0xEF, 0x3D, 0x56, 0x7E, 0x0C, 0x8A, 0x84, 0x46, 0x5D, 0x46, 0x38, + 0xCB, 0xDF, 0x20, 0xE2, 0x26, 0xB5, 0x3B, 0x39, 0x37, 0xAB, 0x1B, 0xBC, 0x78, 0x39, 0x44, 0x55, + 0x8A, 0x56, 0xA8, 0xC3, 0x1F, 0xD4, 0x7F, 0xB7, 0xCD, 0xA0, 0x2C, 0xEC, 0x24, 0xDB, 0xBD, 0xCF, + 0xC5, 0x25, 0xC9, 0x74, 0x21, 0x29, 0xCF, 0xE1, 0xBC, 0xF2, 0xA6, 0x4B, 0x0E, 0xD4, 0x7A, 0xCB, + 0xB6, 0xE9, 0xEB, 0xA3, 0xA4, 0x0B, 0x63, 0xB0, 0xD0, 0x2F, 0xE0, 0x44, 0x3F, 0x03, 0xB6, 0xDF, + 0x32, 0x32, 0x21, 0x03, 0xEC, 0x84, 0x83, 0x56, 0x34, 0xAE, 0xE0, 0x57, 0x0B, 0xE1, 0x57, 0xB4, + 0x7A, 0x40, 0xD9, 0xE1, 0x49, 0x85, 0xAE, 0xF4, 0xAF, 0x28, 0x07, 0x78, 0x3B, 0x12, 0x01, 0x08, + 0x85, 0xCB, 0xDF, 0xE7, 0xEF, 0x93, 0x64, 0x31, 0x59, 0xBF, 0xF2, 0x96, 0x7B, 0xAA, 0x97, 0xA6, + 0xBC, 0xD3, 0x1B, 0xE2, 0x4F, 0x5A, 0x60, 0x62, 0xA6, 0x12, 0x2D, 0x73, 0x07, 0x0B, 0x79, 0x1C, + 0x97, 0xAF, 0x82, 0xD9, 0x79, 0x78, 0xF5, 0x8A, 0x91, 0x73, 0x7A, 0x39, 0x47, 0x79, 0x56, 0xF9, + 0x64, 0xF6, 0x03, 0x09, 0xCC, 0xE3, 0x68, 0xE0, 0x9B, 0xC5, 0xF8, 0xF8, 0xB0, 0xFE, 0x44, 0xE4, + 0xE3, 0xF9, 0x22, 0xBC, 0x6B, 0x99, 0xA3, 0x98, 0x37, 0x37, 0x0E, 0x22, 0xDB, 0x2A, 0x7A, 0xD9, + 0xCC, 0xBF, 0xF8, 0x3C, 0x62, 0x73, 0x12, 0x63, 0xA0, 0xF4, 0x3D, 0x7F, 0x69, 0xD9, 0xA2, 0x09, + 0x9F, 0xA0, 0xA9, 0xC2, 0x53, 0xFE, 0x58, 0xBC, 0x77, 0xAE, 0x2C, 0x0B, 0x6C, 0xC1, 0x93, 0xFD, + 0x91, 0x2D, 0x3E, 0x6F, 0xBA, 0xA1, 0xFF, 0x95, 0xB5, 0xB6, 0x17, 0x88, 0x6A, 0x59, 0x8B, 0x9B, + 0xDF, 0x55, 0x38, 0xD8, 0x8E, 0x51, 0x14, 0x2C, 0x01, 0x5B, 0xA6, 0xDE, 0xA8, 0xA0, 0xC8, 0xCD, + 0xD3, 0x7A, 0x22, 0xB2, 0xCB, 0xB4, 0xE3, 0x02, 0x50, 0xAE, 0x52, 0xD0, 0xFE, 0x82, 0x09, 0xE7, + 0x6A, 0xE8, 0x74, 0x0E, 0x63, 0x25, 0xF2, 0x2A, 0x41, 0xD1, 0x45, 0x08, 0x30, 0xCF, 0xD3, 0xA3, + 0xA9, 0x8A, 0xF2, 0xD6, 0xBF, 0xF0, 0xA0, 0xD3, 0xDD, 0x73, 0xE4, 0x7F, 0x72, 0xD6, 0x1F, 0x7D, + 0x78, 0x43, 0x5A, 0xDF, 0x25, 0xEF, 0xDA, 0xF3, 0xDB, 0x31, 0xE7, 0xC1, 0x78, 0x6C, 0xD5, 0xD8, + 0xBE, 0xD8, 0xD1, 0xB1, 0x9F, 0x1B, 0xD8, 0xF9, 0x18, 0x73, 0xCE, 0x21, 0x90, 0x54, 0xC0, 0x6E, + 0xD5, 0x6B, 0xDB, 0xE7, 0xAB, 0x0D, 0x18, 0x56, 0x21, 0x81, 0x93, 0x25, 0x57, 0x08, 0x12, 0x6C, + 0x0E, 0x7C, 0x18, 0x10, 0x16, 0xD1, 0x2F, 0x64, 0xD8, 0x19, 0x97, 0xCD, 0x7F, 0xD5, 0x02, 0x8B, + 0x44, 0xD4, 0xDE, 0x24, 0xE2, 0x29, 0x15, 0x1F, 0x2C, 0x1D, 0x32, 0x97, 0x28, 0xFD, 0xD1, 0x59, + 0xD1, 0x2A, 0xBF, 0x64, 0xF8, 0xE8, 0xDF, 0x2C, 0x8C, 0x10, 0xA1, 0x11, 0xDB, 0x40, 0x36, 0xF7, + 0x30, 0x2A, 0x2B, 0x5B, 0x30, 0x65, 0x8D, 0x64, 0x15, 0x69, 0xCB, 0x3A, 0x8A, 0x30, 0xC2, 0xF5, + 0x76, 0xFF, 0xCB, 0xD4, 0x83, 0xEF, 0x9B, 0xB4, 0xFA, 0x3A, 0x57, 0xDB, 0x79, 0xE5, 0x17, 0x09, + 0x03, 0xFE, 0x2B, 0x80, 0x31, 0x98, 0xCD, 0x0C, 0x05, 0xF6, 0xE0, 0xA1, 0x49, 0xC9, 0x7C, 0x95, + 0x26, 0x57, 0x5E, 0xC5, 0x05, 0x38, 0xE9, 0x74, 0xF1, 0x1F, 0xFB, 0x5D, 0x9E, 0x83, 0xE7, 0x97, + 0xEA, 0x4D, 0x4A, 0xEC, 0xE7, 0x75, 0x2B, 0x47, 0xC8, 0x9A, 0xEA, 0x2C, 0x56, 0xFF, 0x41, 0x3D, + 0x12, 0x3E, 0x35, 0x00, 0x34, 0x81, 0xC9, 0x5F, 0xCA, 0x26, 0x3E, 0x32, 0x08, 0xE8, 0x73, 0xE4, + 0xA2, 0xDF, 0x17, 0x35, 0xC3, 0x8B, 0x88, 0x88, 0x6E, 0x4B, 0x42, 0x7B, 0x95, 0x17, 0x29, 0x1A, + 0x2C, 0xB4, 0xFF, 0xDA, 0x75, 0x03, 0x69, 0x3D, 0x78, 0x93, 0x9B, 0x3A, 0xCD, 0x09, 0x1B, 0x58, + 0xE2, 0xAD, 0x3D, 0x93, 0x76, 0x66, 0x27, 0xEA, 0x0B, 0x88, 0x49, 0xD0, 0xDA, 0x12, 0xDB, 0xE2, + 0x59, 0x40, 0x33, 0x1A, 0x64, 0xC2, 0xB4, 0x47, 0x48, 0x63, 0xBB, 0xC9, 0x49, 0x5A, 0xD2, 0xAA, + 0xB1, 0x1C, 0xBC, 0x1E, 0xA5, 0x7E, 0x1B, 0x3A, 0x8B, 0x67, 0x28, 0xE6, 0x2F, 0xAF, 0x44, 0x1B, + 0x74, 0xD6, 0x4F, 0x4C, 0x88, 0xE7, 0x93, 0x05, 0xC2, 0x21, 0x42, 0x8E, 0x65, 0x41, 0x6F, 0x34, + 0x02, 0xC5, 0x4C, 0x93, 0x06, 0x7F, 0xB3, 0xBE, 0x92, 0x17, 0x0C, 0x34, 0x4E, 0xC8, 0xF9, 0xF6, + 0xD3, 0x9F, 0x6B, 0xAB, 0x2E, 0x53, 0xD0, 0xB4, 0xFD, 0x93, 0xFB, 0xD9, 0x2D, 0xD8, 0x00, 0x7D, + 0x19, 0x41, 0x23, 0xC1, 0xF9, 0x53, 0x1C, 0xFF, 0x9B, 0x85, 0x9C, 0x1C, 0x89, 0x8C, 0xA9, 0xBB, + 0xE4, 0xB0, 0x74, 0xC8, 0x8F, 0xF5, 0xDC, 0x33, 0x15, 0xB8, 0x98, 0x96, 0x5B, 0x24, 0x2A, 0x1B, + 0x87, 0x96, 0x32, 0x7B, 0xCB, 0x48, 0x3A, 0x1F, 0x4A, 0xF5, 0x3D, 0x34, 0x4E, 0x34, 0x0E, 0x45, + 0xEA, 0xE6, 0x87, 0xC7, 0x76, 0x6C, 0x08, 0xA3, 0xB4, 0x11, 0xF9, 0x7D, 0x29, 0x60, 0x4C, 0x4C, + 0x73, 0x4A, 0x1C, 0x65, 0xDC, 0x64, 0x6B, 0x86, 0xAA, 0xB1, 0xB8, 0xB7, 0x98, 0x77, 0x8F, 0x98, + 0xDC, 0x16, 0xA0, 0xE5, 0xEE, 0xE1, 0xB1, 0x47, 0xEA, 0x33, 0x8D, 0xDC, 0x97, 0x24, 0x8D, 0x61, + 0xC7, 0x8F, 0x50, 0xA9, 0x0A, 0xC5, 0x63, 0x0F, 0xBB, 0x8B, 0xDA, 0x91, 0x3E, 0x99, 0x74, 0x07, + 0xE8, 0x8B, 0xB7, 0x63, 0x10, 0x4B, 0x89, 0x1F, 0x8F, 0xDB, 0x7A, 0x10, 0xA8, 0xB4, 0xDB, 0x67, + 0x17, 0xCE, 0x8F, 0x31, 0x53, 0x30, 0x40, 0x46, 0x8D, 0x85, 0x31, 0xEC, 0x06, 0xA7, 0x3E, 0xE1, + 0x99, 0x17, 0xAE, 0x3B, 0x91, 0xDD, 0xB5, 0xE9, 0x74, 0xC9, 0x00, 0xF3, 0x55, 0x8E, 0x1E, 0xA0, + 0x97, 0xBF, 0x7F, 0x96, 0x2B, 0x98, 0x49, 0x1A, 0xDA, 0x42, 0x70, 0xA4, 0xFD, 0x38, 0x1D, 0x9C, + 0x8B, 0xE5, 0x6E, 0x68, 0xD2, 0xB3, 0x5F, 0xDC, 0x56, 0xE0, 0xF4, 0x01, 0x0B, 0x0C, 0xFC, 0x75, + 0xAA, 0x28, 0x47, 0xE5, 0xCD, 0x1B, 0xA9, 0x30, 0x26, 0x10, 0xFE, 0x9B, 0x10, 0xB1, 0xD7, 0x07, + 0xD9, 0x11, 0x7C, 0x4C, 0x19, 0x8A, 0xAF, 0x02, 0x8B, 0x0C, 0x45, 0x6E, 0x54, 0x67, 0x1B, 0x2A, + 0x3F, 0x7D, 0xC6, 0x67, 0x5C, 0x8D, 0xE3, 0xA8, 0x26, 0xB4, 0xEC, 0x08, 0xE3, 0x9B, 0xF6, 0x0B, + 0x3F, 0xA7, 0xFA, 0xED, 0x80, 0x43, 0x56, 0xCC, 0x40, 0xCF, 0xAD, 0x20, 0x6A, 0x39, 0xA4, 0x8C, + 0x16, 0x01, 0x0A, 0x65, 0xBD, 0x59, 0x15, 0x12, 0xB0, 0xC9, 0xF5, 0xCA, 0x0E, 0x74, 0x55, 0x2F, + 0xAD, 0x9A, 0xC4, 0x80, 0xD9, 0x1E, 0xAA, 0x90, 0x99, 0x41, 0x14, 0xE9, 0xC5, 0xE0, 0x96, 0x35, + 0xB3, 0x1F, 0x90, 0x5E, 0xEC, 0x0A, 0x77, 0xA6, 0xF9, 0xAC, 0x35, 0x95, 0xC8, 0xAC, 0x8A, 0x5D, + 0xAF, 0x7F, 0xAB, 0x95, 0x88, 0x00, 0xCE, 0x22, 0x3A, 0xF8, 0x93, 0x22, 0x49, 0x10, 0xED, 0xA5, + 0xDC, 0x43, 0x34, 0xA1, 0x19, 0x0F, 0x6A, 0x9C, 0xC4, 0x15, 0xD6, 0x67, 0x23, 0xCF, 0xCE, 0xF1, + 0xAE, 0x1F, 0x98, 0xB2, 0x15, 0xBD, 0x56, 0x9A, 0x3B, 0x24, 0x07, 0xA3, 0x6C, 0xC5, 0xA4, 0x32, + 0x91, 0x9B, 0x2E, 0xFA, 0x2F, 0x46, 0x1E, 0xBE, 0x03, 0xFB, 0xC6, 0x7E, 0xC3, 0x6C, 0x3D, 0xC9, + 0xD2, 0x8A, 0x6C, 0x1A, 0xA4, 0xD5, 0xE2, 0x23, 0x5E, 0x49, 0xDE, 0x13, 0x2C, 0x33, 0x7A, 0x50, + 0x79, 0x50, 0x0D, 0x65, 0xBB, 0x72, 0xF7, 0x59, 0xFD, 0xEA, 0x1C, 0x64, 0x80, 0xF4, 0x82, 0x95, + 0x1D, 0x4C, 0x73, 0x15, 0xC3, 0x19, 0x9C, 0x42, 0x52, 0x44, 0x5E, 0x4D, 0xA2, 0x37, 0x9B, 0x32, + 0xD4, 0xCD, 0xB5, 0x45, 0x9D, 0xC5, 0x70, 0x34, 0x56, 0x7E, 0xA9, 0x94, 0xD9, 0x99, 0x30, 0xDA, + 0xF8, 0xE0, 0x78, 0x9E, 0x6A, 0xAD, 0xD4, 0x75, 0x9B, 0xE0, 0xC6, 0x9A, 0x45, 0x7F, 0xE3, 0xFC, + 0x49, 0xD3, 0x22, 0x27, 0x24, 0xDE, 0xFA, 0x97, 0xA8, 0xB5, 0xB6, 0x8D, 0xE2, 0xD3, 0x8C, 0xD2, + 0x7F, 0xBB, 0x2C, 0x31, 0x9C, 0x3D, 0x9E, 0xCE, 0x7D, 0x67, 0x7C, 0xBD, 0x6B, 0x89, 0x5C, 0xD1, + 0x43, 0xFE, 0x06, 0x85, 0x0C, 0xF0, 0x03, 0xFA, 0xC7, 0x9E, 0xBC, 0xEC, 0x8B, 0xF7, 0x56, 0x62, + 0xC7, 0x1C, 0xB2, 0x90, 0xCA, 0x6E, 0x6A, 0x7C, 0x07, 0x20, 0x03, 0x13, 0x7E, 0x08, 0x05, 0xB0, + 0xB2, 0x37, 0xFD, 0xA1, 0xFE, 0x2D, 0xCF, 0xF0, 0x47, 0x42, 0x0A, 0x44, 0x5A, 0x4C, 0x7C, 0xA0, + 0x42, 0xA6, 0x88, 0x89, 0x00, 0x00, 0xF5, 0xD5, 0xD8, 0x36, 0x99, 0x48, 0x44, 0x0B, 0x81, 0x08, + 0xDF, 0x71, 0x72, 0xCC, 0x7D, 0x72, 0x02, 0x61, 0x27, 0x67, 0x81, 0x04, 0xBF, 0xA3, 0x81, 0x4E, + 0xE7, 0x9D, 0x16, 0xD3, 0x6B, 0x75, 0x70, 0x38, 0xB6, 0xBC, 0xFC, 0xFF, 0x07, 0x36, 0x70, 0x9A, + 0x47, 0x0A, 0xA7, 0x68, 0x64, 0x20, 0xCD, 0xD1, 0x35, 0xDC, 0x95, 0x2B, 0x23, 0x98, 0x4F, 0x01, + 0x6F, 0x93, 0xC2, 0xC3, 0xAD, 0x48, 0x9F, 0x40, 0xA8, 0x65, 0xC7, 0xA0, 0x43, 0xC8, 0xF9, 0xD6, + 0x7C, 0x4E, 0x1B, 0x35, 0xCE, 0x13, 0xF6, 0x22, 0x6F, 0x74, 0xD2, 0xC0, 0x92, 0xC3, 0xAA, 0xFB, + 0x39, 0x43, 0x17, 0x5C, 0x6A, 0x2E, 0xA8, 0xAA, 0x3C, 0x1D, 0xB7, 0x6A, 0x55, 0xF6, 0x09, 0x37, + 0x8E, 0x7B, 0xF1, 0xA4, 0x63, 0x58, 0x22, 0x7C, 0xB5, 0x5A, 0x72, 0x9A, 0x0C, 0xF0, 0xFA, 0xFA, + 0x6D, 0x2D, 0xDC, 0x3F, 0x4A, 0xC6, 0x6A, 0x7C, 0x40, 0xD4, 0xA5, 0x0B, 0x07, 0x30, 0x52, 0x59, + 0x9C, 0xE2, 0x28, 0x27, 0x22, 0xA6, 0xE1, 0x6A, 0x06, 0xAA, 0x47, 0xCF, 0x52, 0x4D, 0x29, 0x7E, + 0x42, 0xC1, 0x18, 0xF0, 0xEE, 0xD5, 0x52, 0x01, 0x52, 0xC8, 0x57, 0x8B, 0x78, 0x30, 0x0D, 0xEB, + 0xCD, 0x04, 0x91, 0x5E, 0x55, 0x40, 0x98, 0x77, 0xB5, 0x77, 0x9F, 0xCA, 0xA8, 0xDF, 0x8D, 0x76, + 0x87, 0x34, 0xC5, 0xC8, 0xEA, 0x6D, 0x1F, 0x6C, 0x2B, 0x6A, 0x2A, 0xCF, 0x7C, 0x5C, 0x75, 0x75, + 0x7F, 0xCD, 0xCC, 0xA9, 0x52, 0xFA, 0xAB, 0xD7, 0xB6, 0xE3, 0x92, 0xA1, 0x08, 0xBC, 0xB1, 0xA1, + 0x0C, 0xE1, 0x1A, 0xC2, 0xCA, 0x5E, 0xE8, 0x01, 0xCB, 0xB3, 0x3A, 0xCD, 0x1D, 0xC2, 0xA4, 0x68, + 0xEC, 0x74, 0xA1, 0x32, 0xF3, 0xD6, 0x93, 0x98, 0xC8, 0x13, 0xB2, 0x86, 0xE6, 0x00, 0x0D, 0x0F, + 0x07, 0x78, 0x28, 0x02, 0x70, 0xBA, 0xD9, 0x22, 0x21, 0x3B, 0x57, 0x0C, 0x1E, 0x7D, 0x12, 0x7B, + 0x5A, 0x28, 0x17, 0x80, 0x37, 0x2F, 0x2A, 0x22, 0x91, 0xC8, 0xB2, 0xDA, 0xCE, 0x83, 0x7A, 0x49, + 0xF4, 0x85, 0x5A, 0x6D, 0x46, 0xF9, 0x0B, 0xAE, 0x1C, 0xBA, 0x9A, 0xEB, 0x06, 0xB7, 0x1F, 0x7F, + 0x9A, 0x7B, 0x0D, 0xFE, 0x36, 0x85, 0x80, 0x07, 0xA0, 0xD1, 0x71, 0xBA, 0xFD, 0xFD, 0xF4, 0x73, + 0x9B, 0xDD, 0xAA, 0x4F, 0x87, 0x9E, 0xBF, 0xA5, 0x8B, 0xEF, 0x83, 0xAE, 0xF2, 0xC6, 0x69, 0x13, + 0x5C, 0x3D, 0x9A, 0x2E, 0xE4, 0xC9, 0x75, 0x4C, 0x4F, 0x9E, 0xC1, 0xE1, 0xDC, 0x03, 0xAB, 0x84, + 0x86, 0x3F, 0x49, 0xF4, 0x03, 0xA3, 0x82, 0x38, 0x8C, 0x27, 0x8B, 0xF3, 0x2B, 0x57, 0xBA, 0x70, + 0xDF, 0x39, 0x9F, 0xC2, 0xA6, 0x9B, 0xED, 0x89, 0xDB, 0x14, 0x69, 0x4E, 0x6D, 0xCA, 0x46, 0x1C, + 0x0E, 0xD4, 0x44, 0x51, 0x2B, 0x92, 0x35, 0x9F, 0xCC, 0xB2, 0xFC, 0xED, 0xE6, 0xD3, 0x63, 0x8D, + 0x2D, 0x1C, 0x3E, 0xFD, 0x73, 0xD7, 0x16, 0x10, 0xEF, 0xE0, 0x88, 0xD9, 0xF8, 0x73, 0x86, 0x02, + 0xD7, 0x61, 0x28, 0x3E, 0x36, 0xB1, 0x03, 0x91, 0xA2, 0xB4, 0xFD, 0x3D, 0x7B, 0xE7, 0x5E, 0xBF, + 0xCC, 0x20, 0x12, 0x02, 0xA8, 0x25, 0x0A, 0xDA, 0x6E, 0x32, 0xA8, 0xA1, 0xEA, 0xC3, 0x12, 0x40, + 0x8A, 0xC9, 0x72, 0x68, 0x2D, 0x62, 0xCF, 0xDC, 0x76, 0x05, 0x01, 0x60, 0xCC, 0xDF, 0x4E, 0x36, + 0xD3, 0x87, 0x96, 0x19, 0xDE, 0x17, 0xB8, 0x86, 0x78, 0xA6, 0x19, 0xCB, 0x89, 0x6A, 0xF0, 0xB0, + 0x53, 0x3F, 0xF7, 0xA9, 0x74, 0xBB, 0x04, 0x27, 0x9D, 0x2B, 0x98, 0x57, 0xFD, 0x26, 0x32, 0xEB, + 0xD2, 0x89, 0x0C, 0x49, 0x4F, 0x50, 0x46, 0x20, 0xD0, 0x22, 0x2C, 0x4C, 0x6C, 0x7F, 0xF3, 0xA0, + 0x5A, 0x27, 0x6C, 0xAB, 0x6D, 0xFC, 0xE6, 0x50, 0x22, 0x17, 0x65, 0x6A, 0xD0, 0xC1, 0xCF, 0xB3, + 0xF4, 0xC0, 0x03, 0x6C, 0x7F, 0xA4, 0x14, 0x1C, 0xBF, 0x95, 0xF9, 0x8B, 0xB3, 0x98, 0xA1, 0xCA, + 0xC6, 0xE9, 0x0B, 0x56, 0xAD, 0xA9, 0x58, 0x9F, 0x9C, 0xAE, 0xB0, 0xDA, 0x42, 0x5D, 0x87, 0x79, + 0x2F, 0xFF, 0xC5, 0x16, 0x80, 0x95, 0xB8, 0x1E, 0xCA, 0xB6, 0x4C, 0x00, 0x71, 0x06, 0x53, 0x27, + 0xA1, 0x8E, 0xE5, 0x93, 0x6D, 0x33, 0x2E, 0x1E, 0xDB, 0x51, 0x7F, 0xA0, 0x50, 0xD3, 0x92, 0xD1, + 0xE1, 0xB3, 0xED, 0xFB, 0x2A, 0x79, 0xD4, 0x92, 0xBE, 0xBF, 0xCA, 0xFE, 0x6D, 0xEB, 0x65, 0xBE, + 0xD7, 0x91, 0x98, 0x9D, 0x70, 0xA7, 0xD5, 0x1E, 0x03, 0xD1, 0xD1, 0x43, 0x61, 0xDE, 0x09, 0x74, + 0x2F, 0xB8, 0xA0, 0xC2, 0x94, 0xD6, 0x84, 0x1B, 0x54, 0x85, 0x3B, 0x2A, 0xC0, 0x5C, 0xA1, 0x85, + 0x43, 0x12, 0x3E, 0xCD, 0x19, 0x0E, 0x44, 0x33, 0x34, 0xE9, 0xF7, 0xFB, 0xC6, 0xAD, 0x5A, 0x84, + 0xDD, 0x60, 0x62, 0x4D, 0xE1, 0x50, 0x37, 0xE6, 0x1E, 0x57, 0xEC, 0x47, 0x7B, 0xBE, 0x2D, 0xB8, + 0x0B, 0x40, 0x23, 0xF5, 0x71, 0x9A, 0xD5, 0x89, 0xCF, 0x7D, 0xCC, 0x3C, 0xFF, 0x90, 0x21, 0xC9, + 0x88, 0x77, 0x9E, 0x0D, 0x20, 0x06, 0x7D, 0x6E, 0xF7, 0x51, 0xBB, 0xDF, 0x26, 0x75, 0x46, 0x6E, + 0xDC, 0x3B, 0x62, 0x0A, 0x34, 0x89, 0x90, 0x5B, 0x19, 0x3B, 0xF8, 0xFB, 0x09, 0x7D, 0xEC, 0x8F, + 0xF6, 0x0F, 0xBE, 0x30, 0x13, 0x7C, 0xDB, 0x59, 0x96, 0xD8, 0xB8, 0xE9, 0x73, 0xF0, 0x3A, 0xB8, + 0x4E, 0x88, 0x7A, 0xC5, 0xC0, 0x37, 0xF9, 0xB6, 0x80, 0xB6, 0x33, 0xD6, 0x72, 0xC3, 0xB4, 0x9B, + 0x96, 0xE6, 0x43, 0x8F, 0xEA, 0x35, 0x80, 0x21, 0x97, 0xFF, 0x08, 0xEC, 0xE1, 0xB8, 0xCE, 0xF8, + 0x08, 0xBF, 0x68, 0xD0, 0x87, 0xD6, 0x4D, 0xDD, 0xA6, 0x7B, 0xE2, 0x16, 0x5A, 0x8E, 0xDB, 0x27, + 0x59, 0xC6, 0x6C, 0x89, 0x24, 0x87, 0x43, 0x67, 0xFB, 0xC5, 0xC1, 0x68, 0x2F, 0x6D, 0x9A, 0xE0, + 0x53, 0x65, 0xAE, 0xE7, 0x8F, 0x05, 0x1A, 0x50, 0x50, 0x5B, 0x08, 0x72, 0x7E, 0x54, 0xA8, 0x3A, + 0xE1, 0x9D, 0x76, 0xB3, 0x01, 0x43, 0x61, 0x7A, 0x2D, 0x5C, 0x05, 0xB5, 0xC2, 0xDF, 0x66, 0xB5, + 0xF9, 0x2C, 0xA6, 0x1B, 0x2E, 0xAE, 0xDD, 0x6E, 0xF7, 0x57, 0xC6, 0xB5, 0xB0, 0x9B, 0x88, 0xC0, + 0xE9, 0x09, 0x39, 0x5C, 0x59, 0x7C, 0xF0, 0xC2, 0xA7, 0x81, 0x2A, 0x0D, 0x41, 0xF4, 0x60, 0x17, + 0xBF, 0xC4, 0x04, 0xBA, 0x28, 0x1B, 0x35, 0xC3, 0x8C, 0xF7, 0xD0, 0x49, 0x5E, 0x37, 0xA7, 0x74, + 0x5C, 0xB2, 0x46, 0x4B, 0x00, 0xAA, 0xEF, 0xB3, 0x52, 0x4B, 0x17, 0x27, 0x2F, 0xB6, 0x48, 0xF4, + 0x09, 0x70, 0xD4, 0xF7, 0xF2, 0xAD, 0xED, 0x1B, 0x9A, 0x3D, 0x60, 0x56, 0x14, 0xF0, 0xCE, 0xCB, + 0x59, 0x62, 0x33, 0xA8, 0xEF, 0xE4, 0x80, 0x6F, 0xD0, 0x4D, 0x21, 0x85, 0x1D, 0x5A, 0xAF, 0xFF, + 0xEA, 0xC3, 0xC1, 0xCC, 0x9F, 0x53, 0x15, 0xBF, 0x56, 0x24, 0x8D, 0x64, 0x3A, 0x63, 0xEB, 0x57, + 0x21, 0xEA, 0x71, 0xF8, 0xEB, 0x2A, 0x2E, 0x8E, 0x96, 0x7A, 0xDD, 0x05, 0xA0, 0x1F, 0x7E, 0x4F, + 0xFC, 0xB3, 0x12, 0x74, 0x28, 0xB3, 0x71, 0x2A, 0xFF, 0x8F, 0x38, 0xA0, 0x3F, 0x3C, 0xBC, 0x16, + 0x18, 0x0A, 0x99, 0xF6, 0x6B, 0x71, 0x97, 0xCA, 0x57, 0x72, 0xAB, 0xC6, 0xFE, 0xAD, 0xFA, 0x8F, + 0xDE, 0x15, 0xA7, 0x62, 0x28, 0xAA, 0x70, 0xFE, 0xF0, 0xFF, 0xD3, 0x66, 0x07, 0xE1, 0x65, 0xF7, + 0x99, 0x56, 0x2D, 0xE2, 0xB1, 0x08, 0xFB, 0xA3, 0xD9, 0x07, 0x28, 0x64, 0xA5, 0xB0, 0xCC, 0x7B, + 0x38, 0xBB, 0x90, 0xFC, 0x8A, 0xC5, 0x12, 0xBB, 0x42, 0xEA, 0x5D, 0x20, 0x00, 0xBA, 0xF7, 0x6F, + 0xEA, 0xC0, 0x81, 0x02, 0xAB, 0x5A, 0xD3, 0x4E, 0x1E, 0xE0, 0x8A, 0x25, 0xF0, 0xE1, 0xC9, 0x7B, + 0x60, 0xBE, 0xD7, 0xF2, 0xB3, 0xCC, 0x92, 0xB6, 0xF5, 0xE2, 0x77, 0x91, 0x28, 0xDC, 0xE5, 0x65, + 0x4C, 0xE1, 0x4A, 0x6C, 0xDD, 0x83, 0x3E, 0x6F, 0xF4, 0x9B, 0xFD, 0x8A, 0x8E, 0x79, 0x06, 0x06, + 0xEC, 0x35, 0x53, 0x7C, 0xF8, 0x59, 0x3B, 0xBD, 0x75, 0x0C, 0xA3, 0xA9, 0x7A, 0x8F, 0xF1, 0xEA, + 0x39, 0x84, 0x35, 0x2F, 0xFE, 0x6C, 0xEB, 0x5F, 0x5C, 0x25, 0x66, 0x7F, 0x05, 0x5F, 0x38, 0xB8, + 0x93, 0xB7, 0x39, 0xCA, 0x04, 0x66, 0x10, 0x99, 0x79, 0xC6, 0x29, 0x35, 0x34, 0x40, 0xC1, 0x54, + 0x4E, 0xD7, 0x15, 0x26, 0xAB, 0xC2, 0xAA, 0xDE, 0x69, 0x15, 0xC6, 0x52, 0x94, 0x50, 0x54, 0xD7, + 0x92, 0x04, 0x9E, 0x1C, 0x0F, 0xEB, 0xE7, 0x6E, 0x03, 0xA2, 0x87, 0x55, 0xD1, 0x89, 0xD8, 0x20, + 0x32, 0xCD, 0x04, 0x7B, 0xCE, 0x78, 0x41, 0x8A, 0x22, 0xA0, 0x33, 0xD6, 0x7A, 0xEE, 0x1D, 0x7E, + 0x5D, 0xBC, 0xF6, 0x6F, 0x0E, 0x85, 0xD2, 0xFB, 0x88, 0x63, 0x00, 0x53, 0x00, 0x57, 0x96, 0xEE, + 0xB2, 0x5A, 0x72, 0x28, 0xB7, 0x4C, 0x1A, 0x22, 0x9E, 0x3A, 0xCC, 0x34, 0xB4, 0x58, 0xE6, 0x8A, + 0x75, 0xB4, 0xD4, 0x49, 0x1F, 0xB9, 0x5B, 0x8D, 0x8F, 0x35, 0x99, 0xBD, 0xE9, 0x32, 0x0B, 0xFD, + 0xCA, 0x71, 0xD9, 0x59, 0x9B, 0x65, 0x62, 0x10, 0x5C, 0xEE, 0x47, 0x27, 0x0B, 0x56, 0xA9, 0x32, + 0xBE, 0x67, 0x67, 0x8B, 0x54, 0x19, 0xBB, 0xB6, 0x48, 0x14, 0x54, 0xE2, 0x25, 0x89, 0x03, 0x79, + 0x80, 0x55, 0xD9, 0xA8, 0x2A, 0x3D, 0x9E, 0x55, 0x02, 0x20, 0xA2, 0x66, 0x31, 0x85, 0x2F, 0x21, + 0xC0, 0xBA, 0x46, 0x0C, 0x00, 0x3D, 0x94, 0x9E, 0x4A, 0x4E, 0x9F, 0x73, 0x51, 0x98, 0x91, 0x12, + 0x22, 0xA8, 0x63, 0xFF, 0x9A, 0x4A, 0x5E, 0xF7, 0x33, 0xCF, 0xF4, 0x96, 0x76, 0x79, 0x6E, 0xD5, + 0xB6, 0x33, 0x1A, 0xAA, 0x0C, 0x88, 0x41, 0xEC, 0xB1, 0xAE, 0x4D, 0x24, 0x78, 0xFD, 0x8B, 0x77, + 0xE2, 0xBC, 0xF9, 0x4E, 0x49, 0x00, 0x2E, 0x10, 0xCA, 0xBB, 0x17, 0x01, 0x9B, 0x83, 0x49, 0xA2, + 0xBD, 0x51, 0x90, 0x09, 0x68, 0xE2, 0x44, 0xF0, 0xA9, 0xED, 0xE8, 0x5D, 0x78, 0xDD, 0x47, 0x0F, + 0x69, 0x49, 0xE1, 0x2B, 0x46, 0x9C, 0xBD, 0x5A, 0xC8, 0xC4, 0x82, 0x08, 0x07, 0xF9, 0x74, 0x72, + 0x4B, 0x00, 0xE5, 0x3D, 0x1D, 0xF4, 0x9E, 0x93, 0x22, 0x6A, 0xC4, 0x8E, 0x13, 0x80, 0x05, 0x28, + 0xE1, 0x8B, 0xB4, 0x1F, 0x58, 0x64, 0xD9, 0xFA, 0x33, 0x0E, 0x9E, 0xA2, 0x6C, 0x9F, 0x1A, 0x83, + 0xAB, 0xCE, 0xC1, 0x51, 0x3F, 0x29, 0xC0, 0x51, 0x3D, 0xA3, 0x67, 0xB5, 0xFE, 0x49, 0x1A, 0x75, + 0xB0, 0x92, 0xC3, 0x82, 0x7E, 0xDD, 0x18, 0x2F, 0xF6, 0xFF, 0x0C, 0x65, 0x1C, 0x7A, 0xAF, 0xDB, + 0x9E, 0xCD, 0x4E, 0x3F, 0x85, 0x6A, 0x48, 0xE7, 0xDA, 0x50, 0x4B, 0x7D, 0x27, 0x78, 0x69, 0xEA, + 0xE0, 0x88, 0xF8, 0xD2, 0xF0, 0x17, 0x42, 0x50, 0x1B, 0x22, 0x2E, 0x22, 0x87, 0xA7, 0xF0, 0x61, + 0xC0, 0xE6, 0xF9, 0xE2, 0xB4, 0x75, 0xCB, 0x9A, 0x2C, 0xFA, 0x6C, 0x4E, 0x69, 0x3F, 0x2C, 0x59, + 0x1D, 0xAA, 0x57, 0x34, 0xD7, 0x0D, 0x30, 0x30, 0x8B, 0x60, 0xA8, 0x74, 0x81, 0x51, 0xA3, 0x10, + 0xDB, 0x93, 0x74, 0x70, 0xAF, 0xDD, 0x4D, 0x29, 0x2E, 0x8C, 0x59, 0x96, 0xCB, 0x4A, 0x0E, 0x0C, + 0x78, 0x1D, 0x76, 0x6C, 0xE7, 0x14, 0xA9, 0x86, 0x52, 0x7C, 0x01, 0xA3, 0x03, 0x25, 0xA6, 0x63, + 0xFF, 0x64, 0x06, 0xF7, 0x27, 0x88, 0x71, 0x6B, 0x84, 0x30, 0x7E, 0x2F, 0x5E, 0xA2, 0x87, 0x05, + 0xEF, 0xBA, 0x75, 0xAD, 0xB9, 0xEC, 0x4C, 0xFF, 0x62, 0xD0, 0x6A, 0x92, 0xB8, 0x0E, 0x68, 0xA2, + 0xFE, 0xE6, 0x29, 0xCE, 0x15, 0x00, 0xD1, 0xF0, 0xD8, 0x25, 0x19, 0xAB, 0x6E, 0xA0, 0x2B, 0xFE, + 0x97, 0x42, 0x34, 0x92, 0xB7, 0x7B, 0x59, 0x22, 0xDA, 0xAB, 0x4D, 0xAB, 0x60, 0x9F, 0x59, 0x5D, + 0x24, 0xBA, 0xE8, 0xA4, 0xDC, 0xFB, 0xF2, 0x3C, 0xC0, 0x07, 0x7E, 0xC4, 0xFF, 0x4E, 0xA9, 0x53, + 0x1C, 0x79, 0x92, 0x78, 0x78, 0x51, 0xB9, 0xD9, 0x06, 0xC6, 0x18, 0xC5, 0xB7, 0x2A, 0x7B, 0x0E, + 0xA5, 0x59, 0xD8, 0x5D, 0xF2, 0xEF, 0x04, 0x46, 0x7B, 0xAA, 0xFA, 0xAD, 0xC8, 0xB8, 0x82, 0x1E, + 0x77, 0x33, 0xA2, 0xE1, 0xC6, 0xFB, 0x26, 0x6B, 0x11, 0x14, 0x54, 0xD0, 0x89, 0x4F, 0x78, 0xEF, + 0x88, 0x8D, 0xC1, 0xCD, 0x7A, 0x07, 0x96, 0x0F, 0xC8, 0x00, 0x74, 0x86, 0x9E, 0x40, 0x20, 0x58, + 0x8C, 0xFF, 0xA5, 0x34, 0x93, 0x3F, 0x4C, 0x50, 0xC0, 0x87, 0xDD, 0x73, 0x96, 0xE8, 0x1B, 0x64, + 0x09, 0x6C, 0xA0, 0x50, 0xF0, 0x62, 0xBE, 0x2C, 0x81, 0x6A, 0x82, 0xA3, 0xB4, 0x4A, 0x81, 0x5B, + 0x4C, 0x13, 0x7E, 0xCB, 0xD7, 0x23, 0x9D, 0x7D, 0x32, 0x11, 0x86, 0xBA, 0xE7, 0xB9, 0x9E, 0x50, + 0xF5, 0xA4, 0x3C, 0x36, 0xD3, 0xD0, 0x85, 0x66, 0xF0, 0xEA, 0x77, 0x70, 0x67, 0x8A, 0xA1, 0x19, + 0xEC, 0x6A, 0x60, 0xDD, 0x63, 0x5C, 0x4A, 0xC1, 0xDC, 0x0A, 0x35, 0x35, 0x3A, 0x35, 0x11, 0xFB, + 0x5D, 0x0D, 0xDF, 0x6A, 0xDD, 0x8E, 0x81, 0xB0, 0xD0, 0xF0, 0xB2, 0xA4, 0x6A, 0xEC, 0xD8, 0xA5, + 0x29, 0x7D, 0xB4, 0x67, 0x4B, 0xF6, 0xF4, 0xDF, 0xF1, 0xCF, 0xE6, 0x03, 0x8D, 0x90, 0x0D, 0x32, + 0x6A, 0x30, 0x5F, 0x3D, 0xA2, 0x68, 0x56, 0x7F, 0x2D, 0x98, 0x2C, 0x75, 0x84, 0x54, 0xDC, 0xCA, + 0x6D, 0xA4, 0xA9, 0x41, 0x94, 0x55, 0x8C, 0xBB, 0xE6, 0xD0, 0x44, 0x0F, 0xED, 0x86, 0x3C, 0x7C, + 0x91, 0xA4, 0x9D, 0x20, 0x67, 0x5D, 0x01, 0x1D, 0x28, 0x18, 0xC7, 0x63, 0xF0, 0x9E, 0x34, 0x57, + 0x8C, 0x4E, 0xCF, 0x4B, 0x74, 0xFA, 0x76, 0x9C, 0x79, 0x24, 0x1F, 0xD9, 0x78, 0xC9, 0x0C, 0xE7, + 0x28, 0xCC, 0x5F, 0xA6, 0x5D, 0xAB, 0x3F, 0x5F, 0x0E, 0xB1, 0xD7, 0x4E, 0xFB, 0x67, 0x9F, 0x9C, + 0x53, 0x28, 0x40, 0x70, 0x7B, 0x09, 0xE8, 0x97, 0xC2, 0xA7, 0x8C, 0x07, 0x42, 0xA2, 0xBE, 0x78, + 0xBB, 0x0F, 0x10, 0x24, 0x6F, 0x43, 0xCE, 0x52, 0x35, 0xBB, 0x18, 0x2C, 0xE5, 0xD8, 0x42, 0x3E, + 0xF3, 0xA7, 0xC3, 0xFE, 0x99, 0xC6, 0x59, 0x29, 0x74, 0x32, 0x77, 0xAE, 0xB9, 0x2C, 0x1E, 0x5B, + 0x8A, 0xCE, 0x19, 0xE7, 0x8B, 0x26, 0x31, 0x9A, 0x86, 0x45, 0x6A, 0x78, 0x18, 0x46, 0x89, 0x23, + 0x8C, 0xDC, 0x17, 0x29, 0xED, 0x14, 0x90, 0x2C, 0xA8, 0x53, 0xFF, 0x64, 0x53, 0x45, 0x65, 0x23, + 0xAA, 0xDC, 0x4D, 0xD8, 0x39, 0xD9, 0x2D, 0xD1, 0xCF, 0x39, 0x1D, 0x12, 0xD5, 0x30, 0x2B, 0x06, + 0x19, 0xA0, 0x30, 0xB6, 0x32, 0xF7, 0xC2, 0xAF, 0x35, 0xEC, 0xB6, 0x99, 0x5A, 0x61, 0x2A, 0x29, + 0x60, 0x0A, 0x9D, 0x2C, 0xFD, 0x72, 0x9F, 0xAF, 0xE0, 0x29, 0x86, 0xCB, 0x18, 0x70, 0x4D, 0xF9, + 0x91, 0xD1, 0xFD, 0xB4, 0x18, 0xCD, 0xE1, 0xA5, 0x08, 0x6A, 0x7C, 0xEA, 0x1F, 0x0F, 0x53, 0xF1, + 0x34, 0x2D, 0xCA, 0xC5, 0x0F, 0xA8, 0xF8, 0xA5, 0xF9, 0x30, 0xE9, 0xF4, 0x37, 0xB9, 0x3C, 0x61, + 0x7F, 0xB8, 0x7B, 0x26, 0x4B, 0x20, 0x89, 0xAF, 0x9B, 0x90, 0x59, 0x9E, 0x82, 0xE2, 0x45, 0x02, + 0x37, 0xC4, 0x9A, 0x9F, 0xE4, 0x11, 0x1F, 0x8C, 0x41, 0xFA, 0xE6, 0xAF, 0x2C, 0xE3, 0x8E, 0xEF, + 0x04, 0x30, 0x02, 0x90, 0x98, 0x13, 0x1D, 0x5F, 0x24, 0xDD, 0x4D, 0x9C, 0x2C, 0x0B, 0x45, 0x6A, + 0xA1, 0xA6, 0x84, 0x6F, 0x70, 0xFD, 0x44, 0x09, 0xE9, 0x3D, 0x99, 0xBB, 0xE3, 0xE3, 0x24, 0x56, + 0x23, 0xE8, 0x34, 0xCC, 0x52, 0x26, 0x8A, 0xA9, 0x84, 0xCF, 0x94, 0x55, 0x21, 0x6B, 0xAE, 0x88, + 0x56, 0xFF, 0xB8, 0x38, 0x62, 0x30, 0xD3, 0x78, 0xF8, 0x90, 0x0A, 0x94, 0x10, 0x22, 0x76, 0xAE, + 0x35, 0x15, 0x5F, 0xC9, 0x33, 0x29, 0x1D, 0x6F, 0x84, 0x43, 0xC6, 0x58, 0x20, 0x36, 0x3E, 0x58, + 0x2B, 0x6B, 0xBC, 0x2F, 0x35, 0x60, 0xDA, 0x09, 0xB0, 0x86, 0x3E, 0x2F, 0x38, 0x2F, 0x24, 0x6C, + 0x1B, 0x8F, 0x88, 0xF3, 0x8F, 0xE0, 0x89, 0xC0, 0x67, 0x7C, 0x15, 0x80, 0x35, 0xA1, 0x96, 0x09, + 0x43, 0x4B, 0x2A, 0x3A, 0x1F, 0x6B, 0xCA, 0x0D, 0x68, 0x6B, 0x00, 0x66, 0xD1, 0xFB, 0x5E, 0xC5, + 0x61, 0xE5, 0xFE, 0xCD, 0xCB, 0xFE, 0x20, 0x9E, 0x6D, 0x0D, 0x3F, 0x22, 0xA8, 0xBD, 0xB6, 0x89, + 0x72, 0x93, 0x07, 0x55, 0x09, 0x83, 0x7B, 0x89, 0x56, 0x0E, 0x3E, 0x74, 0x3A, 0xD1, 0x46, 0x88, + 0x52, 0x63, 0x85, 0xAD, 0xC7, 0x66, 0x49, 0xF0, 0xA8, 0x21, 0x05, 0xB5, 0xA2, 0xC5, 0x7A, 0x42, + 0xAB, 0xBD, 0x18, 0x63, 0x81, 0x11, 0xEA, 0xE7, 0x76, 0x90, 0x7A, 0xE2, 0x41, 0x37, 0xC8, 0x20, + 0xFD, 0x85, 0x24, 0x58, 0x1C, 0x17, 0xB6, 0xC1, 0x3D, 0x11, 0x5C, 0x2B, 0xE2, 0xC9, 0xCE, 0x7D, + 0x83, 0x4D, 0xD8, 0x1F, 0xF5, 0xB5, 0x4D, 0x9D, 0x28, 0x1B, 0x35, 0xD4, 0x92, 0x08, 0x0E, 0xCE, + 0x95, 0x7A, 0x5E, 0x74, 0xB0, 0x91, 0xDD, 0x63, 0x87, 0xC5, 0xC6, 0x01, 0x54, 0x68, 0x92, 0x00, + 0x7A, 0x03, 0xC8, 0x20, 0xFC, 0x5F, 0xA4, 0xCA, 0x78, 0x6F, 0xBC, 0x8E, 0xF2, 0x64, 0x17, 0xA2, + 0xFC, 0x3A, 0x68, 0x04, 0xA2, 0x28, 0x9F, 0x35, 0x72, 0xF3, 0x0C, 0xAD, 0x19, 0x74, 0xC6, 0xD1, + 0x25, 0x60, 0xEA, 0xF6, 0x89, 0x0C, 0x62, 0x7F, 0x4D, 0xC0, 0x78, 0x69, 0x0D, 0xB7, 0x8E, 0x08, + 0x6D, 0xF8, 0x38, 0xC6, 0xB6, 0x12, 0x36, 0x25, 0x96, 0xE7, 0x65, 0xCD, 0xE7, 0xB6, 0x63, 0x36, + 0x9D, 0x7D, 0x64, 0x92, 0x1F, 0xDB, 0x69, 0xA7, 0x75, 0x12, 0x41, 0xBA, 0xE6, 0xDD, 0xF9, 0x1C, + 0xFA, 0xF8, 0x8C, 0x0E, 0x8F, 0x86, 0x1E, 0xDA, 0x54, 0x4F, 0xC4, 0x75, 0x12, 0x66, 0x64, 0xC0, + 0x04, 0x7F, 0xB8, 0x9C, 0x20, 0x46, 0x8A, 0x20, 0x03, 0xC8, 0xBC, 0x1F, 0xD6, 0x3E, 0xD6, 0xC1, + 0x3E, 0xD3, 0x5B, 0x84, 0x0B, 0x8F, 0x50, 0x2B, 0x98, 0x7A, 0xD7, 0x5F, 0xD3, 0x76, 0x94, 0x0D, + 0x53, 0x2D, 0x86, 0xD3, 0x5C, 0x61, 0x0E, 0x97, 0x7C, 0x69, 0x60, 0xB6, 0x73, 0xC1, 0x84, 0xA3, + 0x8E, 0xFA, 0x9F, 0x2B, 0x2B, 0x38, 0xFF, 0x97, 0xE2, 0xC3, 0xA4, 0x4E, 0x72, 0x20, 0xE6, 0x49, + 0x02, 0x7B, 0xCC, 0x2C, 0x91, 0xED, 0x9C, 0xAC, 0x28, 0x1A, 0x30, 0x31, 0xDB, 0x79, 0xFC, 0x14, + 0xCC, 0x2A, 0x67, 0x9B, 0x97, 0x70, 0xAC, 0x25, 0xCD, 0xD2, 0x5E, 0xEA, 0x73, 0x13, 0xDB, 0xAB, + 0x44, 0x48, 0xAF, 0x35, 0x57, 0xCE, 0x2B, 0xF0, 0x7A, 0xCC, 0xC5, 0xC1, 0xD7, 0xC9, 0x63, 0x15, + 0x59, 0xF0, 0x6D, 0x73, 0x08, 0x74, 0x27, 0x4E, 0x81, 0x23, 0x3D, 0xE6, 0xFA, 0xC9, 0xDC, 0x10, + 0x99, 0x94, 0xFA, 0x55, 0x3F, 0xD3, 0x72, 0x6F, 0xDF, 0x59, 0xF9, 0x41, 0x89, 0x2D, 0x1C, 0x92, + 0x9E, 0xA3, 0xE6, 0x4B, 0xCD, 0x44, 0x93, 0x85, 0xCB, 0xB4, 0x55, 0x52, 0x13, 0x62, 0xFF, 0xC4, + 0x38, 0x93, 0xA3, 0x79, 0x51, 0xDB, 0xC6, 0xF8, 0x86, 0x90, 0x6C, 0x9C, 0x32, 0x18, 0x02, 0x17, + 0x17, 0x41, 0xF8, 0x42, 0x46, 0x5B, 0x36, 0xFB, 0x7A, 0x2B, 0xCC, 0xCE, 0x43, 0x03, 0xE8, 0x7D, + 0x7C, 0x67, 0xA0, 0x2E, 0xF4, 0xC3, 0x72, 0xAD, 0x13, 0xEE, 0x61, 0xFD, 0x50, 0xD6, 0xBF, 0xA2, + 0xDC, 0xD5, 0x56, 0xB3, 0xAD, 0xA1, 0x3A, 0xC7, 0xCC, 0x75, 0x76, 0xDE, 0x21, 0x7C, 0x88, 0xE5, + 0x86, 0x95, 0x07, 0xB6, 0xE6, 0xEF, 0x04, 0x07, 0x5D, 0xBE, 0x00, 0xFE, 0xC8, 0x4A, 0xC0, 0xD4, + 0x5D, 0x8F, 0xA2, 0x55, 0xD0, 0xDB, 0x67, 0xAD, 0x04, 0x45, 0x2F, 0xBD, 0xA8, 0xCB, 0x79, 0x06, + 0x6A, 0xEE, 0x6C, 0xF4, 0xCF, 0x7F, 0x2F, 0xF4, 0x19, 0x15, 0xD8, 0x0F, 0xC8, 0x55, 0x64, 0x1D, + 0x32, 0x67, 0x4E, 0xAF, 0xE4, 0x92, 0xE8, 0x00, 0xF7, 0x7C, 0x68, 0x8A, 0x3E, 0x9B, 0x52, 0xB1, + 0xD7, 0xAC, 0x74, 0x04, 0xAD, 0x82, 0x4B, 0x67, 0xE9, 0x12, 0x69, 0xAC, 0x74, 0xC6, 0xB6, 0x8A, + 0x59, 0x30, 0x11, 0x2C, 0x60, 0xE4, 0x93, 0x91, 0xEB, 0xE6, 0x82, 0x9C, 0xA3, 0x24, 0xFE, 0x00, + 0x9E, 0xED, 0x31, 0x7C, 0xAF, 0xA8, 0x1B, 0x0C, 0x3F, 0xDC, 0x75, 0xB0, 0xF9, 0x3B, 0x1A, 0x02, + 0x45, 0x2B, 0x27, 0xB2, 0x67, 0x10, 0xBD, 0xE2, 0x47, 0x70, 0xB7, 0xA7, 0x29, 0x55, 0x07, 0x88, + 0x9C, 0x00, 0x72, 0x44, 0x06, 0x1F, 0x90, 0xBC, 0x8C, 0xA6, 0x1F, 0x33, 0xD6, 0xA6, 0xA3, 0xF1, + 0xF1, 0x65, 0xA5, 0x97, 0x9B, 0x30, 0x19, 0xFD, 0x0E, 0x74, 0x0F, 0xC2, 0x47, 0x66, 0x31, 0x17, + 0xB1, 0xED, 0x38, 0x46, 0x86, 0xC9, 0x9A, 0x1A, 0x5E, 0x17, 0xEC, 0xD4, 0xE9, 0x28, 0xB4, 0xA6, + 0xCB, 0x88, 0xCF, 0x06, 0xDB, 0xAE, 0x2A, 0x88, 0x8C, 0xBE, 0x17, 0x89, 0x8E, 0xD5, 0xAC, 0x0D, + 0x11, 0xBC, 0xB8, 0x4E, 0xFD, 0x5E, 0x27, 0xAC, 0xC9, 0xE9, 0x52, 0xCD, 0xA8, 0xA7, 0xC9, 0x13, + 0xC9, 0x08, 0xAE, 0xF4, 0x0E, 0x94, 0xEF, 0xBD, 0xB7, 0xF8, 0xCA, 0x90, 0xE5, 0x20, 0xE1, 0x79, + 0x80, 0x29, 0x06, 0xC7, 0x03, 0x3E, 0x35, 0xE9, 0xA9, 0x9A, 0x04, 0xF4, 0xF1, 0x0D, 0x09, 0x83, + 0x41, 0x9A, 0xEE, 0x77, 0x75, 0x69, 0x8C, 0x89, 0xD4, 0xB5, 0xD8, 0xAE, 0x37, 0x05, 0x0C, 0x29, + 0x62, 0x1F, 0x91, 0xFC, 0xF3, 0xED, 0xEA, 0x3A, 0x42, 0x34, 0xA5, 0x19, 0x1C, 0x7D, 0x12, 0x38, + 0x08, 0xD2, 0x44, 0x18, 0xD7, 0x7D, 0xBF, 0x82, 0xB4, 0x5F, 0x5F, 0x1A, 0x4B, 0x04, 0x34, 0x67, + 0x5C, 0xC9, 0xBC, 0x94, 0x8C, 0x85, 0xCA, 0xE6, 0x2F, 0x1F, 0x0E, 0xDE, 0x92, 0x44, 0x80, 0xF3, + 0xFE, 0x0F, 0x46, 0x2F, 0x3C, 0x17, 0x2D, 0x2D, 0xC6, 0x02, 0x88, 0x51, 0x94, 0xF6, 0x5F, 0xBD, + 0xDA, 0xC1, 0x7A, 0x77, 0x50, 0xD9, 0x43, 0xC8, 0x78, 0x8C, 0x93, 0x41, 0x36, 0xDA, 0x62, 0x9C, + 0xE6, 0xB9, 0x06, 0x82, 0xF9, 0xEE, 0xBC, 0x8A, 0x13, 0x95, 0x35, 0x1E, 0xD3, 0x86, 0xA9, 0x17, + 0xC8, 0x7D, 0xDB, 0x07, 0x77, 0x7B, 0xA3, 0xA3, 0x43, 0xF4, 0x5F, 0x20, 0x2C, 0xCB, 0xB5, 0xE0, + 0x00, 0x9D, 0x8A, 0xF0, 0x05, 0x61, 0xE2, 0x96, 0xFE, 0x11, 0x17, 0xF8, 0xAB, 0xE0, 0x04, 0x35, + 0xB1, 0xEC, 0x78, 0x93, 0x21, 0x30, 0x7A, 0xCA, 0x6D, 0xAF, 0x29, 0xDC, 0xF4, 0xD3, 0x3A, 0x2A, + 0xA4, 0x64, 0xEA, 0x09, 0xEE, 0xA8, 0x63, 0x57, 0x85, 0x0A, 0x39, 0x3A, 0x4B, 0xEB, 0x18, 0x17, + 0x06, 0x09, 0xB3, 0x38, 0x9D, 0x4A, 0x54, 0x9D, 0x04, 0x2C, 0xBF, 0xA6, 0x8A, 0x48, 0x22, 0xBD, + 0xC7, 0xA2, 0x70, 0xAD, 0x7C, 0x33, 0x34, 0xB5, 0xBB, 0x8A, 0x0E, 0x4C, 0xC8, 0xF6, 0xA3, 0xE6, + 0xEB, 0xFA, 0x84, 0xAF, 0x94, 0x57, 0x4E, 0xD7, 0xCE, 0x49, 0xBD, 0xBD, 0x96, 0x53, 0x3A, 0xAE, + 0xD5, 0xBF, 0xB5, 0xA1, 0x90, 0x37, 0xA3, 0x11, 0x87, 0x0A, 0x9B, 0x0D, 0x62, 0xC1, 0x40, 0x66, + 0x7D, 0x51, 0xFB, 0xB3, 0x54, 0x74, 0xCA, 0x0D, 0x98, 0xB1, 0x11, 0x15, 0x5F, 0x49, 0xA0, 0x92, + 0xD7, 0xBF, 0xBA, 0x1A, 0x5D, 0x08, 0x8B, 0xE7, 0xC2, 0x5F, 0x6C, 0xB4, 0x6E, 0x6C, 0xBB, 0xF9, + 0x12, 0xF4, 0x42, 0xE1, 0x0A, 0xE3, 0x09, 0x9B, 0x5D, 0xD8, 0x97, 0x39, 0x93, 0x4F, 0x5E, 0xBE, + 0x68, 0xED, 0xCD, 0xFB, 0x8E, 0xD2, 0x8E, 0x91, 0x0A, 0x74, 0xA3, 0x61, 0x03, 0x4E, 0x56, 0x21, + 0x63, 0x79, 0x89, 0x64, 0x52, 0xE1, 0x81, 0xE3, 0x6F, 0x45, 0x24, 0x25, 0x6F, 0x35, 0xFF, 0x36, + 0xCC, 0xE9, 0x1F, 0xA3, 0x4F, 0x8E, 0x29, 0x6E, 0x5E, 0x9B, 0x0E, 0xC7, 0xAC, 0x15, 0x02, 0x43, + 0xE1, 0x15, 0x9F, 0xB9, 0xA1, 0x6A, 0xDD, 0x81, 0xBC, 0xA6, 0x65, 0xD4, 0x1E, 0x6A, 0x1B, 0x6F, + 0x9B, 0x89, 0x6B, 0x45, 0x90, 0x29, 0xA2, 0x33, 0x21, 0xC7, 0x5E, 0xF0, 0xBC, 0x03, 0x63, 0x9C, + 0x23, 0xF6, 0x2E, 0xC1, 0x28, 0xFB, 0x5F, 0x93, 0x20, 0x24, 0xC4, 0xBA, 0xAB, 0x08, 0x11, 0x93, + 0x69, 0xAA, 0x26, 0xD6, 0xE0, 0x77, 0xB4, 0x9F, 0x4C, 0x85, 0xE9, 0x7F, 0x7C, 0x9A, 0x8D, 0x01, + 0xB5, 0x7C, 0xFF, 0x82, 0x06, 0xA8, 0x7E, 0x19, 0xB1, 0x2B, 0xEA, 0x2D, 0x54, 0xBB, 0x85, 0x19, + 0x78, 0x7C, 0xC0, 0xAD, 0x5C, 0x24, 0x25, 0x4F, 0x4F, 0xA4, 0x7A, 0xC2, 0xAF, 0x0F, 0xC9, 0x8A, + 0xA2, 0xF1, 0xF0, 0x7F, 0xC2, 0x84, 0xE5, 0x1C, 0x67, 0x22, 0xE8, 0x0E, 0x30, 0x9E, 0xCB, 0x07, + 0x22, 0x34, 0x9D, 0x66, 0xB8, 0x58, 0x4E, 0xEB, 0xA8, 0x09, 0x84, 0x87, 0x7E, 0xF4, 0xFC, 0x38, + 0x44, 0xA1, 0x8E, 0xC3, 0x33, 0x35, 0x7A, 0xBE, 0x12, 0xCF, 0x7E, 0xD2, 0x2F, 0xD9, 0xDA, 0x03, + 0xF3, 0x80, 0xE1, 0x59, 0xD2, 0xD8, 0xB8, 0x3F, 0xE9, 0x5C, 0xE1, 0xAB, 0xE6, 0x86, 0x5E, 0x3C, + 0x12, 0xC4, 0xE6, 0x8C, 0xCC, 0x94, 0x6A, 0x0C, 0xB8, 0xE5, 0x4C, 0x72, 0x11, 0x8F, 0x08, 0xFD, + 0x97, 0x2D, 0x84, 0xE4, 0x7D, 0x8B, 0xF1, 0xBD, 0xFF, 0x09, 0x73, 0x86, 0x3B, 0x8E, 0x4D, 0x28, + 0x90, 0x18, 0x22, 0xE8, 0x3A, 0x22, 0x5F, 0x96, 0x8A, 0x3D, 0xEC, 0xCE, 0x8B, 0x9F, 0x3D, 0xAD, + 0x8E, 0x13, 0xA6, 0x87, 0x05, 0xEB, 0xA0, 0x6B, 0x8F, 0x82, 0xBA, 0xBF, 0x63, 0xEE, 0x5C, 0x30, + 0x30, 0x97, 0xFD, 0x91, 0xA0, 0xBA, 0xD7, 0x7E, 0x9D, 0xDC, 0x22, 0x13, 0x87, 0x22, 0xEB, 0xEC, + 0x3A, 0x86, 0xEB, 0xA6, 0x14, 0x30, 0x5A, 0xC7, 0x91, 0x5A, 0xCE, 0x0A, 0x5B, 0x67, 0x0E, 0x24, + 0x56, 0x59, 0x18, 0x93, 0x5D, 0x88, 0xCB, 0xB6, 0x0C, 0xDA, 0x3D, 0xF2, 0x14, 0xF0, 0xDF, 0xF4, + 0x5D, 0x93, 0x60, 0x30, 0x35, 0x9C, 0xF3, 0x0D, 0xB9, 0xEE, 0xB1, 0x1D, 0x29, 0x5D, 0x1A, 0x64, + 0xAF, 0xD3, 0x1E, 0x97, 0x22, 0x05, 0x42, 0xF5, 0xFC, 0x24, 0xED, 0xF1, 0xFC, 0x0E, 0xED, 0x25, + 0xD9, 0x55, 0x3E, 0xC6, 0xB7, 0x95, 0x73, 0xD6, 0x18, 0x0F, 0x02, 0x97, 0x58, 0x3D, 0x0D, 0x63, + 0x0B, 0xA4, 0xCD, 0x4E, 0x03, 0x66, 0xF7, 0xF8, 0x3D, 0x91, 0x0B, 0x45, 0x03, 0xF0, 0x13, 0x68, + 0x72, 0x4B, 0xFD, 0xDA, 0xEF, 0xAE, 0x57, 0x59, 0x88, 0xDE, 0x98, 0x76, 0x11, 0x01, 0x27, 0x08, + 0xCF, 0xD8, 0xAB, 0xA2, 0x91, 0xA3, 0x61, 0xB4, 0xD3, 0x62, 0xA4, 0xCD, 0xDE, 0x10, 0x98, 0x33, + 0x6E, 0x40, 0xFB, 0xF1, 0xA9, 0xDA, 0x44, 0x17, 0xE7, 0xC5, 0x98, 0x60, 0x37, 0x6D, 0x08, 0x21, + 0x5C, 0xE6, 0x38, 0xEA, 0xFB, 0xA7, 0x04, 0x1F, 0x6B, 0x84, 0x93, 0xDF, 0x31, 0xB6, 0x3C, 0x21, + 0x39, 0xED, 0xC8, 0x9B, 0x99, 0x5B, 0xAB, 0x5E, 0x0E, 0x6C, 0x93, 0x9B, 0x47, 0xB4, 0xAF, 0x8A, + 0x10, 0x51, 0x64, 0xEE, 0x08, 0xC0, 0xEB, 0x6B, 0xE4, 0x98, 0x11, 0x13, 0x32, 0x87, 0x86, 0x4D, + 0x02, 0xFA, 0x0D, 0x55, 0xA1, 0x8D, 0x79, 0xF8, 0xC9, 0xB9, 0x02, 0xC7, 0x03, 0xA6, 0x3D, 0x82, + 0x90, 0xC2, 0xEB, 0x90, 0xF4, 0xF8, 0x69, 0xA2, 0x4F, 0x2B, 0xE4, 0x1E, 0x08, 0x8E, 0x66, 0x40, + 0x24, 0x6E, 0x99, 0xD7, 0x11, 0x1E, 0xD5, 0xE3, 0xE6, 0xA1, 0x32, 0xBD, 0x51, 0xDB, 0x45, 0xAB, + 0xFF, 0xC5, 0xD4, 0xE3, 0x3F, 0x84, 0x1F, 0x9B, 0x78, 0x98, 0x12, 0x8C, 0xD8, 0x4C, 0xD7, 0x63, + 0xC9, 0x56, 0xE8, 0x72, 0x8E, 0xA0, 0xC6, 0x47, 0x1D, 0x5C, 0x9A, 0xC1, 0x15, 0x93, 0x53, 0xA2, + 0x6A, 0xE1, 0x34, 0x2F, 0x2A, 0xE1, 0x16, 0xB1, 0x49, 0x7A, 0x5C, 0xE8, 0x5F, 0x2F, 0xC0, 0x08, + 0x8E, 0x08, 0x57, 0x6F, 0xB7, 0x8D, 0x03, 0xED, 0x88, 0x87, 0x47, 0x4F, 0x4D, 0xB0, 0xC9, 0x54, + 0x6D, 0xA1, 0x72, 0xE4, 0xBF, 0x2C, 0x8E, 0x7B, 0x63, 0xDE, 0xF5, 0xAC, 0x73, 0xF4, 0x9B, 0x6A, + 0x52, 0xAF, 0x08, 0xBF, 0x33, 0xE6, 0x8C, 0xBB, 0xF0, 0xBB, 0x98, 0x0A, 0xB8, 0x6E, 0xCA, 0xEF, + 0x55, 0xF9, 0xCA, 0x60, 0xEC, 0x6A, 0xFB, 0x72, 0x76, 0xA5, 0xE3, 0xF0, 0xB3, 0x02, 0x8B, 0x97, + 0x1D, 0x9A, 0x3F, 0x4B, 0x86, 0xE2, 0x79, 0x0D, 0xD2, 0x2F, 0x92, 0x67, 0x88, 0x7E, 0xBA, 0x6F, + 0xC5, 0x86, 0x8B, 0x27, 0x12, 0x88, 0x80, 0x11, 0xF4, 0x1B, 0xBC, 0xE4, 0x1B, 0xCD, 0x97, 0x99, + 0xFB, 0x9B, 0x42, 0x76, 0x95, 0x52, 0x5A, 0xBE, 0xEE, 0x9C, 0x3D, 0xDF, 0xB0, 0xDA, 0xA7, 0x92, + 0xBF, 0xB6, 0x68, 0x5F, 0xC0, 0x27, 0x8C, 0x91, 0xBB, 0x33, 0x3C, 0x49, 0xD7, 0x58, 0x04, 0x12, + 0x83, 0x5F, 0xBC, 0x50, 0x30, 0x22, 0xA3, 0xA1, 0x3A, 0x30, 0x9A, 0x7F, 0xA7, 0xD5, 0xD7, 0x24, + 0x32, 0x29, 0xD0, 0x0F, 0x3F, 0xF2, 0x27, 0x15, 0xBF, 0x12, 0x02, 0x7E, 0xCA, 0xC7, 0x98, 0x9D, + 0xD8, 0xC5, 0x55, 0xB2, 0x65, 0x03, 0xF0, 0x8D, 0x41, 0x07, 0xFC, 0xB0, 0x56, 0x3E, 0x70, 0x85, + 0xEC, 0x78, 0x9A, 0x38, 0xA6, 0xAC, 0x87, 0x7E, 0x52, 0x56, 0x92, 0x9D, 0x2D, 0x3E, 0x68, 0x4A, + 0x47, 0xA7, 0x77, 0x0F, 0x52, 0x3C, 0xF6, 0x0F, 0xEF, 0x80, 0xC9, 0xFB, 0x9A, 0x29, 0x4C, 0x5F, + 0x1E, 0xB8, 0xBB, 0x66, 0xCE, 0xD0, 0xAF, 0xBD, 0xAB, 0x36, 0xD4, 0xAA, 0xD7, 0xAA, 0xCB, 0x1A, + 0xEB, 0xEB, 0x77, 0xE3, 0xF6, 0x4E, 0xE1, 0xD3, 0xCD, 0x8B, 0xF7, 0xA8, 0x32, 0x9D, 0x85, 0xE9, + 0xED, 0x8A, 0x34, 0x35, 0x95, 0x9A, 0x85, 0xD0, 0x9B, 0x42, 0xD1, 0xBE, 0xCE, 0x9B, 0x14, 0x3E, + 0x9C, 0x14, 0xEF, 0xE6, 0x8C, 0x52, 0x43, 0x1C, 0x2D, 0x32, 0x41, 0xBA, 0x1E, 0x75, 0x04, 0xE6, + 0x15, 0xA6, 0xA1, 0xEB, 0x84, 0x82, 0x88, 0x30, 0x26, 0xE2, 0x37, 0x2F, 0xC4, 0xE6, 0x00, 0x02, + 0x13, 0x60, 0xDF, 0x53, 0xDF, 0x59, 0x46, 0x80, 0x23, 0xA7, 0x68, 0xE1, 0xC3, 0x0F, 0x89, 0x73, + 0xF2, 0xE5, 0x7E, 0x83, 0x39, 0x90, 0x87, 0x06, 0xAA, 0x2E, 0x75, 0x5E, 0xDD, 0xC5, 0xC7, 0x20, + 0x7B, 0x4F, 0x8A, 0x12, 0xAF, 0xD1, 0xDF, 0x6B, 0xE8, 0x23, 0x2F, 0x49, 0x8F, 0x72, 0xF6, 0xE3, + 0xB7, 0xCD, 0x3C, 0xA5, 0x2A, 0x2B, 0xFE, 0x48, 0x5C, 0x88, 0x3A, 0xB7, 0x3D, 0xA2, 0x83, 0xCD, + 0xAD, 0xEB, 0x23, 0x57, 0x5C, 0xAE, 0xEE, 0x3A, 0x33, 0x3B, 0xAD, 0xBB, 0x4C, 0x95, 0xF3, 0x9A, + 0x83, 0x7C, 0x30, 0xDF, 0xF3, 0x0E, 0xC5, 0x5F, 0x5B, 0xCB, 0x86, 0x83, 0x5B, 0x0A, 0xD3, 0x95, + 0x4B, 0xE2, 0x8D, 0x72, 0x58, 0xE1, 0xFD, 0x7D, 0xBB, 0x44, 0x31, 0xA0, 0x93, 0x9A, 0xF5, 0xDD, + 0xC8, 0xAD, 0xE4, 0xFE, 0x3A, 0x8C, 0x4F, 0x9A, 0x70, 0x29, 0x7B, 0xC9, 0x2C, 0x9D, 0x7A, 0x94, + 0x91, 0x8C, 0x8C, 0x9A, 0x8D, 0x70, 0xE2, 0x11, 0xEB, 0x8D, 0xD3, 0xE5, 0xD6, 0x67, 0x95, 0xD9, + 0x88, 0x59, 0x19, 0x29, 0x14, 0xE6, 0x7B, 0xF6, 0x3F, 0x67, 0x29, 0xDC, 0x6D, 0xBD, 0xA4, 0xE4, + 0xCD, 0x5E, 0x35, 0x25, 0x13, 0x5D, 0x3C, 0x3E, 0x9C, 0xE3, 0x5F, 0xF2, 0x78, 0x29, 0xE0, 0xD6, + 0xEC, 0x8F, 0x9E, 0xAC, 0x75, 0xDC, 0xFD, 0x89, 0x53, 0xE7, 0x62, 0x6B, 0x38, 0x0D, 0x8B, 0x79, + 0xB7, 0x05, 0x45, 0xF5, 0x72, 0x9E, 0xE5, 0x3C, 0xFB, 0xB4, 0xD3, 0x9F, 0x62, 0x38, 0x3A, 0x80, + 0xDA, 0x59, 0x53, 0x3B, 0xBB, 0x55, 0x4B, 0xD0, 0xE1, 0x63, 0xF4, 0xBC, 0x99, 0xD3, 0x63, 0x5A, + 0xCC, 0x0D, 0x2D, 0x09, 0x80, 0x46, 0x62, 0xEE, 0xE4, 0x50, 0xF2, 0x5B, 0xBB, 0x96, 0xC6, 0x1D, + 0x05, 0xE6, 0x5C, 0x68, 0x7E, 0xCC, 0xBD, 0x96, 0x0B, 0x8E, 0xDC, 0x45, 0x62, 0x9C, 0x48, 0x24, + 0x9B, 0x72, 0x47, 0x2F, 0xB3, 0x14, 0xCF, 0xB8, 0x1A, 0x93, 0x73, 0x83, 0x11, 0x7C, 0x27, 0xC4, + 0x99, 0x4B, 0x4F, 0x5E, 0x32, 0x86, 0x85, 0xFD, 0x5C, 0x36, 0xA6, 0xC6, 0x02, 0x47, 0x3E, 0xF0, + 0x66, 0xDF, 0x9C, 0x88, 0x72, 0x0D, 0xA7, 0xB7, 0xAA, 0x14, 0x91, 0x86, 0xAF, 0x08, 0x2D, 0xC8, + 0x6A, 0x08, 0x12, 0x40, 0x3E, 0xBB, 0x5B, 0x1A, 0xC3, 0x2F, 0x97, 0x44, 0xAD, 0xD6, 0x70, 0xCA, + 0x23, 0x15, 0x3D, 0xF8, 0x81, 0xDD, 0xE6, 0x1B, 0xFC, 0x24, 0x42, 0x70, 0xBC, 0x47, 0xAB, 0xA1, + 0xCA, 0x6F, 0x27, 0x18, 0x4D, 0x82, 0xBA, 0x34, 0x31, 0x44, 0xA1, 0x84, 0x8D, 0x70, 0x1A, 0xC5, + 0x02, 0xA5, 0xED, 0x67, 0xC7, 0x18, 0xFA, 0xD2, 0xF3, 0x0F, 0x7A, 0x12, 0x40, 0x77, 0xA5, 0x0E, + 0x03, 0xF0, 0xC8, 0xEA, 0xE9, 0x36, 0xDF, 0xCB, 0xDA, 0xA6, 0x25, 0x73, 0xD2, 0x7B, 0x57, 0xB4, + 0x40, 0xAD, 0x90, 0x35, 0x27, 0x2C, 0x99, 0xE2, 0x34, 0x50, 0x12, 0xF9, 0xF4, 0xBE, 0xF2, 0x86, + 0x4E, 0xAD, 0xFA, 0x83, 0x92, 0x33, 0x48, 0x4F, 0x1E, 0xB4, 0xB2, 0x0D, 0x88, 0xCF, 0x0B, 0xDF, + 0x03, 0x48, 0x2C, 0xA8, 0x9D, 0x60, 0xFC, 0x44, 0x24, 0x9B, 0xF8, 0x86, 0xE2, 0x23, 0xFE, 0xC7, + 0xF7, 0x9C, 0xA1, 0xE0, 0x97, 0x8E, 0x23, 0x8D, 0x60, 0x0D, 0xAF, 0xB2, 0xF1, 0x6D, 0xC4, 0xE4, + 0x48, 0xF6, 0xC0, 0xC0, 0xF2, 0xDA, 0x1E, 0x15, 0x27, 0x99, 0x78, 0x9F, 0xCC, 0x8D, 0xF9, 0xC1, + 0x2F, 0xF6, 0x7B, 0x45, 0x65, 0xD2, 0x4F, 0x78, 0x4E, 0xB2, 0x39, 0x3D, 0xC9, 0xA3, 0x20, 0x2A, + 0xC8, 0xC6, 0x67, 0x2B, 0xA0, 0x2C, 0x4A, 0x75, 0x03, 0xEA, 0xD7, 0xB1, 0xD4, 0x57, 0x07, 0x11, + 0x4A, 0xB0, 0xF8, 0x86, 0xCE, 0x4F, 0xF1, 0xD0, 0x19, 0x62, 0xE3, 0xD7, 0xE3, 0x59, 0xDD, 0x38, + 0xD6, 0x12, 0xCE, 0xE4, 0x7A, 0x18, 0xEB, 0x5C, 0x3E, 0xFF, 0xDB, 0xF6, 0xBC, 0x9C, 0x18, 0xF3, + 0x1A, 0xF8, 0xC4, 0x69, 0xC0, 0x0D, 0x75, 0x38, 0xA9, 0x6D, 0xFC, 0xA5, 0x10, 0x71, 0x0B, 0xB3, + 0xA4, 0xCC, 0xDF, 0x32, 0x12, 0x94, 0x4B, 0x17, 0xDE, 0x79, 0xA0, 0x4A, 0x23, 0x3C, 0x02, 0xCA, + 0xBD, 0x13, 0x23, 0xDD, 0x44, 0x60, 0x15, 0x51, 0x2F, 0xC5, 0xFE, 0x61, 0x93, 0xCB, 0xDE, 0x2A, + 0x4A, 0xF0, 0xF7, 0xC9, 0x83, 0x91, 0xB4, 0xCD, 0x27, 0x42, 0x43, 0x85, 0x03, 0x49, 0x2F, 0x08, + 0x93, 0x50, 0x1F, 0x19, 0x82, 0x0D, 0x7A, 0xF6, 0x3A, 0xB9, 0xCF, 0xC1, 0x7B, 0x5B, 0x73, 0xAC, + 0x8E, 0x03, 0x8B, 0x99, 0x8C, 0x68, 0x85, 0xD7, 0xAE, 0x2D, 0x1B, 0xF3, 0x1B, 0xBA, 0x2F, 0x37, + 0x42, 0x4D, 0x3D, 0x91, 0xB4, 0x77, 0x4A, 0x78, 0xB9, 0xB4, 0x0E, 0x08, 0x62, 0x9C, 0x8E, 0x6C, + 0xB6, 0x97, 0x7D, 0x40, 0x9F, 0x97, 0xE2, 0x49, 0x26, 0x7F, 0xD5, 0xDB, 0x98, 0xB5, 0x77, 0x35, + 0x4A, 0x18, 0x1E, 0x3E, 0xC5, 0xCE, 0x55, 0x87, 0xC9, 0x34, 0xE2, 0x4E, 0x05, 0x3E, 0xE1, 0x9D, + 0x4F, 0x0A, 0x02, 0x46, 0xC6, 0x11, 0x00, 0x66, 0x45, 0x32, 0xB0, 0x21, 0xB2, 0xCD, 0xC6, 0xA7, + 0x35, 0xF5, 0xFC, 0xA2, 0x58, 0xD3, 0x22, 0x03, 0xE4, 0x25, 0xE3, 0x52, 0x7C, 0x1D, 0xC8, 0xF8, + 0x83, 0xB8, 0xC8, 0xBE, 0x6A, 0xAD, 0xFA, 0x5E, 0x54, 0x21, 0x18, 0xF8, 0x8F, 0x6A, 0x8D, 0x39, + 0xA4, 0x31, 0x67, 0x0D, 0xF5, 0xB3, 0xE8, 0xCC, 0x80, 0xDC, 0xD6, 0xAA, 0xB5, 0x85, 0x13, 0x01, + 0x5F, 0x25, 0x83, 0xA1, 0xFC, 0x96, 0xF8, 0x17, 0xB7, 0x80, 0x0E, 0x36, 0x80, 0xF1, 0x48, 0xA4, + 0x50, 0x76, 0x96, 0x77, 0x0A, 0x5D, 0xA4, 0x1F, 0x12, 0x37, 0xEB, 0x2B, 0xB8, 0x5C, 0x18, 0xEA, + 0x4B, 0x31, 0x59, 0x39, 0x42, 0x06, 0x7A, 0x36, 0x77, 0x90, 0xE3, 0x3E, 0xB0, 0xD5, 0xB2, 0x6E, + 0xEE, 0xFD, 0xB0, 0xB6, 0x06, 0xB7, 0xC1, 0x38, 0x69, 0x6A, 0xF0, 0x47, 0x28, 0xEA, 0x54, 0xAA, + 0x9A, 0x40, 0x85, 0x93, 0x52, 0xA5, 0x84, 0x4F, 0x0A, 0x9F, 0x27, 0xEA, 0x10, 0xFE, 0xBB, 0x07, + 0x35, 0x42, 0x89, 0x39, 0xBF, 0x76, 0x70, 0xCC, 0xD1, 0xC7, 0x3E, 0x89, 0x65, 0xF5, 0xA2, 0xC1, + 0x82, 0x4F, 0x5D, 0xDD, 0xFB, 0xA6, 0xAB, 0xF0, 0xDC, 0xEC, 0xCA, 0xCA, 0x4B, 0xC0, 0x63, 0x56, + 0xC9, 0x8F, 0xE0, 0xCB, 0x38, 0xB4, 0x33, 0x4E, 0x74, 0x3F, 0xF2, 0x23, 0xE2, 0xA9, 0x71, 0x40, + 0x8B, 0x63, 0x74, 0xA4, 0xBD, 0x10, 0x99, 0xB4, 0x5E, 0x41, 0x1A, 0x79, 0x26, 0x1B, 0x63, 0x5B, + 0x5A, 0x1E, 0xCF, 0x33, 0xD3, 0xC7, 0x95, 0x3D, 0xD4, 0xAC, 0x58, 0x1F, 0xB2, 0x59, 0xF6, 0x3E, + 0xDF, 0x05, 0xF4, 0xA0, 0x1C, 0xAF, 0x4F, 0x06, 0xFF, 0x16, 0x2E, 0xE1, 0xD2, 0x13, 0x41, 0x6F, + 0xAE, 0x46, 0xC9, 0x6F, 0xC9, 0x8F, 0x56, 0x8E, 0x69, 0x8D, 0x43, 0xAE, 0x3D, 0x74, 0x78, 0x5C, + 0x10, 0xE0, 0xB8, 0xAD, 0xA0, 0xD9, 0xAC, 0x46, 0x0D, 0x29, 0x55, 0xCC, 0x1B, 0x66, 0x92, 0x64, + 0xD9, 0xE3, 0xDB, 0xDA, 0x07, 0x7C, 0x31, 0xD9, 0xCA, 0xC8, 0xE0, 0x64, 0x3C, 0xFC, 0xE9, 0xA9, + 0xD5, 0x8E, 0x17, 0xEC, 0xA6, 0x0A, 0x6C, 0x5D, 0xD2, 0x3C, 0x1F, 0x88, 0x33, 0xAF, 0xF0, 0x7B, + 0x40, 0x61, 0x96, 0xA2, 0xDF, 0x2F, 0x43, 0x8B, 0x65, 0x46, 0xD3, 0xD8, 0xB7, 0x3B, 0x04, 0xFB, + 0x47, 0x7F, 0xCE, 0x5A, 0x7F, 0x08, 0xE8, 0xE8, 0x5E, 0x6E, 0xDF, 0xB7, 0xFF, 0x2F, 0x37, 0x04, + 0x87, 0xB0, 0x63, 0xE5, 0x15, 0x2E, 0x6A, 0x1A, 0xCE, 0x55, 0x7A, 0xFA, 0x32, 0x49, 0x99, 0x75, + 0x9C, 0xB0, 0x91, 0x5F, 0x8F, 0x18, 0x2C, 0xF9, 0xEC, 0xB3, 0xB0, 0xC9, 0x12, 0x9E, 0x3E, 0x0A, + 0x26, 0xB5, 0xAA, 0x17, 0x41, 0x03, 0xE2, 0xB9, 0x8B, 0x6E, 0x27, 0xA3, 0xCE, 0xDD, 0x0B, 0x57, + 0x86, 0x5E, 0x82, 0x4B, 0x10, 0x88, 0x90, 0x85, 0xD0, 0x24, 0xBD, 0xF6, 0x37, 0x7C, 0xD9, 0x8C, + 0xD3, 0x55, 0x20, 0x20, 0xC4, 0xEB, 0x5B, 0x16, 0xF6, 0x17, 0xB8, 0x51, 0x91, 0xE7, 0xBC, 0xC6, + 0x9B, 0xC3, 0x76, 0xB7, 0x93, 0x25, 0x53, 0x4E, 0x29, 0x66, 0x27, 0x67, 0xCE, 0x64, 0x57, 0xB5, + 0xF4, 0xC5, 0xF3, 0x55, 0x34, 0xD1, 0xC9, 0xD1, 0x17, 0xBD, 0x3E, 0x44, 0x6D, 0x25, 0x54, 0xCB, + 0x2A, 0xE8, 0x4F, 0x71, 0x6B, 0x71, 0xCA, 0x9D, 0xA8, 0x2C, 0x89, 0xAF, 0x24, 0x90, 0xBA, 0x19, + 0x2A, 0xEA, 0x1E, 0xFF, 0x0E, 0xDA, 0x54, 0xF9, 0x85, 0x30, 0x27, 0x9D, 0xA8, 0x4F, 0xDF, 0xE3, + 0xBC, 0xB0, 0x04, 0x4A, 0x9A, 0xAE, 0xDE, 0xFD, 0x06, 0xC7, 0x1A, 0x88, 0x46, 0x57, 0x5A, 0x16, + 0x60, 0x3A, 0x62, 0x45, 0x88, 0x35, 0x92, 0xFD, 0x4D, 0x18, 0x1F, 0xAD, 0x3D, 0x33, 0xED, 0x6D, + 0x48, 0x2E, 0x63, 0x92, 0x35, 0x78, 0x4F, 0x20, 0xFE, 0x3F, 0x58, 0xE2, 0x71, 0x58, 0x92, 0x69, + 0x39, 0xA2, 0xA0, 0x8C, 0x5E, 0x61, 0x7F, 0x12, 0x8A, 0xF7, 0x6E, 0x0B, 0x71, 0xF7, 0x04, 0x38, + 0xF7, 0x49, 0x80, 0x56, 0x6F, 0x9B, 0x8B, 0x1E, 0x8E, 0xDF, 0x2B, 0x85, 0xE7, 0xC8, 0xE7, 0xCD, + 0xFD, 0x38, 0xCC, 0x96, 0xBD, 0x60, 0x54, 0xCE, 0x35, 0x16, 0x67, 0xDE, 0xE9, 0xDF, 0x57, 0xF3, + 0xAD, 0x6D, 0x11, 0x35, 0xC3, 0xEE, 0xEF, 0x85, 0x92, 0x44, 0xF7, 0xEF, 0x8A, 0xD6, 0xB5, 0x91, + 0x4C, 0x30, 0x3E, 0xFB, 0x3C, 0x9A, 0x7B, 0xBE, 0xDE, 0xDA, 0xA9, 0xFF, 0x66, 0xAD, 0xF1, 0x3A, + 0x54, 0x7E, 0xF2, 0xE7, 0x04, 0xE1, 0x9A, 0x93, 0x46, 0xA9, 0xF1, 0x1A, 0x90, 0x44, 0x41, 0xDB, + 0x9B, 0xEE, 0x63, 0x70, 0x38, 0x26, 0xFE, 0xE7, 0xD1, 0x96, 0xDD, 0xED, 0x8D, 0xB4, 0x33, 0xFE, + 0xBA, 0xC7, 0x18, 0xDD, 0xE4, 0xE9, 0x2C, 0x45, 0xB3, 0x6B, 0x5B, 0x2D, 0xE9, 0xF1, 0xA8, 0x4B, + 0xEF, 0x51, 0x4C, 0x35, 0x5F, 0xBE, 0x4E, 0x0A, 0xB8, 0x03, 0x83, 0x5A, 0xB9, 0x6B, 0x4C, 0x5C, + 0x29, 0x87, 0x52, 0xEA, 0xD1, 0x34, 0x7E, 0x9D, 0x23, 0x68, 0x8A, 0xDD, 0xA8, 0x7E, 0x9B, 0x7E, + 0xE7, 0xEA, 0xB6, 0xDF, 0xBB, 0x3B, 0x35, 0x7D, 0x20, 0x9D, 0x89, 0xE9, 0x98, 0x63, 0x96, 0x3A, + 0x94, 0x6B, 0x89, 0x59, 0x15, 0x83, 0x51, 0x21, 0x94, 0x60, 0xC4, 0x14, 0xC8, 0x8E, 0x6A, 0x85, + 0x32, 0x6A, 0x66, 0x92, 0xD6, 0x6C, 0xE9, 0x9E, 0x08, 0x93, 0x0D, 0x55, 0xD7, 0x79, 0xAD, 0xE6, + 0xC6, 0xF2, 0x6A, 0x6B, 0xD1, 0x14, 0x0A, 0x07, 0xA8, 0x90, 0x6A, 0xFF, 0x0F, 0xDF, 0xC7, 0x55, + 0x93, 0x94, 0x7F, 0x4D, 0x70, 0x07, 0x7C, 0x64, 0x10, 0x63, 0x93, 0xF3, 0x89, 0xA5, 0x20, 0x7F, + 0x63, 0xD7, 0xA8, 0x69, 0xBE, 0x3F, 0x5A, 0xD7, 0x3C, 0x91, 0x6E, 0x23, 0xF9, 0x78, 0x92, 0xB2, + 0x63, 0xA0, 0x21, 0x9E, 0x9E, 0x98, 0x9C, 0xBF, 0x2B, 0xB5, 0xA5, 0x62, 0x2A, 0xB6, 0x13, 0xC9, + 0x19, 0xB4, 0x1B, 0x11, 0x01, 0x40, 0x5B, 0xB9, 0x03, 0x1D, 0x3B, 0x4A, 0xE9, 0x12, 0xCD, 0x37, + 0xDE, 0x97, 0xBA, 0xA5, 0x7A, 0xAA, 0xA2, 0xAC, 0xD4, 0x21, 0xD9, 0x44, 0x59, 0xE2, 0x39, 0x41, + 0x9C, 0xD1, 0xF0, 0x15, 0xEE, 0x7B, 0x04, 0x3B, 0xFC, 0x07, 0xB2, 0xA2, 0x1D, 0xF8, 0x65, 0x2B, + 0x9E, 0xED, 0x84, 0xAC, 0x0E, 0x24, 0x38, 0x08, 0xB2, 0xB1, 0x5F, 0xE1, 0x9A, 0x65, 0x7D, 0x0F, + 0xCE, 0xAF, 0x28, 0x37, 0x18, 0x0C, 0xB2, 0x79, 0xF0, 0x1D, 0xFF, 0x91, 0xC1, 0xDC, 0x5F, 0x97, + 0x37, 0xE7, 0x9D, 0x27, 0x96, 0x63, 0x24, 0xFD, 0x1F, 0x2C, 0xE5, 0x6C, 0x5C, 0xBF, 0x62, 0x3A, + 0x78, 0x41, 0x18, 0x96, 0xE2, 0xBA, 0x91, 0xF3, 0x6C, 0x87, 0xC3, 0x97, 0x98, 0x5D, 0xD8, 0xB3, + 0x4B, 0x46, 0xA1, 0x0E, 0xD5, 0x23, 0x1B, 0x2A, 0x0B, 0x51, 0x2F, 0xC6, 0xE8, 0x0A, 0x71, 0xC4, + 0xC4, 0x6B, 0xCF, 0x85, 0x96, 0x81, 0xEB, 0x6F, 0xE1, 0x0A, 0xD8, 0xD3, 0x26, 0x38, 0x5A, 0xE0, + 0x5C, 0x5E, 0xBC, 0x1A, 0xFE, 0x15, 0x9E, 0xA4, 0x5C, 0x37, 0x49, 0x36, 0x3C, 0x5C, 0x20, 0x3B, + 0xA1, 0xBB, 0xF0, 0xB6, 0x94, 0x03, 0x1D, 0xCD, 0x79, 0xF8, 0x91, 0x0A, 0xE3, 0x9B, 0x03, 0x85, + 0x78, 0x0E, 0x8C, 0xD9, 0x68, 0x06, 0xC6, 0xA1, 0x64, 0x6D, 0x7C, 0xFB, 0x31, 0x3F, 0x13, 0xA1, + 0x78, 0xC0, 0x65, 0x0D, 0x65, 0xB2, 0xB0, 0x60, 0x40, 0x34, 0x6E, 0xFA, 0x28, 0x7B, 0xA2, 0x57, + 0x03, 0x30, 0x66, 0xD5, 0x86, 0xF1, 0xA4, 0xF5, 0x96, 0x82, 0xC1, 0xAD, 0x1F, 0x9C, 0xD8, 0x83, + 0x4A, 0xEA, 0xF5, 0xB3, 0x8C, 0x54, 0xCA, 0x9F, 0x76, 0x08, 0xE7, 0x6E, 0xD8, 0xDF, 0xE2, 0x08, + 0xD6, 0x96, 0x53, 0xA6, 0x87, 0xA6, 0xB2, 0x67, 0xB0, 0x09, 0x67, 0xEC, 0x3A, 0xBA, 0xBC, 0x20, + 0x47, 0x90, 0x16, 0xB6, 0x0C, 0x18, 0x5F, 0x70, 0xEB, 0x4B, 0x1C, 0x1D, 0x3C, 0x6D, 0x4C, 0xC7, + 0x34, 0x6D, 0x6B, 0xC6, 0xBB, 0xF7, 0xF0, 0x4F, 0x46, 0x5D, 0x6B, 0xCB, 0xE2, 0x2D, 0x60, 0x54, + 0x27, 0x7D, 0x59, 0xF3, 0x72, 0xE2, 0xFF, 0x07, 0xC1, 0x6F, 0x37, 0x3D, 0xAC, 0x38, 0x7A, 0x89, + 0x6B, 0x99, 0xBD, 0x34, 0x76, 0xF5, 0x52, 0x61, 0x5C, 0x09, 0xD8, 0x49, 0x00, 0xDF, 0x3A, 0x93, + 0x05, 0xE6, 0x3F, 0x84, 0x7C, 0xE4, 0x8E, 0xF3, 0xF0, 0xF3, 0x17, 0x2C, 0xD5, 0x00, 0x9D, 0x46, + 0x0C, 0xE2, 0x26, 0x9D, 0xC0, 0x9E, 0xA0, 0x52, 0x13, 0x53, 0x2F, 0xF4, 0x2C, 0x99, 0x11, 0x6D, + 0x60, 0x6B, 0x2D, 0xDD, 0xF1, 0x7C, 0x53, 0x04, 0x9C, 0xB6, 0x33, 0x2F, 0x8C, 0x6C, 0x19, 0x7C, + 0x65, 0x16, 0xB3, 0xF6, 0x57, 0x02, 0xE2, 0x0E, 0xCD, 0x22, 0xCF, 0x61, 0x3D, 0x77, 0xAF, 0x44, + 0x38, 0x8A, 0x33, 0x05, 0xD9, 0xDE, 0xDD, 0xB7, 0x59, 0x6E, 0xCD, 0x69, 0x95, 0xA5, 0x69, 0x9A, + 0x15, 0x29, 0x6A, 0x67, 0xAB, 0xCB, 0xCF, 0x67, 0xC8, 0x7C, 0x43, 0x2E, 0x9E, 0xF7, 0x2E, 0x0C, + 0xE4, 0xC5, 0x9F, 0x7C, 0xBF, 0x11, 0x45, 0xF0, 0x64, 0xED, 0x6F, 0xCE, 0x26, 0xD2, 0xDD, 0xCB, + 0x7C, 0x71, 0x92, 0xF1, 0x7F, 0xF6, 0x16, 0x27, 0xC7, 0x15, 0x6B, 0x26, 0x13, 0x86, 0x68, 0xC3, + 0x88, 0xA6, 0xEA, 0x2A, 0x0F, 0xA3, 0x89, 0xB2, 0x03, 0x98, 0xB3, 0x3C, 0xF8, 0x40, 0x0B, 0xD8, + 0x35, 0xC8, 0xDD, 0xCD, 0x9A, 0x10, 0xFD, 0x4D, 0x35, 0x0E, 0x22, 0x5D, 0xA2, 0xCE, 0x35, 0xE4, + 0xB9, 0xC8, 0x69, 0x70, 0x07, 0xEE, 0xA5, 0x53, 0xC1, 0x05, 0x40, 0x02, 0x05, 0x74, 0x80, 0x5A, + 0x33, 0x2B, 0x04, 0x7F, 0x77, 0xF1, 0x40, 0xDF, 0x2C, 0xB4, 0xE3, 0xEF, 0x76, 0x63, 0xB0, 0xE5, + 0x37, 0x2D, 0x4E, 0xD3, 0xF7, 0x4F, 0xA6, 0x12, 0x1C, 0x84, 0x33, 0xBE, 0xBD, 0x06, 0xAF, 0x07, + 0x5C, 0xB2, 0x4F, 0x39, 0x3D, 0x10, 0x65, 0x24, 0xAF, 0x80, 0xCA, 0x44, 0xCC, 0x32, 0x8B, 0x2B, + 0x94, 0xA3, 0x75, 0xAE, 0xDE, 0x27, 0x22, 0xF2, 0xF2, 0xA7, 0x4E, 0x0F, 0x90, 0x20, 0x45, 0xC5, + 0xFA, 0xFE, 0xFE, 0x09, 0xA5, 0xFD, 0x23, 0x06, 0x8A, 0x38, 0x1A, 0xE3, 0x67, 0x84, 0xA9, 0xC6, + 0x41, 0x61, 0x1F, 0x6C, 0x1E, 0xE4, 0x78, 0x6C, 0x35, 0x52, 0xC8, 0x12, 0xBC, 0x0C, 0xBE, 0x1B, + 0xAB, 0x9B, 0x2A, 0x64, 0x9D, 0x40, 0x74, 0x1A, 0x89, 0xD1, 0x2B, 0xA6, 0x1F, 0x27, 0x06, 0xDB, + 0x46, 0x09, 0x5B, 0x49, 0x70, 0xA6, 0x97, 0x8A, 0x55, 0x87, 0x18, 0x38, 0xA4, 0xD6, 0x0A, 0x9F, + 0xF5, 0x2D, 0xFA, 0x13, 0xF6, 0x27, 0xD8, 0x6E, 0x92, 0x46, 0x49, 0x02, 0xF8, 0x47, 0xD2, 0x5C, + 0x82, 0x92, 0xA7, 0x31, 0xF5, 0x1A, 0xD9, 0x66, 0xC5, 0x52, 0x6B, 0xD5, 0xD0, 0x74, 0xA4, 0x0B, + 0x66, 0xFE, 0xF2, 0xE3, 0x08, 0x3C, 0x86, 0x95, 0x54, 0x51, 0x73, 0xAC, 0x1D, 0xA9, 0x8D, 0xA2, + 0xA5, 0x66, 0xC4, 0x27, 0x5C, 0xB3, 0xA2, 0xB7, 0xDF, 0xEC, 0xD6, 0x15, 0xFF, 0xF7, 0x6C, 0x38, + 0xF3, 0x32, 0x18, 0xFA, 0x41, 0x32, 0xEE, 0xAC, 0xDD, 0xB3, 0x18, 0xAB, 0x47, 0x66, 0xB6, 0x3C, + 0x69, 0xB8, 0x88, 0x80, 0x39, 0xDF, 0x54, 0x21, 0x90, 0x09, 0xC4, 0x18, 0x10, 0x18, 0xAE, 0x13, + 0xF2, 0xFA, 0x31, 0xBF, 0x39, 0x79, 0x03, 0x09, 0x09, 0x09, 0x1D, 0x86, 0xAC, 0xCD, 0x4D, 0xDB, + 0xA6, 0x86, 0x06, 0x6F, 0x79, 0x1D, 0xE1, 0x7C, 0x8E, 0x39, 0x15, 0xC4, 0x26, 0xB7, 0x45, 0x2B, + 0xF7, 0x8B, 0xB1, 0x97, 0x8A, 0x69, 0x3A, 0xE2, 0x85, 0xD1, 0x39, 0x57, 0x05, 0xD2, 0x60, 0xC7, + 0xD7, 0xE4, 0x05, 0xCF, 0xFD, 0x7D, 0xB4, 0x33, 0xAB, 0x48, 0x79, 0x3E, 0x93, 0x29, 0xD8, 0xCC, + 0xC5, 0x22, 0x7E, 0xA8, 0x9D, 0x76, 0xF8, 0xA5, 0xD1, 0x85, 0x32, 0x71, 0xED, 0x33, 0x4C, 0xD1, + 0x1B, 0x61, 0x7F, 0x6A, 0x2A, 0x34, 0xF0, 0xE2, 0xC6, 0x08, 0x5E, 0x32, 0x79, 0x06, 0x96, 0x5A, + 0x03, 0x07, 0xD9, 0x22, 0x3F, 0xE4, 0xEB, 0xD9, 0x7D, 0x0C, 0xAD, 0x63, 0x91, 0x74, 0x86, 0x5C, + 0xED, 0xD9, 0x8D, 0x23, 0xFE, 0xCC, 0x0A, 0xE8, 0xA0, 0xC6, 0xF4, 0x7D, 0x08, 0xC3, 0x5E, 0x11, + 0x5D, 0x56, 0x64, 0x73, 0x25, 0xE7, 0x10, 0xE5, 0x9B, 0xB1, 0xE7, 0xDC, 0xD4, 0xC5, 0x3B, 0xA4, + 0x20, 0x12, 0x05, 0x19, 0x04, 0x3F, 0x03, 0x1E, 0x05, 0x20, 0xB1, 0x08, 0x0B, 0x19, 0x19, 0x00, + 0x00, 0x00, 0x05, 0x80, 0x07, 0x03, 0x1A, 0x1E, 0x05, 0x2D, 0xEB, 0x0F, 0x92, 0x09, 0x01, 0x36, + 0x30, 0x00, 0x30, 0x00, 0xDD, 0x48, 0xB0, 0x42, 0xAD, 0xEB, 0x3D, 0xE7, 0x00, 0xA0, 0x1D, 0x1D, + 0x1D, 0x1D, 0x0A, 0x04, 0xC0, 0x5C, 0x17, 0x1A, 0x5A, 0xF4, 0x06, 0x19, 0x00, 0x00, 0x0A, 0x00, + 0x08, 0xA1, 0x00, 0x38, 0x03, 0x01, 0xEF, 0x1A, 0x10, 0x00, 0x02, 0x0B, 0x01, 0x80, 0x02, 0x0E, + 0x1F, 0x16, 0x2B, 0x00, 0x19, 0x04, 0x00, 0x00, 0x10, 0x0A, 0x00, 0x14, 0x11, 0x12, 0x10, 0x0F, + 0x0E, 0x0A, 0x09, 0x07, 0x08, 0x01, 0x18, 0x19, 0x1B, 0x1A, 0x15, 0x16, 0x17, 0x0D, 0x0C, 0x06, + 0x05, 0x0B, 0x04, 0x03, 0x02, 0x00, 0x0B, 0x13, 0x0C, 0x05, 0x0A, 0x02, 0x04, 0x06, 0x08, 0x01, + 0x0D, 0x07, 0x0E, 0x10, 0x0F, 0x12, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x2A, 0x2A, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x00, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xC0, 0x80, 0x00, 0x18, + 0x00, 0x18, 0x00, 0x10, 0x00, 0x10, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x51, 0x7E, 0x56, 0x58, 0x5A, 0x5C, 0x5E, 0x60, 0x00, 0xFF, 0xFF, 0x10, 0x0A, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x0D, + 0x00, 0x10, 0x00, 0xA2, 0xB7, 0xAD, 0xAD, 0xCD, 0x0D, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x49, 0xC7, 0xF3, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3F, 0x03, 0x1E, + 0x05, 0x20, 0xB1, 0x08, 0x0B, 0x19, 0x19, 0x00, 0x00, 0x4C, 0x04, 0x6C, 0x07, 0x02, 0x14, 0x1E, + 0x05, 0x28, 0xF5, 0x28, 0x1E, 0x05, 0x01, 0x3C, 0x30, 0x00, 0x30, 0x00, 0x00, 0x48, 0x00, 0x48, + 0xF0, 0xD2, 0xF0, 0xD2, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x04, 0xC0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x19, 0x01, 0x00, 0x0A, 0x00, 0x08, 0xA2, 0x02, 0x32, 0x0A, 0x0A, 0x96, 0x1B, + 0x10, 0x00, 0x00, 0x56, 0x35, 0x05, 0x10, 0x00, 0x00, 0x0B, 0x20, 0x00, 0x01, 0xE0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x33, 0x32, 0x30, 0x32, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x0F, 0x05, 0x00, 0x38, 0x15, 0x10, 0x1B, 0x2B, 0xC0, 0xD1, 0xFF, 0x0C, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xA2, 0x63, + 0x15, 0x21, 0x11, 0xAC, 0xA1, 0x5C, 0x13, 0x01, 0x01, 0xA3, 0x00, 0x58, 0x00, 0x01, 0x34, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xF4, 0x01, 0x80, + 0x03, 0x0E, 0x1F, 0x00, 0xDB, 0x01, 0x19, 0x04, 0x00, 0x00, 0x10, 0x0A, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x01, 0x02, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0A, + 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x12, 0x13, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xC0, 0x80, + 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0x0A, + 0x00, 0x00, 0x00, 0x1B, 0x10, 0x44, 0x88, 0x13, 0x01, 0x01, 0xBF, 0x01, 0x7E, 0x3D, 0x00, 0x00, + 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB3, 0xB2, 0x0B, 0x00, 0x01, 0x54, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + diff --git a/drivers/input/touchscreen/rmi4/rmi_spi.c b/drivers/input/touchscreen/rmi4/rmi_spi.c new file mode 100755 index 000000000000..a19e49aa9457 --- /dev/null +++ b/drivers/input/touchscreen/rmi4/rmi_spi.c @@ -0,0 +1,909 @@ +/* + * Copyright (c) 2011 Synaptics Incorporated + * Copyright (c) 2011 Unixphere + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define COMMS_DEBUG 0 +#define FF_DEBUG 0 + +#define RMI_PROTOCOL_VERSION_ADDRESS 0xa0fd +#define SPI_V2_UNIFIED_READ 0xc0 +#define SPI_V2_WRITE 0x40 +#define SPI_V2_PREPARE_SPLIT_READ 0xc8 +#define SPI_V2_EXECUTE_SPLIT_READ 0xca + +#define RMI_SPI_BLOCK_DELAY_US 65 +#define RMI_SPI_BYTE_DELAY_US 65 +#define RMI_SPI_WRITE_DELAY_US 0 + +#define RMI_V1_READ_FLAG 0x80 + +#define RMI_PAGE_SELECT_REGISTER 0x00FF +#define RMI_SPI_PAGE(addr) (((addr) >> 8) & 0x80) + +#define DEFAULT_POLL_INTERVAL_MS 13 + +static char *spi_v1_proto_name = "spi"; +static char *spi_v2_proto_name = "spiv2"; + +struct rmi_spi_data { + struct mutex page_mutex; + int page; + int (*set_page) (struct rmi_phys_device *phys, u8 page); + bool split_read_pending; + int enabled; + int irq; + int irq_flags; + struct rmi_phys_device *phys; + struct completion irq_comp; + + /* Following are used when polling. */ + struct hrtimer poll_timer; + struct work_struct poll_work; + int poll_interval; + +}; + +static irqreturn_t rmi_spi_hard_irq(int irq, void *p) +{ + struct rmi_phys_device *phys = p; + struct rmi_spi_data *data = phys->data; + struct rmi_device_platform_data *pdata = phys->dev->platform_data; + + if (data->split_read_pending && + gpio_get_value(pdata->attn_gpio) == + pdata->attn_polarity) { + phys->info.attn_count++; + complete(&data->irq_comp); + return IRQ_HANDLED; + } + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t rmi_spi_irq_thread(int irq, void *p) +{ + struct rmi_phys_device *phys = p; + struct rmi_device *rmi_dev = phys->rmi_dev; + struct rmi_driver *driver = rmi_dev->driver; + struct rmi_device_platform_data *pdata = phys->dev->platform_data; + + if (gpio_get_value(pdata->attn_gpio) == pdata->attn_polarity) { + phys->info.attn_count++; + if (driver && driver->irq_handler) + driver->irq_handler(rmi_dev, irq); + } + + return IRQ_HANDLED; +} + +static void spi_poll_work(struct work_struct *work) +{ + struct rmi_spi_data *data = + container_of(work, struct rmi_spi_data, poll_work); + struct rmi_device *rmi_dev = data->phys->rmi_dev; + struct rmi_driver *driver = rmi_dev->driver; + + if (driver && driver->irq_handler) + driver->irq_handler(rmi_dev, 0); +} + +/* This is the timer function for polling - it simply has to schedule work + * and restart the timer. */ +static enum hrtimer_restart spi_poll_timer(struct hrtimer *timer) +{ + struct rmi_spi_data *data = + container_of(timer, struct rmi_spi_data, poll_timer); + + if (!work_pending(&data->poll_work)) + schedule_work(&data->poll_work); + hrtimer_start(&data->poll_timer, ktime_set(0, data->poll_interval), + HRTIMER_MODE_REL); + return HRTIMER_NORESTART; +} + + + +static int rmi_spi_xfer(struct rmi_phys_device *phys, + const u8 *txbuf, unsigned n_tx, u8 *rxbuf, unsigned n_rx) +{ + struct spi_device *client = to_spi_device(phys->dev); + struct rmi_spi_data *v2_data = phys->data; + struct rmi_device_platform_data *pdata = phys->dev->platform_data; + int status; + struct spi_message message; + struct spi_transfer *xfers; + int total_bytes = n_tx + n_rx; + u8 local_buf[total_bytes]; + int xfer_count = 0; + int xfer_index = 0; + int block_delay = n_rx > 0 ? pdata->spi_data.block_delay_us : 0; + int byte_delay = n_rx > 1 ? pdata->spi_data.read_delay_us : 0; + int write_delay = n_tx > 1 ? pdata->spi_data.write_delay_us : 0; +#if FF_DEBUG + bool bad_data = true; +#endif +#if COMMS_DEBUG || FF_DEBUG + int i; +#endif + + if (v2_data->split_read_pending) { + block_delay = + n_rx > 0 ? pdata->spi_data.split_read_block_delay_us : 0; + byte_delay = + n_rx > 1 ? pdata->spi_data.split_read_byte_delay_us : 0; + write_delay = 0; + } + + if (n_tx) { + phys->info.tx_count++; + phys->info.tx_bytes += n_tx; + if (write_delay) + xfer_count += n_tx; + else + xfer_count += 1; + } + + if (n_rx) { + phys->info.rx_count++; + phys->info.rx_bytes += n_rx; + if (byte_delay) + xfer_count += n_rx; + else + xfer_count += 1; + } + + xfers = kcalloc(xfer_count, + sizeof(struct spi_transfer), GFP_KERNEL); + if (!xfers) + return -ENOMEM; + + spi_message_init(&message); + + if (n_tx) { + if (write_delay) { + for (xfer_index = 0; xfer_index < n_tx; + xfer_index++) { + memset(&xfers[xfer_index], 0, + sizeof(struct spi_transfer)); + xfers[xfer_index].len = 1; + xfers[xfer_index].delay_usecs = write_delay; + xfers[xfer_index].tx_buf = txbuf + xfer_index; + spi_message_add_tail(&xfers[xfer_index], + &message); + } + } else { + memset(&xfers[0], 0, sizeof(struct spi_transfer)); + xfers[0].len = n_tx; + spi_message_add_tail(&xfers[0], &message); + memcpy(local_buf, txbuf, n_tx); + xfers[0].tx_buf = local_buf; + xfer_index++; + } + if (block_delay) + xfers[xfer_index-1].delay_usecs = block_delay; + } + if (n_rx) { + if (byte_delay) { + int buffer_offset = n_tx; + for (; xfer_index < xfer_count; xfer_index++) { + memset(&xfers[xfer_index], 0, + sizeof(struct spi_transfer)); + xfers[xfer_index].len = 1; + xfers[xfer_index].delay_usecs = byte_delay; + xfers[xfer_index].rx_buf = + local_buf + buffer_offset; + buffer_offset++; + spi_message_add_tail(&xfers[xfer_index], + &message); + } + } else { + memset(&xfers[xfer_index], 0, + sizeof(struct spi_transfer)); + xfers[xfer_index].len = n_rx; + xfers[xfer_index].rx_buf = local_buf + n_tx; + spi_message_add_tail(&xfers[xfer_index], &message); + xfer_index++; + } + } + +#if COMMS_DEBUG + if (n_tx) { + dev_dbg(&client->dev, "SPI sends %d bytes: ", n_tx); + for (i = 0; i < n_tx; i++) + pr_info("%02X ", txbuf[i]); + pr_info("\n"); + } +#endif + + /* do the i/o */ + if (pdata->spi_data.cs_assert) { + status = pdata->spi_data.cs_assert( + pdata->spi_data.cs_assert_data, true); + if (status) { + dev_err(phys->dev, "Failed to assert CS, code %d.\n", + status); + /* nonzero means error */ + status = -1; + goto error_exit; + } else + status = 0; + } + + if (pdata->spi_data.pre_delay_us) + udelay(pdata->spi_data.pre_delay_us); + + status = spi_sync(client, &message); + + if (pdata->spi_data.post_delay_us) + udelay(pdata->spi_data.post_delay_us); + + if (pdata->spi_data.cs_assert) { + status = pdata->spi_data.cs_assert( + pdata->spi_data.cs_assert_data, false); + if (status) { + dev_err(phys->dev, "Failed to deassert CS. code %d.\n", + status); + /* nonzero means error */ + status = -1; + goto error_exit; + } else + status = 0; + } + + if (status == 0) { + memcpy(rxbuf, local_buf + n_tx, n_rx); + status = message.status; + } else { + if (n_tx) phys->info.tx_errs++; + if (n_rx) phys->info.rx_errs++; + dev_err(phys->dev, "spi_sync failed with error code %d.", + status); + goto error_exit; + } + +#if COMMS_DEBUG + if (n_rx) { + dev_dbg(&client->dev, "SPI received %d bytes: ", n_rx); + for (i = 0; i < n_rx; i++) + pr_info("%02X ", rxbuf[i]); + pr_info("\n"); + } +#endif +#if FF_DEBUG + if (n_rx) { + for (i = 0; i < n_rx; i++) { + if (rxbuf[i] != 0xFF) { + bad_data = false; + break; + } + } + if (bad_data) { + phys->info.rx_errs++; + dev_err(phys->dev, "BAD READ %lu out of %lu.\n", + phys->info.rx_errs, phys->info.rx_count); + } + } +#endif + +error_exit: + kfree(xfers); + return status; +} + +static int rmi_spi_v2_write_block(struct rmi_phys_device *phys, u16 addr, + u8 *buf, int len) +{ + struct rmi_spi_data *data = phys->data; + u8 txbuf[len + 4]; + int error; + + txbuf[0] = SPI_V2_WRITE; + txbuf[1] = (addr >> 8) & 0x00FF; + txbuf[2] = addr & 0x00FF; + txbuf[3] = len; + + memcpy(&txbuf[4], buf, len); + + mutex_lock(&data->page_mutex); + + if (RMI_SPI_PAGE(addr) != data->page) { + error = data->set_page(phys, RMI_SPI_PAGE(addr)); + if (error < 0) + goto exit; + } + + error = rmi_spi_xfer(phys, buf, len + 4, NULL, 0); + if (error < 0) + goto exit; + error = len; + +exit: + mutex_unlock(&data->page_mutex); + return error; +} + +static int rmi_spi_v2_write(struct rmi_phys_device *phys, u16 addr, u8 data) +{ + int error = rmi_spi_v2_write_block(phys, addr, &data, 1); + + return (error == 1) ? 0 : error; +} + +static int rmi_spi_v1_write_block(struct rmi_phys_device *phys, u16 addr, + u8 *buf, int len) +{ + struct rmi_spi_data *data = phys->data; + unsigned char txbuf[len + 2]; + int error; + + txbuf[0] = (addr >> 8) & ~RMI_V1_READ_FLAG; + txbuf[1] = addr; + memcpy(txbuf+2, buf, len); + + mutex_lock(&data->page_mutex); + + if (RMI_SPI_PAGE(addr) != data->page) { + error = data->set_page(phys, RMI_SPI_PAGE(addr)); + if (error < 0) + goto exit; + } + + error = rmi_spi_xfer(phys, txbuf, len + 2, NULL, 0); + if (error < 0) + goto exit; + error = len; + +exit: + mutex_unlock(&data->page_mutex); + return error; +} + +static int rmi_spi_v1_write(struct rmi_phys_device *phys, u16 addr, u8 data) +{ + int error = rmi_spi_v1_write_block(phys, addr, &data, 1); + + return (error == 1) ? 0 : error; +} + +static int rmi_spi_v2_split_read_block(struct rmi_phys_device *phys, u16 addr, + u8 *buf, int len) +{ + struct rmi_spi_data *data = phys->data; + u8 txbuf[4]; + u8 rxbuf[len + 1]; /* one extra byte for read length */ + int error; + + txbuf[0] = SPI_V2_PREPARE_SPLIT_READ; + txbuf[1] = (addr >> 8) & 0x00FF; + txbuf[2] = addr & 0x00ff; + txbuf[3] = len; + + mutex_lock(&data->page_mutex); + + if (RMI_SPI_PAGE(addr) != data->page) { + error = data->set_page(phys, RMI_SPI_PAGE(addr)); + if (error < 0) + goto exit; + } + + data->split_read_pending = true; + + error = rmi_spi_xfer(phys, txbuf, 4, NULL, 0); + if (error < 0) { + data->split_read_pending = false; + goto exit; + } + + wait_for_completion(&data->irq_comp); + + txbuf[0] = SPI_V2_EXECUTE_SPLIT_READ; + txbuf[1] = 0; + + error = rmi_spi_xfer(phys, txbuf, 2, rxbuf, len + 1); + data->split_read_pending = false; + if (error < 0) + goto exit; + + /* first byte is length */ + if (rxbuf[0] != len) { + error = -EIO; + goto exit; + } + + memcpy(buf, rxbuf + 1, len); + error = len; + +exit: + mutex_unlock(&data->page_mutex); + return error; +} + +static int rmi_spi_v2_read_block(struct rmi_phys_device *phys, u16 addr, + u8 *buf, int len) +{ + struct rmi_spi_data *data = phys->data; + u8 txbuf[4]; + int error; + + txbuf[0] = SPI_V2_UNIFIED_READ; + txbuf[1] = (addr >> 8) & 0x00FF; + txbuf[2] = addr & 0x00ff; + txbuf[3] = len; + + mutex_lock(&data->page_mutex); + + if (RMI_SPI_PAGE(addr) != data->page) { + error = data->set_page(phys, RMI_SPI_PAGE(addr)); + if (error < 0) + goto exit; + } + + error = rmi_spi_xfer(phys, txbuf, 4, buf, len); + if (error < 0) + goto exit; + error = len; + +exit: + mutex_unlock(&data->page_mutex); + return error; +} + +static int rmi_spi_v2_read(struct rmi_phys_device *phys, u16 addr, u8 *buf) +{ + int error = rmi_spi_v2_read_block(phys, addr, buf, 1); + + return (error == 1) ? 0 : error; +} + +static int rmi_spi_v1_read_block(struct rmi_phys_device *phys, u16 addr, + u8 *buf, int len) +{ + struct rmi_spi_data *data = phys->data; + u8 txbuf[2]; + int error; + + txbuf[0] = (addr >> 8) | RMI_V1_READ_FLAG; + txbuf[1] = addr; + + mutex_lock(&data->page_mutex); + + if (RMI_SPI_PAGE(addr) != data->page) { + error = data->set_page(phys, RMI_SPI_PAGE(addr)); + if (error < 0) + goto exit; + } + + error = rmi_spi_xfer(phys, txbuf, 2, buf, len); + if (error < 0) + goto exit; + error = len; + +exit: + mutex_unlock(&data->page_mutex); + return error; +} + +static int rmi_spi_v1_read(struct rmi_phys_device *phys, u16 addr, u8 *buf) +{ + int error = rmi_spi_v1_read_block(phys, addr, buf, 1); + + return (error == 1) ? 0 : error; +} + +#define RMI_SPI_PAGE_SELECT_WRITE_LENGTH 1 + +static int rmi_spi_v1_set_page(struct rmi_phys_device *phys, u8 page) +{ + struct rmi_spi_data *data = phys->data; + u8 txbuf[] = {RMI_PAGE_SELECT_REGISTER >> 8, + RMI_PAGE_SELECT_REGISTER & 0xFF, page}; + int error; + + error = rmi_spi_xfer(phys, txbuf, sizeof(txbuf), NULL, 0); + if (error < 0) { + dev_err(phys->dev, "Failed to set page select, code: %d.\n", + error); + return error; + } + + data->page = page; + + return RMI_SPI_PAGE_SELECT_WRITE_LENGTH; +} + +static int rmi_spi_v2_set_page(struct rmi_phys_device *phys, u8 page) +{ + struct rmi_spi_data *data = phys->data; + u8 txbuf[] = {SPI_V2_WRITE, RMI_PAGE_SELECT_REGISTER >> 8, + RMI_PAGE_SELECT_REGISTER & 0xFF, + RMI_SPI_PAGE_SELECT_WRITE_LENGTH, page}; + int error; + + error = rmi_spi_xfer(phys, txbuf, sizeof(txbuf), NULL, 0); + if (error < 0) { + dev_err(phys->dev, "Failed to set page select, code: %d.\n", + error); + return error; + } + + data->page = page; + + return RMI_SPI_PAGE_SELECT_WRITE_LENGTH; +} + + +static int acquire_attn_irq(struct rmi_spi_data *data) +{ + int retval; + struct rmi_phys_device *rmi_phys = data->phys; + + retval = request_threaded_irq(data->irq, rmi_spi_hard_irq, + rmi_spi_irq_thread, data->irq_flags, + dev_name(rmi_phys->dev), rmi_phys); + if (retval < 0) { + dev_err(&(rmi_phys->rmi_dev->dev), "request_threaded_irq " + "failed, code: %d.\n", retval); + } + return retval; +} + +static int setup_attn(struct rmi_spi_data *data) +{ + int retval; + struct rmi_phys_device *rmi_phys = data->phys; + struct rmi_device_platform_data *pdata = rmi_phys->dev->platform_data; + + retval = acquire_attn_irq(data); + if (retval < 0) + return retval; + +#if defined(CONFIG_RMI4_DEV) + retval = gpio_export(pdata->attn_gpio, false); + if (retval) { + dev_warn(&(rmi_phys->rmi_dev->dev), + "WARNING: Failed to export ATTN gpio!\n"); + retval = 0; + } else { + retval = gpio_export_link(&(rmi_phys->rmi_dev->dev), "attn", + pdata->attn_gpio); + if (retval) { + dev_warn(&(rmi_phys->rmi_dev->dev), "WARNING: " + "Failed to symlink ATTN gpio!\n"); + retval = 0; + } else { + dev_info(&(rmi_phys->rmi_dev->dev), + "%s: Exported GPIO %d.", __func__, + pdata->attn_gpio); + } + } +#endif /* CONFIG_RMI4_DEV */ + + return retval; +} + +static int setup_polling(struct rmi_spi_data *data) +{ + INIT_WORK(&data->poll_work, spi_poll_work); + hrtimer_init(&data->poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + data->poll_timer.function = spi_poll_timer; + hrtimer_start(&data->poll_timer, ktime_set(1, 0), HRTIMER_MODE_REL); + + return 0; +} + +static int enable_device(struct rmi_phys_device *phys) +{ + int retval = 0; + + struct rmi_spi_data *data = phys->data; + + if (data->enabled) { + dev_dbg(phys->dev, "Physical device already enabled.\n"); + return 0; + } + + retval = acquire_attn_irq(data); + if (retval) + goto error_exit; + + data->enabled = true; + dev_dbg(phys->dev, "Physical device enabled.\n"); + return 0; + +error_exit: + dev_err(phys->dev, "Failed to enable physical device. Code=%d.\n", + retval); + return retval; +} + +static void disable_device(struct rmi_phys_device *phys) +{ + struct rmi_spi_data *data = phys->data; + + if (!data->enabled) { + dev_warn(phys->dev, "Physical device already disabled.\n"); + return; + } + disable_irq(data->irq); + free_irq(data->irq, data->phys); + + dev_dbg(phys->dev, "Physical device disabled.\n"); + data->enabled = false; +} + +#define DUMMY_READ_SLEEP_US 10 + +static int rmi_spi_check_device(struct rmi_phys_device *rmi_phys) +{ + u8 buf[6]; + int error; + int i; + + /* Some SPI subsystems return 0 for the very first read you do. So + * we use this dummy read to get that out of the way. + */ + error = rmi_spi_v1_read_block(rmi_phys, PDT_START_SCAN_LOCATION, + buf, sizeof(buf)); + if (error < 0) { + dev_err(rmi_phys->dev, "dummy read failed with %d.\n", error); + return error; + } + udelay(DUMMY_READ_SLEEP_US); + + /* Force page select to 0. + */ + error = rmi_spi_v1_set_page(rmi_phys, 0x00); + if (error < 0) + return error; + + /* Now read the first PDT entry. We know where this is, and if the + * RMI4 device is out there, these 6 bytes will be something other + * than all 0x00 or 0xFF. We need to check for 0x00 and 0xFF, + * because many (maybe all) SPI implementations will return all 0x00 + * or all 0xFF on read if the device is not connected. + */ + error = rmi_spi_v1_read_block(rmi_phys, PDT_START_SCAN_LOCATION, + buf, sizeof(buf)); + if (error < 0) { + dev_err(rmi_phys->dev, "probe read failed with %d.\n", error); + return error; + } + for (i = 0; i < sizeof(buf); i++) { + if (buf[i] != 0x00 && buf[i] != 0xFF) + return error; + } + + dev_err(rmi_phys->dev, "probe read returned invalid block.\n"); + return -ENODEV; +} + + +static int __devinit rmi_spi_probe(struct spi_device *spi) +{ + struct rmi_phys_device *rmi_phys; + struct rmi_spi_data *data; + struct rmi_device_platform_data *pdata = spi->dev.platform_data; + u8 buf[2]; + int retval; + + if (!pdata) { + dev_err(&spi->dev, "no platform data\n"); + return -EINVAL; + } + + if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) + return -EINVAL; + + spi->bits_per_word = 8; + spi->mode = SPI_MODE_3; + retval = spi_setup(spi); + if (retval < 0) { + dev_err(&spi->dev, "spi_setup failed!\n"); + return retval; + } + + rmi_phys = kzalloc(sizeof(struct rmi_phys_device), GFP_KERNEL); + if (!rmi_phys) + return -ENOMEM; + + data = kzalloc(sizeof(struct rmi_spi_data), GFP_KERNEL); + if (!data) { + retval = -ENOMEM; + goto err_phys; + } + data->enabled = true; /* We plan to come up enabled. */ + data->irq = gpio_to_irq(pdata->attn_gpio); + if (pdata->level_triggered) { + data->irq_flags = IRQF_ONESHOT | + ((pdata->attn_polarity == RMI_ATTN_ACTIVE_HIGH) ? + IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW); + } else { + data->irq_flags = + (pdata->attn_polarity == RMI_ATTN_ACTIVE_HIGH) ? + IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING; + } + data->phys = rmi_phys; + + rmi_phys->data = data; + rmi_phys->dev = &spi->dev; + + rmi_phys->write = rmi_spi_v1_write; + rmi_phys->write_block = rmi_spi_v1_write_block; + rmi_phys->read = rmi_spi_v1_read; + rmi_phys->read_block = rmi_spi_v1_read_block; + rmi_phys->enable_device = enable_device; + rmi_phys->disable_device = disable_device; + data->set_page = rmi_spi_v1_set_page; + + rmi_phys->info.proto = spi_v1_proto_name; + + mutex_init(&data->page_mutex); + + dev_set_drvdata(&spi->dev, rmi_phys); + + pdata->spi_data.block_delay_us = pdata->spi_data.block_delay_us ? + pdata->spi_data.block_delay_us : RMI_SPI_BLOCK_DELAY_US; + pdata->spi_data.read_delay_us = pdata->spi_data.read_delay_us ? + pdata->spi_data.read_delay_us : RMI_SPI_BYTE_DELAY_US; + pdata->spi_data.write_delay_us = pdata->spi_data.write_delay_us ? + pdata->spi_data.write_delay_us : RMI_SPI_BYTE_DELAY_US; + pdata->spi_data.split_read_block_delay_us = + pdata->spi_data.split_read_block_delay_us ? + pdata->spi_data.split_read_block_delay_us : + RMI_SPI_BLOCK_DELAY_US; + pdata->spi_data.split_read_byte_delay_us = + pdata->spi_data.split_read_byte_delay_us ? + pdata->spi_data.split_read_byte_delay_us : + RMI_SPI_BYTE_DELAY_US; + + if (pdata->gpio_config) { + retval = pdata->gpio_config(pdata->gpio_data, true); + if (retval < 0) { + dev_err(&spi->dev, "Failed to setup GPIOs, code: %d.\n", + retval); + goto err_data; + } + } + + retval = rmi_spi_check_device(rmi_phys); + if (retval < 0) + goto err_gpio; + + /* check if this is an SPI v2 device */ + retval = rmi_spi_v1_read_block(rmi_phys, RMI_PROTOCOL_VERSION_ADDRESS, + buf, 2); + if (retval < 0) { + dev_err(&spi->dev, "failed to get SPI version number!\n"); + goto err_gpio; + } + dev_dbg(&spi->dev, "SPI version is %d", buf[0]); + + if (buf[0] == 1) { + /* SPIv2 */ + rmi_phys->write = rmi_spi_v2_write; + rmi_phys->write_block = rmi_spi_v2_write_block; + rmi_phys->read = rmi_spi_v2_read; + data->set_page = rmi_spi_v2_set_page; + + rmi_phys->info.proto = spi_v2_proto_name; + + if (pdata->attn_gpio > 0) { + init_completion(&data->irq_comp); + rmi_phys->read_block = rmi_spi_v2_split_read_block; + } else { + dev_warn(&spi->dev, "WARNING: SPI V2 detected, but no " + "attention GPIO was specified. This is unlikely" + " to work well.\n"); + rmi_phys->read_block = rmi_spi_v2_read_block; + } + } else if (buf[0] != 0) { + dev_err(&spi->dev, "Unrecognized SPI version %d.\n", buf[0]); + retval = -ENODEV; + goto err_gpio; + } + + retval = rmi_register_phys_device(rmi_phys); + if (retval) { + dev_err(&spi->dev, "failed to register physical driver\n"); + goto err_gpio; + } + + if (pdata->attn_gpio > 0) { + retval = setup_attn(data); + if (retval < 0) + goto err_unregister; + } else { + retval = setup_polling(data); + if (retval < 0) + goto err_unregister; + } + + dev_info(&spi->dev, "registered RMI SPI driver\n"); + return 0; + +err_unregister: + rmi_unregister_phys_device(rmi_phys); +err_gpio: + if (pdata->gpio_config) + pdata->gpio_config(pdata->gpio_data, false); +err_data: + kfree(data); +err_phys: + kfree(rmi_phys); + return retval; +} + +static int __devexit rmi_spi_remove(struct spi_device *spi) +{ + struct rmi_phys_device *phys = dev_get_drvdata(&spi->dev); + struct rmi_device_platform_data *pd = spi->dev.platform_data; + + disable_device(phys); + rmi_unregister_phys_device(phys); + kfree(phys->data); + kfree(phys); + + if (pd->gpio_config) + pd->gpio_config(pdata->gpio_data, false); + + return 0; +} + +static const struct spi_device_id rmi_id[] = { + { "rmi", 0 }, + { "rmi_spi", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, rmi_id); + +static struct spi_driver rmi_spi_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "rmi_spi", + }, + .id_table = rmi_id, + .probe = rmi_spi_probe, + .remove = __devexit_p(rmi_spi_remove), +}; + +static int __init rmi_spi_init(void) +{ + return spi_register_driver(&rmi_spi_driver); +} + +static void __exit rmi_spi_exit(void) +{ + spi_unregister_driver(&rmi_spi_driver); +} + +module_init(rmi_spi_init); +module_exit(rmi_spi_exit); + +MODULE_AUTHOR("Christopher Heiny "); +MODULE_DESCRIPTION("RMI SPI driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(RMI_DRIVER_VERSION); \ No newline at end of file diff --git a/include/linux/rmi.h b/include/linux/rmi.h new file mode 100755 index 000000000000..354eea9739a1 --- /dev/null +++ b/include/linux/rmi.h @@ -0,0 +1,609 @@ +/* + * Copyright (c) 2011 Synaptics Incorporated + * Copyright (c) 2011 Unixphere + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef _RMI_H +#define _RMI_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_RMI_DEBUG +#include +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + + +/* Permissions for sysfs attributes. Since the permissions policy will change + * on a global basis in the future, rather than edit all sysfs attrs everywhere + * in the driver (and risk screwing that up in the process), we use this handy + * set of #defines. That way when we change the policy for sysfs permissions, + * we only need to change them here. + */ +#define RMI_RO_ATTR S_IRUGO +#define RMI_RW_ATTR (S_IRUGO | S_IWUGO) +#define RMI_WO_ATTR S_IWUGO + +#define PDT_START_SCAN_LOCATION 0x00e9 + +enum rmi_attn_polarity { + RMI_ATTN_ACTIVE_LOW = 0, + RMI_ATTN_ACTIVE_HIGH = 1 +}; + +/** + * struct rmi_f11_axis_alignment - target axis alignment + * @swap_axes: set to TRUE if desired to swap x- and y-axis + * @flip_x: set to TRUE if desired to flip direction on x-axis + * @flip_y: set to TRUE if desired to flip direction on y-axis + */ +struct rmi_f11_2d_axis_alignment { + bool swap_axes; + bool flip_x; + bool flip_y; + int clip_X_low; + int clip_Y_low; + int clip_X_high; + int clip_Y_high; + int offset_X; + int offset_Y; + int rel_report_enabled; +}; + +/** + * struct rmi_f01_power - override default power management settings. + * + */ +enum rmi_f01_nosleep { + RMI_F01_NOSLEEP_DEFAULT = 0, + RMI_F01_NOSLEEP_OFF = 1, + RMI_F01_NOSLEEP_ON = 2 +}; + +struct rmi_f01_power_management { + enum rmi_f01_nosleep nosleep; + u8 wakeup_threshold; + u8 doze_holdoff; + u8 doze_interval; +}; + +struct rmi_f19_button_map { + unsigned char nbuttons; + unsigned char *map; +}; + +struct rmi_f1a_button_map { + unsigned char nbuttons; + unsigned char *map; +}; + +struct virtualbutton_map { + u16 x; + u16 y; + u16 width; + u16 height; + u16 code; +}; + +struct rmi_f11_virtualbutton_map { + u8 buttons; + struct virtualbutton_map *map; +}; +struct rmi_device_platform_data_spi { + int block_delay_us; + int split_read_block_delay_us; + int read_delay_us; + int write_delay_us; + int split_read_byte_delay_us; + int pre_delay_us; + int post_delay_us; + + void *cs_assert_data; + int (*cs_assert) (const void *cs_assert_data, const bool assert); +}; + +struct rmi_device_platform_data { + char *driver_name; + char *sensor_name; /* Used for diagnostics. */ + + int attn_gpio; + enum rmi_attn_polarity attn_polarity; + bool level_triggered; + void *gpio_data; + int (*gpio_config)(void *gpio_data, bool configure); + + int reset_delay_ms; + + struct rmi_device_platform_data_spi spi_data; + + /* function handler pdata */ + struct rmi_f01_power_management power_management; + struct rmi_f11_2d_axis_alignment axis_align; + struct rmi_f19_button_map *button_map; + struct rmi_f1a_button_map *f1a_button_map; + struct rmi_f11_virtualbutton_map *virtualbutton_map; + int (*init_hw)(void); +#ifdef CONFIG_PM + void *pm_data; + int (*pre_suspend) (const void *pm_data); + int (*post_resume) (const void *pm_data); +#endif +}; + +/** + * struct rmi_function_descriptor - RMI function base addresses + * @query_base_addr: The RMI Query base address + * @command_base_addr: The RMI Command base address + * @control_base_addr: The RMI Control base address + * @data_base_addr: The RMI Data base address + * @interrupt_source_count: The number of irqs this RMI function needs + * @function_number: The RMI function number + * + * This struct is used when iterating the Page Description Table. The addresses + * are 16-bit values to include the current page address. + * + */ +struct rmi_function_descriptor { + u16 query_base_addr; + u16 command_base_addr; + u16 control_base_addr; + u16 data_base_addr; + u8 interrupt_source_count; + u8 function_number; + u8 function_version; +}; + +struct rmi_function_container; +struct rmi_device; + +/** + * struct rmi_function_handler - an RMI function handler + * @func: The RMI function number + * @init: Callback for RMI function init + * @attention: Callback for RMI function attention + * @suspend: Callback for function suspend, returns 0 for success. + * @resume: Callback for RMI function resume, returns 0 for success. + * @remove: Callback for RMI function removal + * + * This struct describes the interface of an RMI function. These are + * registered to the bus using the rmi_register_function_driver() call. + * + */ +struct rmi_function_handler { + int func; + int (*init)(struct rmi_function_container *fc); + int (*config)(struct rmi_function_container *fc); + int (*reset)(struct rmi_function_container *fc); + int (*attention)(struct rmi_function_container *fc, u8 *irq_bits); +#ifdef CONFIG_PM + int (*suspend)(struct rmi_function_container *fc); + int (*resume)(struct rmi_function_container *fc); +#ifdef CONFIG_HAS_EARLYSUSPEND + int (*early_suspend)(struct rmi_function_container *fc); + int (*late_resume)(struct rmi_function_container *fc); +#endif +#endif + void (*remove)(struct rmi_function_container *fc); +}; + +/** + * struct rmi_function_container - an element in a function handler list + * @list: The list + * @fd: The function descriptor of the RMI function + * @rmi_dev: Pointer to the RMI device associated with this function container + * @fh: The callbacks connected to this function + * @num_of_irqs: The number of irqs needed by this function + * @irq_pos: The position in the irq bitfield this function holds + * @data: Private data pointer + * + */ +struct rmi_function_container { + struct list_head list; + + struct rmi_function_descriptor fd; + struct rmi_device *rmi_dev; + struct rmi_function_handler *fh; + struct device dev; + +#ifdef CONFIG_RMI4_DEBUG + struct dentry *debugfs_root; +#endif + + int num_of_irqs; + int irq_pos; + u8 *irq_mask; + + void *data; +}; +#define to_rmi_function_container(d) \ + container_of(d, struct rmi_function_container, dev); + + +/** + * struct rmi_driver - represents an RMI driver + * @driver: Device driver model driver + * @probe: Callback for device probe + * @remove: Callback for device removal + * @shutdown: Callback for device shutdown + * @irq_handler: Callback for handling irqs + * @fh_add: Callback for function handler add + * @fh_remove: Callback for function handler remove + * @get_func_irq_mask: Callback for calculating interrupt mask + * @store_irq_mask: Callback for storing and replacing interrupt mask + * @restore_irq_mask: Callback for restoring previously stored interrupt mask + * @data: Private data pointer + * + * The RMI driver implements a driver on the RMI bus. + * + */ +struct rmi_driver { + struct device_driver driver; + + int (*probe)(struct rmi_device *rmi_dev); + int (*remove)(struct rmi_device *rmi_dev); + void (*shutdown)(struct rmi_device *rmi_dev); + int (*irq_handler)(struct rmi_device *rmi_dev, int irq); + int (*reset_handler)(struct rmi_device *rmi_dev); + void (*fh_add)(struct rmi_device *rmi_dev, + struct rmi_function_handler *fh); + void (*fh_remove)(struct rmi_device *rmi_dev, + struct rmi_function_handler *fh); + u8* (*get_func_irq_mask)(struct rmi_device *rmi_dev, + struct rmi_function_container *fc); + int (*store_irq_mask)(struct rmi_device *rmi_dev, u8* new_interupts); + int (*restore_irq_mask)(struct rmi_device *rmi_dev); + void *data; +}; +#define to_rmi_driver(d) \ + container_of(d, struct rmi_driver, driver); + +/** struct rmi_phys_info - diagnostic information about the RMI physical + * device, used in the phys sysfs file. + * @proto String indicating the protocol being used. + * @tx_count Number of transmit operations. + * @tx_bytes Number of bytes transmitted. + * @tx_errs Number of errors encountered during transmit operations. + * @rx_count Number of receive operations. + * @rx_bytes Number of bytes received. + * @rx_errs Number of errors encountered during receive operations. + * @att_count Number of times ATTN assertions have been handled. + */ +struct rmi_phys_info { + char *proto; + long tx_count; + long tx_bytes; + long tx_errs; + long rx_count; + long rx_bytes; + long rx_errs; + long attn_count; +}; + +/** + * struct rmi_phys_device - represent an RMI physical device + * @dev: Pointer to the communication device, e.g. i2c or spi + * @rmi_dev: Pointer to the RMI device + * @write: Callback for write + * @write_block: Callback for writing a block of data + * @read: Callback for read + * @read_block: Callback for reading a block of data + * @data: Private data pointer + * + * The RMI physical device implements the glue between different communication + * buses such as I2C and SPI. + * + */ +struct rmi_phys_device { + struct device *dev; + struct rmi_device *rmi_dev; + + int (*write)(struct rmi_phys_device *phys, u16 addr, u8 data); + int (*write_block)(struct rmi_phys_device *phys, u16 addr, u8 *buf, + int len); + int (*read)(struct rmi_phys_device *phys, u16 addr, u8 *buf); + int (*read_block)(struct rmi_phys_device *phys, u16 addr, u8 *buf, + int len); + + int (*enable_device) (struct rmi_phys_device *phys); + void (*disable_device) (struct rmi_phys_device *phys); + + void *data; + + struct rmi_phys_info info; +}; + +/** + * struct rmi_device - represents an RMI device + * @dev: The device created for the RMI bus + * @number: Unique number for the device on the bus. + * @driver: Pointer to associated driver + * @phys: Pointer to the physical interface + * @early_suspend_handler: Pointers to early_suspend and late_resume, if + * configured. + * + * This structs represent an RMI device. + * + */ +struct rmi_device { + struct device dev; + int number; + + struct rmi_driver *driver; + struct rmi_phys_device *phys; + +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend_handler; +#endif +#ifdef CONFIG_RMI4_DEBUG + struct dentry *debugfs_root; +#endif +}; +#define to_rmi_device(d) container_of(d, struct rmi_device, dev); +#define to_rmi_platform_data(d) ((d)->phys->dev->platform_data); + +static inline void rmi_set_driverdata(struct rmi_device *d, void *data) +{ + dev_set_drvdata(&d->dev, data); +} + +static inline void *rmi_get_driverdata(struct rmi_device *d) +{ + return dev_get_drvdata(&d->dev); +} + +/** + * rmi_read - RMI read byte + * @d: Pointer to an RMI device + * @addr: The address to read from + * @buf: The read buffer + * + * Reads a byte of data using the underlaying physical protocol in to buf. It + * returns zero or a negative error code. + */ +static inline int rmi_read(struct rmi_device *d, u16 addr, u8 *buf) +{ + return d->phys->read(d->phys, addr, buf); +} + +/** + * rmi_read_block - RMI read block + * @d: Pointer to an RMI device + * @addr: The start address to read from + * @buf: The read buffer + * @len: Length of the read buffer + * + * Reads a block of byte data using the underlaying physical protocol in to buf. + * It returns the amount of bytes read or a negative error code. + */ +static inline int rmi_read_block(struct rmi_device *d, u16 addr, u8 *buf, + int len) +{ + return d->phys->read_block(d->phys, addr, buf, len); +} + +/** + * rmi_write - RMI write byte + * @d: Pointer to an RMI device + * @addr: The address to write to + * @data: The data to write + * + * Writes a byte from buf using the underlaying physical protocol. It + * returns zero or a negative error code. + */ +static inline int rmi_write(struct rmi_device *d, u16 addr, u8 data) +{ + return d->phys->write(d->phys, addr, data); +} + +/** + * rmi_write_block - RMI write block + * @d: Pointer to an RMI device + * @addr: The start address to write to + * @buf: The write buffer + * @len: Length of the write buffer + * + * Writes a block of byte data from buf using the underlaying physical protocol. + * It returns the amount of bytes written or a negative error code. + */ +static inline int rmi_write_block(struct rmi_device *d, u16 addr, u8 *buf, + int len) +{ + return d->phys->write_block(d->phys, addr, buf, len); +} + +/** + * rmi_register_driver - register rmi driver + * @driver: the driver to register + * + * This function registers an RMI driver to the RMI bus. + */ +int rmi_register_driver(struct rmi_driver *driver); + +/** + * rmi_unregister_driver - unregister rmi driver + * @driver: the driver to unregister + * + * This function unregisters an RMI driver to the RMI bus. + */ +void rmi_unregister_driver(struct rmi_driver *driver); + +/** + * rmi_register_phys_device - register a physical device connection + * @phys: the physical driver to register + * + * This function registers a physical driver to the RMI bus. These drivers + * provide a communication layer for the drivers connected to the bus, e.g. + * I2C, SPI and so on. + */ +int rmi_register_phys_device(struct rmi_phys_device *phys); + +/** + * rmi_unregister_phys_device - unregister a physical device connection + * @phys: the physical driver to unregister + * + * This function unregisters a physical driver from the RMI bus. + */ +void rmi_unregister_phys_device(struct rmi_phys_device *phys); + +/** + * rmi_register_function_driver - register an RMI function driver + * @fh: the function handler to register + * + * This function registers support for a new RMI function to the bus. All + * drivers on the bus will be notified of the presence of the new function + * driver. + */ +int rmi_register_function_driver(struct rmi_function_handler *fh); + +/** + * rmi_unregister_function_driver - unregister an RMI function driver + * @fh: the function handler to unregister + * + * This function unregisters a RMI function from the RMI bus. All drivers on + * the bus will be notified of the removal of a function driver. + */ +void rmi_unregister_function_driver(struct rmi_function_handler *fh); + +/** + * rmi_get_function_handler - get a pointer to specified RMI function + * @id: the RMI function id + * + * This function gets the specified RMI function handler from the list of + * supported functions. + */ +struct rmi_function_handler *rmi_get_function_handler(int id); + + +struct rmi_char_device; + +/** + * rmi_char_driver - a general driver that doesn't handle specific functions, + * operating outside the bus::sensor::functions + * @match: returns 1 if the driver wants to talk to the specified rmi_dev. + * + * All of the above are optional except driver and init which are required. + * + */ +struct rmi_char_driver { + struct device_driver driver; + + int (*match)(struct rmi_device *rmi_dev); + int (*init)(struct rmi_char_device *cd); + int (*attention)(struct rmi_char_device *cd, u8 *irq_bits); +#ifdef CONFIG_PM + int (*suspend)(struct rmi_char_device *cd); + int (*resume)(struct rmi_char_device *cd); +#ifdef CONFIG_HAS_EARLYSUSPEND + int (*early_suspend)(struct rmi_char_device *cd); + int (*late_resume)(struct rmi_char_device *cd); +#endif +#endif + void (*remove)(struct rmi_char_device *cd); + + struct list_head devices; +}; + +struct rmi_char_device { + struct list_head list; + + struct rmi_device *rmi_dev; + struct rmi_char_driver *driver; + struct device dev; + +#ifdef CONFIG_RMI4_DEBUG + struct dentry *debugfs_root; +#endif + + void *data; +}; +#define to_rmi_char_device(d) \ + container_of(d, struct rmi_char_device, dev) + +int rmi_register_character_driver(struct rmi_char_driver *char_driver); +int rmi_unregister_character_driver(struct rmi_char_driver *char_driver); + + +/* Helper fn to convert a byte array representing a short in the RMI + * endian-ness to a short in the native processor's specific endianness. + * We don't use ntohs/htons here because, well, we're not dealing with + * a pair of shorts. And casting dest to short* wouldn't work, because + * that would imply knowing the byte order of short in the first place. + */ +static inline void batohs(unsigned short *dest, unsigned char *src) +{ + *dest = src[1] * 0x100 + src[0]; +} + +/* Helper function to convert a short (in host processor endianess) to + * a byte array in the RMI endianess for shorts. See above comment for + * why we dont us htons or something like that. + */ +static inline void hstoba(unsigned char *dest, unsigned short src) +{ + dest[0] = src % 0x100; + dest[1] = src / 0x100; +} + +/* Utility routine to handle writes to read-only attributes. Hopefully + * this will never happen, but if the user does something stupid, we don't + * want to accept it quietly (which is what can happen if you just put NULL + * for the attribute's store function). + */ +static inline ssize_t rmi_store_error(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + dev_warn(dev, + "RMI4 WARNING: Attempt to write %d characters to read-only " + "attribute %s.", count, attr->attr.name); + return -EPERM; +} + +/* Utility routine to handle reads of write-only attributes. Hopefully + * this will never happen, but if the user does something stupid, we don't + * want to accept it quietly (which is what can happen if you just put NULL + * for the attribute's show function). + */ +static inline ssize_t rmi_show_error(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + dev_warn(dev, + "RMI4 WARNING: Attempt to read from write-only attribute %s.", + attr->attr.name); + return -EPERM; +} + +/* utility function for bit access of u8*'s */ +void u8_set_bit(u8 *target, int pos); +void u8_clear_bit(u8 *target, int pos); +bool u8_is_set(u8 *target, int pos); +bool u8_is_any_set(u8 *target, int size); +void u8_or(u8 *dest, u8* target1, u8* target2, int size); +void u8_and(u8 *dest, u8* target1, u8* target2, int size); +#endif -- 2.34.1