Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1691831 > unrolled thread
| Started by | Joel Stanley <joel@jms.id.au> |
|---|---|
| First post | 2017-07-19 17:10 +0200 |
| Last post | 2017-07-20 03:30 +0200 |
| Articles | 3 — 3 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: [RFC PATCH v2 3/3] pmbus: Add MAX31785 driver Joel Stanley <joel@jms.id.au> - 2017-07-19 17:10 +0200
Re: [RFC PATCH v2 3/3] pmbus: Add MAX31785 driver Guenter Roeck <linux@roeck-us.net> - 2017-07-19 20:20 +0200
Re: [RFC PATCH v2 3/3] pmbus: Add MAX31785 driver Andrew Jeffery <andrew@aj.id.au> - 2017-07-20 03:30 +0200
| From | Joel Stanley <joel@jms.id.au> |
|---|---|
| Date | 2017-07-19 17:10 +0200 |
| Subject | Re: [RFC PATCH v2 3/3] pmbus: Add MAX31785 driver |
| Message-ID | <u4YLV-1Q5-41@gated-at.bofh.it> |
On Tue, Jul 18, 2017 at 1:06 PM, Andrew Jeffery <andrew@aj.id.au> wrote:
> The driver features fan control and basic dual-tachometer support.
Say something about the hardware?
max31785 is a fancy fan controller with temp measurement, pwm, tach,
breakfast making from Maxim.
>
> The fan control makes use of the new virtual registers exposed by the
> pmbus core, mixing use of the default implementations with some
> overrides via the read/write handlers. FAN_COMMAND_1 on the MAX31785
> breaks the values into bands that depend on the RPM or PWM control mode.
>
> The dual tachometer feature is implemented in hardware with a TACHSEL
> input to indicate the rotor under measurement, and exposed on the bus by
> extending the READ_FAN_SPEED_1 word with two extra bytes*.
> The need to read the non-standard four-byte response leads to a cut-down
> implementation of i2c_smbus_xfer_emulated() included in the driver.
> Further, to expose the second rotor tachometer value to userspace,
> virtual fans are implemented by re-routing the FAN_CONFIG_1_2 register
> from the undefined (in hardware) pages 23-28 to the same register on
> pages 0-5, and similarly re-routing READ_FAN_SPEED_1 requests on 23-28
> to pages 0-5 but extracting the second word of the four-byte response.
>
> * The documentation recommends the slower rotor be associated with
> TACHSEL=0, which is the input used by the controller's closed-loop fan
> management.
>
> Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
> ---
> v1 -> v2:
>
> * Implement in terms of virtual registers
> * Add support for dual-tachometer readings through 'virtual fans' (unused pages)
>
> drivers/hwmon/pmbus/Kconfig | 10 ++
> drivers/hwmon/pmbus/Makefile | 1 +
> drivers/hwmon/pmbus/max31785.c | 372 +++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 383 insertions(+)
> create mode 100644 drivers/hwmon/pmbus/max31785.c
>
> diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
> index cad1229b7e17..5f2f3c6c7499 100644
> --- a/drivers/hwmon/pmbus/Kconfig
> +++ b/drivers/hwmon/pmbus/Kconfig
> @@ -95,6 +95,16 @@ config SENSORS_MAX20751
> This driver can also be built as a module. If so, the module will
> be called max20751.
>
> +config SENSORS_MAX31785
> + tristate "Maxim MAX31785 and compatibles"
> + default n
> + help
> + If you say yes here you get hardware monitoring support for Maxim
> + MAX31785.
> +
> + This driver can also be built as a module. If so, the module will
> + be called max31785.
> +
> config SENSORS_MAX34440
> tristate "Maxim MAX34440 and compatibles"
> default n
> diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
> index 562132054aaf..4ea548a8af46 100644
> --- a/drivers/hwmon/pmbus/Makefile
> +++ b/drivers/hwmon/pmbus/Makefile
> @@ -10,6 +10,7 @@ obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o
> obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o
> obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
> obj-$(CONFIG_SENSORS_MAX20751) += max20751.o
> +obj-$(CONFIG_SENSORS_MAX31785) += max31785.o
> obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
> obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
> obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o
> diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c
> new file mode 100644
> index 000000000000..1baa961f2eb1
> --- /dev/null
> +++ b/drivers/hwmon/pmbus/max31785.c
> @@ -0,0 +1,372 @@
> +/*
> + * Copyright (C) 2017 IBM Corp.
> + *
> + * 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.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include "pmbus.h"
> +
> +#define MFR_FAN_CONFIG_DUAL_TACH BIT(12)
> +#define MFR_FAN_CONFIG_TSFO BIT(9)
> +#define MFR_FAN_CONFIG_TACHO BIT(8)
> +
> +#define MAX31785_CAP_DUAL_TACH BIT(0)
> +
> +struct max31785 {
> + struct pmbus_driver_info info;
> +
> + u32 capabilities;
> +};
> +
> +enum max31785_regs {
> + PMBUS_MFR_FAN_CONFIG = 0xF1,
> + PMBUS_MFR_READ_FAN_PWM = 0xF3,
> + PMBUS_MFR_FAN_FAULT_LIMIT = 0xF5,
> + PMBUS_MFR_FAN_WARN_LIMIT = 0xF6,
> + PMBUS_MFR_FAN_PWM_AVG = 0xF8,
> +};
> +
> +#define to_max31785(_c) container_of(pmbus_get_info(_c), struct max31785, info)
> +
> +static int max31785_read_byte_data(struct i2c_client *client, int page,
> + int reg)
> +{
> + struct max31785 *chip = to_max31785(client);
> + int rv = -ENODATA;
I'd drop this.
> +
> + switch (reg) {
> + case PMBUS_VOUT_MODE:
> + if (page < 23)
> + return -ENODATA;
> +
> + return -ENOTSUPP;
> + case PMBUS_FAN_CONFIG_12:
> + if (page < 23)
> + return -ENODATA;
> +
> + if (WARN_ON(!(chip->capabilities & MAX31785_CAP_DUAL_TACH)))
Not sure about the WARN_ON here - won't users get spammed every time
someone reads a byte of data? When do we expect this case to happen?
> + return -ENOTSUPP;
> +
> + rv = pmbus_read_byte_data(client, page - 23, reg);
return pmbus_read_byte_data(client, page - 23, reg);
> + break;
> + }
> +
> + return rv;
return -ENODATA;
Or something like ESUPP or EINVAL?
Interestingly max34440_read_byte_data (may) return zero in this case.
> +}
> +
> +static long max31785_read_long_data(struct i2c_client *client, int page,
> + int reg)
> +{
> + unsigned char cmdbuf[1];
> + unsigned char rspbuf[4];
> + s64 rc;
This should be the same type as the function returns.
> +
> + struct i2c_msg msg[2] = {
> + {
> + .addr = client->addr,
> + .flags = 0,
> + .len = sizeof(cmdbuf),
> + .buf = cmdbuf,
> + },
> + {
> + .addr = client->addr,
> + .flags = I2C_M_RD,
> + .len = sizeof(rspbuf),
> + .buf = rspbuf,
> + },
> + };
> +
> + cmdbuf[0] = reg;
> +
> + rc = pmbus_set_page(client, page);
> + if (rc < 0)
> + return rc;
> +
> + rc = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
> + if (rc < 0)
> + return rc;
> +
> + rc = (rspbuf[0] << (0 * 8)) | (rspbuf[1] << (1 * 8)) |
> + (rspbuf[2] << (2 * 8)) | (rspbuf[3] << (3 * 8));
It's getting late, so I might have confused myself. But can you just do:
rc = le32_to_cpup(rspbuf);
> +
> + return rc;
> +}
> +
> +static int max31785_get_pwm(struct i2c_client *client, int page)
> +{
> + int config;
> + int command;
> +
> + config = pmbus_read_byte_data(client, page, PMBUS_FAN_CONFIG_12);
> + if (config < 0)
> + return config;
> +
> + command = pmbus_read_word_data(client, page, PMBUS_FAN_COMMAND_1);
> + if (command < 0)
> + return command;
> +
> + if (!(config & PB_FAN_1_RPM)) {
> + if (command >= 0x8000)
> + return 0;
> + else if (command >= 0x2711)
> + return 0x2710;
What are the magic numbers?
> + else
> + return command;
> + }
> +
> + return 0;
> +}
> +
> +static int max31785_get_pwm_mode(struct i2c_client *client, int page)
> +{
> + int config;
> + int command;
> +
> + config = pmbus_read_byte_data(client, page, PMBUS_FAN_CONFIG_12);
> + if (config < 0)
> + return config;
> +
> + command = pmbus_read_word_data(client, page, PMBUS_FAN_COMMAND_1);
> + if (command < 0)
> + return command;
> +
> + if (!(config & PB_FAN_1_RPM)) {
> + if (command >= 0x8000)
> + return 2;
> + else if (command >= 0x2711)
> + return 0;
> + else
> + return 1;
> + }
> +
> + return (command >= 0x8000) ? 2 : 1;
> +}
> +
> +static int max31785_read_word_data(struct i2c_client *client, int page,
> + int reg)
> +{
> + struct max31785 *chip = to_max31785(client);
> + long rv = -ENODATA;
> +
> + switch (reg) {
> + case PMBUS_READ_FAN_SPEED_1:
> + if (likely(page < 23))
> + return -ENODATA;
> +
> + if (WARN_ON(!(chip->capabilities & MAX31785_CAP_DUAL_TACH)))
> + return -ENOTSUPP;
> +
> + rv = max31785_read_long_data(client, page - 23, reg);
> + if (rv < 0)
> + return rv;
> +
> + rv = (rv >> 16) & 0xffff;
> + break;
> + case PMBUS_VIRT_PWM_1:
> + rv = max31785_get_pwm(client, page);
> + rv *= 255;
> + rv /= 100;
> + break;
> + case PMBUS_VIRT_PWM_ENABLE_1:
> + rv = max31785_get_pwm_mode(client, page);
> + break;
> + }
> +
> + if (rv == -ENODATA && page >= 23)
> + return -ENXIO;
> +
> + return rv;
> +}
> +
> +static const int max31785_pwm_modes[] = { 0x7fff, 0x2710, 0xffff };
> +
> +static int max31785_write_word_data(struct i2c_client *client, int page,
> + int reg, u16 word)
> +{
> + int rv = -ENODATA;
> +
> + if (page >= 23)
> + return -ENXIO;
> +
> + switch (reg) {
> + case PMBUS_VIRT_PWM_ENABLE_1:
> + if (word >= ARRAY_SIZE(max31785_pwm_modes))
> + return -ENOTSUPP;
> +
> + rv = pmbus_update_fan(client, page, 0, 0, PB_FAN_1_RPM,
> + max31785_pwm_modes[word]);
> + break;
> + }
> +
> + return rv;
> +}
> +
> +static int max31785_write_byte(struct i2c_client *client, int page, u8 value)
> +{
> + if (page < 23)
> + return -ENODATA;
> +
> + return -ENOTSUPP;
> +}
> +
> +static struct pmbus_driver_info max31785_info = {
> + .pages = 23,
> +
> + .write_word_data = max31785_write_word_data,
> + .read_byte_data = max31785_read_byte_data,
> + .read_word_data = max31785_read_word_data,
> + .write_byte = max31785_write_byte,
> +
> + /* RPM */
> + .format[PSC_FAN] = direct,
> + .m[PSC_FAN] = 1,
> + .b[PSC_FAN] = 0,
> + .R[PSC_FAN] = 0,
> + /* PWM */
> + .format[PSC_PWM] = direct,
> + .m[PSC_PWM] = 1,
> + .b[PSC_PWM] = 0,
> + .R[PSC_PWM] = 2,
> + .func[0] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
> + .func[1] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
> + .func[2] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
> + .func[3] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
> + .func[4] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
> + .func[5] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
> +
> + .format[PSC_TEMPERATURE] = direct,
> + .m[PSC_TEMPERATURE] = 1,
> + .b[PSC_TEMPERATURE] = 0,
> + .R[PSC_TEMPERATURE] = 2,
> + .func[6] = PMBUS_HAVE_STATUS_TEMP,
> + .func[7] = PMBUS_HAVE_STATUS_TEMP,
> + .func[8] = PMBUS_HAVE_STATUS_TEMP,
> + .func[9] = PMBUS_HAVE_STATUS_TEMP,
> + .func[10] = PMBUS_HAVE_STATUS_TEMP,
> + .func[11] = PMBUS_HAVE_STATUS_TEMP,
> + .func[12] = PMBUS_HAVE_STATUS_TEMP,
> + .func[13] = PMBUS_HAVE_STATUS_TEMP,
> + .func[14] = PMBUS_HAVE_STATUS_TEMP,
> + .func[15] = PMBUS_HAVE_STATUS_TEMP,
> + .func[16] = PMBUS_HAVE_STATUS_TEMP,
> +
> + .format[PSC_VOLTAGE_OUT] = direct,
> + .m[PSC_VOLTAGE_OUT] = 1,
> + .b[PSC_VOLTAGE_OUT] = 0,
> + .R[PSC_VOLTAGE_OUT] = 0,
> + .func[17] = PMBUS_HAVE_STATUS_VOUT,
> + .func[18] = PMBUS_HAVE_STATUS_VOUT,
> + .func[19] = PMBUS_HAVE_STATUS_VOUT,
> + .func[20] = PMBUS_HAVE_STATUS_VOUT,
> + .func[21] = PMBUS_HAVE_STATUS_VOUT,
> + .func[22] = PMBUS_HAVE_STATUS_VOUT,
> +};
> +
> +static int max31785_probe(struct i2c_client *client,
> + const struct i2c_device_id *id)
> +{
> + struct max31785 *chip;
> + int rv;
> + int i;
> +
> + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> + if (!chip)
> + return -ENOMEM;
> +
> + chip->info = max31785_info;
> +
> + /*
> + * Identify the chip firmware and configure capabilities.
> + *
> + * Bootstrap with i2c_smbus_*() calls as we need to understand the chip
> + * capabilities for before invoking pmbus_do_probe(). The pmbus_*()
> + * calls need access to memory that is only valid after
> + * pmbus_do_probe().
I think this is common enough in pmbus drivers that the comment is redundant.
> + */
> + rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 255);
> + if (rv < 0)
> + return rv;
> +
> + rv = i2c_smbus_read_word_data(client, PMBUS_MFR_REVISION);
> + if (rv < 0)
> + return rv;
> +
> + if ((rv & 0xff) == 0x40) {
DUAL_TACH_REV? Or a better name from the docs we have?
> + chip->capabilities |= MAX31785_CAP_DUAL_TACH;
> +
> + /*
> + * Punt the dual tach virtual fans to non-existent pages. This
> + * ensures the pwm attributes appear in a contiguous block
> + */
> + chip->info.pages = 29;
> + chip->info.func[23] = PMBUS_HAVE_FAN12;
> + chip->info.func[24] = PMBUS_HAVE_FAN12;
> + chip->info.func[25] = PMBUS_HAVE_FAN12;
> + chip->info.func[26] = PMBUS_HAVE_FAN12;
> + chip->info.func[27] = PMBUS_HAVE_FAN12;
> + chip->info.func[28] = PMBUS_HAVE_FAN12;
> + }
> +
> + rv = pmbus_do_probe(client, id, &chip->info);
> + if (rv < 0)
> + return rv;
> +
> + for (i = 0; i < max31785_info.pages; i++) {
> + int reg;
> +
> + if (!(max31785_info.func[i] & (PMBUS_HAVE_FAN12)))
> + continue;
> +
> + reg = pmbus_read_word_data(client, i, PMBUS_MFR_FAN_CONFIG);
> + if (reg < 0)
> + continue;
> +
> + /*
> + * XXX: Purely for RFC/testing purposes, don't ramp fans on fan
> + * or temperature sensor fault, or a failure to write
> + * FAN_COMMAND_1 inside a 10s window (watchdog mode).
> + *
> + * The TSFO bit controls both ramping on temp sensor failure
> + * AND whether FAN_COMMAND_1 is in watchdog mode.
> + */
> + reg |= MFR_FAN_CONFIG_TSFO | MFR_FAN_CONFIG_TACHO;
> + if (chip->capabilities & MAX31785_CAP_DUAL_TACH)
> + reg |= MFR_FAN_CONFIG_DUAL_TACH;
> + reg &= 0xffff;
> +
> + rv = pmbus_write_word_data(client, i, PMBUS_MFR_FAN_CONFIG,
> + reg);
> + }
> +
> + return 0;
> +}
> +
> +static const struct i2c_device_id max31785_id[] = {
> + { "max31785", 0 },
> + { },
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, max31785_id);
> +
> +static struct i2c_driver max31785_driver = {
> + .driver = {
> + .name = "max31785",
> + },
> + .probe = max31785_probe,
> + .remove = pmbus_do_remove,
> + .id_table = max31785_id,
> +};
> +
> +module_i2c_driver(max31785_driver);
> +
> +MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
> +MODULE_DESCRIPTION("PMBus driver for the Maxim MAX31785");
> +MODULE_LICENSE("GPL");
> --
> 2.11.0
>
[toc] | [next] | [standalone]
| From | Guenter Roeck <linux@roeck-us.net> |
|---|---|
| Date | 2017-07-19 20:20 +0200 |
| Message-ID | <u51JL-3Ue-7@gated-at.bofh.it> |
| In reply to | #1691831 |
On Thu, Jul 20, 2017 at 12:35:09AM +0930, Joel Stanley wrote:
> On Tue, Jul 18, 2017 at 1:06 PM, Andrew Jeffery <andrew@aj.id.au> wrote:
> > The driver features fan control and basic dual-tachometer support.
>
> Say something about the hardware?
>
> max31785 is a fancy fan controller with temp measurement, pwm, tach,
> breakfast making from Maxim.
>
>
> >
> > The fan control makes use of the new virtual registers exposed by the
> > pmbus core, mixing use of the default implementations with some
> > overrides via the read/write handlers. FAN_COMMAND_1 on the MAX31785
> > breaks the values into bands that depend on the RPM or PWM control mode.
> >
> > The dual tachometer feature is implemented in hardware with a TACHSEL
> > input to indicate the rotor under measurement, and exposed on the bus by
> > extending the READ_FAN_SPEED_1 word with two extra bytes*.
> > The need to read the non-standard four-byte response leads to a cut-down
> > implementation of i2c_smbus_xfer_emulated() included in the driver.
> > Further, to expose the second rotor tachometer value to userspace,
> > virtual fans are implemented by re-routing the FAN_CONFIG_1_2 register
> > from the undefined (in hardware) pages 23-28 to the same register on
> > pages 0-5, and similarly re-routing READ_FAN_SPEED_1 requests on 23-28
> > to pages 0-5 but extracting the second word of the four-byte response.
> >
> > * The documentation recommends the slower rotor be associated with
> > TACHSEL=0, which is the input used by the controller's closed-loop fan
> > management.
> >
> > Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
> > ---
> > v1 -> v2:
> >
> > * Implement in terms of virtual registers
> > * Add support for dual-tachometer readings through 'virtual fans' (unused pages)
> >
> > drivers/hwmon/pmbus/Kconfig | 10 ++
> > drivers/hwmon/pmbus/Makefile | 1 +
> > drivers/hwmon/pmbus/max31785.c | 372 +++++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 383 insertions(+)
> > create mode 100644 drivers/hwmon/pmbus/max31785.c
> >
> > diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
> > index cad1229b7e17..5f2f3c6c7499 100644
> > --- a/drivers/hwmon/pmbus/Kconfig
> > +++ b/drivers/hwmon/pmbus/Kconfig
> > @@ -95,6 +95,16 @@ config SENSORS_MAX20751
> > This driver can also be built as a module. If so, the module will
> > be called max20751.
> >
> > +config SENSORS_MAX31785
> > + tristate "Maxim MAX31785 and compatibles"
> > + default n
> > + help
> > + If you say yes here you get hardware monitoring support for Maxim
> > + MAX31785.
> > +
> > + This driver can also be built as a module. If so, the module will
> > + be called max31785.
> > +
> > config SENSORS_MAX34440
> > tristate "Maxim MAX34440 and compatibles"
> > default n
> > diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
> > index 562132054aaf..4ea548a8af46 100644
> > --- a/drivers/hwmon/pmbus/Makefile
> > +++ b/drivers/hwmon/pmbus/Makefile
> > @@ -10,6 +10,7 @@ obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o
> > obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o
> > obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
> > obj-$(CONFIG_SENSORS_MAX20751) += max20751.o
> > +obj-$(CONFIG_SENSORS_MAX31785) += max31785.o
> > obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
> > obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
> > obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o
> > diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c
> > new file mode 100644
> > index 000000000000..1baa961f2eb1
> > --- /dev/null
> > +++ b/drivers/hwmon/pmbus/max31785.c
> > @@ -0,0 +1,372 @@
> > +/*
> > + * Copyright (C) 2017 IBM Corp.
> > + *
> > + * 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.
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/init.h>
> > +#include <linux/err.h>
> > +#include <linux/i2c.h>
> > +#include "pmbus.h"
> > +
> > +#define MFR_FAN_CONFIG_DUAL_TACH BIT(12)
> > +#define MFR_FAN_CONFIG_TSFO BIT(9)
> > +#define MFR_FAN_CONFIG_TACHO BIT(8)
> > +
> > +#define MAX31785_CAP_DUAL_TACH BIT(0)
> > +
> > +struct max31785 {
> > + struct pmbus_driver_info info;
> > +
> > + u32 capabilities;
> > +};
> > +
> > +enum max31785_regs {
> > + PMBUS_MFR_FAN_CONFIG = 0xF1,
> > + PMBUS_MFR_READ_FAN_PWM = 0xF3,
> > + PMBUS_MFR_FAN_FAULT_LIMIT = 0xF5,
> > + PMBUS_MFR_FAN_WARN_LIMIT = 0xF6,
> > + PMBUS_MFR_FAN_PWM_AVG = 0xF8,
> > +};
> > +
> > +#define to_max31785(_c) container_of(pmbus_get_info(_c), struct max31785, info)
> > +
> > +static int max31785_read_byte_data(struct i2c_client *client, int page,
> > + int reg)
> > +{
> > + struct max31785 *chip = to_max31785(client);
> > + int rv = -ENODATA;
>
> I'd drop this.
>
> > +
> > + switch (reg) {
> > + case PMBUS_VOUT_MODE:
> > + if (page < 23)
> > + return -ENODATA;
> > +
> > + return -ENOTSUPP;
> > + case PMBUS_FAN_CONFIG_12:
> > + if (page < 23)
> > + return -ENODATA;
> > +
> > + if (WARN_ON(!(chip->capabilities & MAX31785_CAP_DUAL_TACH)))
>
> Not sure about the WARN_ON here - won't users get spammed every time
> someone reads a byte of data? When do we expect this case to happen?
>
Presumably this would be an implementation error (there is no page numbered 23
or larger if the bit is not set). This can't happen, thus the check is really
unnecessary and just bloats the code.
This also means that the 'capabilities' variable is also unecessary, since it
is only used to verify that the PMBus core really understood that there are
only 24 pages if MAX31785_CAP_DUAL_TACH is not set (and, to be _really_ sure,
it keeps verifying it over and over again).
> > + return -ENOTSUPP;
> > +
> > + rv = pmbus_read_byte_data(client, page - 23, reg);
>
> return pmbus_read_byte_data(client, page - 23, reg);
> > + break;
> > + }
> > +
> > + return rv;
>
> return -ENODATA;
>
-ENODATA: Calling code is expected to handle the command.
> Or something like ESUPP or EINVAL?
>
Only if you want to redefine the entire internal PMBus driver API.
> Interestingly max34440_read_byte_data (may) return zero in this case.
>
zero: No error. Command has been handled.
> > +}
> > +
> > +static long max31785_read_long_data(struct i2c_client *client, int page,
> > + int reg)
> > +{
> > + unsigned char cmdbuf[1];
> > + unsigned char rspbuf[4];
> > + s64 rc;
>
> This should be the same type as the function returns.
>
Also, long is likely s32 on 32-bit architectures, making it quite pointless
as return type. In this case, it may be better to handle data and error return
as separate parameters, such as in
static init max31785_read32(struct i2c_client *client, int page, int reg,
u32 *data)
> > +
> > + struct i2c_msg msg[2] = {
> > + {
> > + .addr = client->addr,
> > + .flags = 0,
> > + .len = sizeof(cmdbuf),
> > + .buf = cmdbuf,
> > + },
> > + {
> > + .addr = client->addr,
> > + .flags = I2C_M_RD,
> > + .len = sizeof(rspbuf),
> > + .buf = rspbuf,
> > + },
> > + };
> > +
> > + cmdbuf[0] = reg;
> > +
> > + rc = pmbus_set_page(client, page);
> > + if (rc < 0)
> > + return rc;
> > +
> > + rc = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
> > + if (rc < 0)
> > + return rc;
> > +
> > + rc = (rspbuf[0] << (0 * 8)) | (rspbuf[1] << (1 * 8)) |
> > + (rspbuf[2] << (2 * 8)) | (rspbuf[3] << (3 * 8));
>
> It's getting late, so I might have confused myself. But can you just do:
>
> rc = le32_to_cpup(rspbuf);
>
> > +
> > + return rc;
> > +}
> > +
> > +static int max31785_get_pwm(struct i2c_client *client, int page)
> > +{
> > + int config;
> > + int command;
> > +
> > + config = pmbus_read_byte_data(client, page, PMBUS_FAN_CONFIG_12);
> > + if (config < 0)
> > + return config;
> > +
> > + command = pmbus_read_word_data(client, page, PMBUS_FAN_COMMAND_1);
> > + if (command < 0)
> > + return command;
> > +
> > + if (!(config & PB_FAN_1_RPM)) {
> > + if (command >= 0x8000)
> > + return 0;
> > + else if (command >= 0x2711)
> > + return 0x2710;
>
> What are the magic numbers?
>
> > + else
unnecessary else
> > + return command;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int max31785_get_pwm_mode(struct i2c_client *client, int page)
> > +{
> > + int config;
> > + int command;
> > +
> > + config = pmbus_read_byte_data(client, page, PMBUS_FAN_CONFIG_12);
> > + if (config < 0)
> > + return config;
> > +
> > + command = pmbus_read_word_data(client, page, PMBUS_FAN_COMMAND_1);
> > + if (command < 0)
> > + return command;
> > +
> > + if (!(config & PB_FAN_1_RPM)) {
> > + if (command >= 0x8000)
> > + return 2;
> > + else if (command >= 0x2711)
> > + return 0;
> > + else
Unecessary else
> > + return 1;
> > + }
> > +
> > + return (command >= 0x8000) ? 2 : 1;
> > +}
> > +
> > +static int max31785_read_word_data(struct i2c_client *client, int page,
> > + int reg)
> > +{
> > + struct max31785 *chip = to_max31785(client);
> > + long rv = -ENODATA;
> > +
> > + switch (reg) {
> > + case PMBUS_READ_FAN_SPEED_1:
> > + if (likely(page < 23))
> > + return -ENODATA;
> > +
> > + if (WARN_ON(!(chip->capabilities & MAX31785_CAP_DUAL_TACH)))
> > + return -ENOTSUPP;
> > +
> > + rv = max31785_read_long_data(client, page - 23, reg);
> > + if (rv < 0)
> > + return rv;
> > +
> > + rv = (rv >> 16) & 0xffff;
> > + break;
> > + case PMBUS_VIRT_PWM_1:
> > + rv = max31785_get_pwm(client, page);
And ignore the error ?
> > + rv *= 255;
> > + rv /= 100;
max31785_get_pwm() returns 0..0x2710 (or 10000). This is translated to 0..25500.
Not really sure if that makes sense. We don't report pwm values in fractions of
100 to user space.
> > + break;
> > + case PMBUS_VIRT_PWM_ENABLE_1:
> > + rv = max31785_get_pwm_mode(client, page);
> > + break;
Not sure if PMBUS_VIRT_PWM_1 and PMBUS_VIRT_PWM_ENABLE_1 should return
-ENOTSUPP for pages 23+.
> > + }
> > +
> > + if (rv == -ENODATA && page >= 23)
> > + return -ENXIO;
That looks like another verification. Please drop.
> > +
> > + return rv;
> > +}
> > +
> > +static const int max31785_pwm_modes[] = { 0x7fff, 0x2710, 0xffff };
> > +
> > +static int max31785_write_word_data(struct i2c_client *client, int page,
> > + int reg, u16 word)
> > +{
> > + int rv = -ENODATA;
> > +
> > + if (page >= 23)
> > + return -ENXIO;
> > +
> > + switch (reg) {
> > + case PMBUS_VIRT_PWM_ENABLE_1:
> > + if (word >= ARRAY_SIZE(max31785_pwm_modes))
> > + return -ENOTSUPP;
That doesn't look correct. -EINVAL, possibly.
> > +
> > + rv = pmbus_update_fan(client, page, 0, 0, PB_FAN_1_RPM,
> > + max31785_pwm_modes[word]);
> > + break;
> > + }
> > +
> > + return rv;
> > +}
> > +
> > +static int max31785_write_byte(struct i2c_client *client, int page, u8 value)
> > +{
> > + if (page < 23)
> > + return -ENODATA;
> > +
> > + return -ENOTSUPP;
> > +}
> > +
> > +static struct pmbus_driver_info max31785_info = {
> > + .pages = 23,
> > +
> > + .write_word_data = max31785_write_word_data,
> > + .read_byte_data = max31785_read_byte_data,
> > + .read_word_data = max31785_read_word_data,
> > + .write_byte = max31785_write_byte,
> > +
> > + /* RPM */
> > + .format[PSC_FAN] = direct,
> > + .m[PSC_FAN] = 1,
> > + .b[PSC_FAN] = 0,
> > + .R[PSC_FAN] = 0,
> > + /* PWM */
> > + .format[PSC_PWM] = direct,
> > + .m[PSC_PWM] = 1,
> > + .b[PSC_PWM] = 0,
> > + .R[PSC_PWM] = 2,
> > + .func[0] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
> > + .func[1] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
> > + .func[2] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
> > + .func[3] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
> > + .func[4] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
> > + .func[5] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
> > +
> > + .format[PSC_TEMPERATURE] = direct,
> > + .m[PSC_TEMPERATURE] = 1,
> > + .b[PSC_TEMPERATURE] = 0,
> > + .R[PSC_TEMPERATURE] = 2,
> > + .func[6] = PMBUS_HAVE_STATUS_TEMP,
> > + .func[7] = PMBUS_HAVE_STATUS_TEMP,
> > + .func[8] = PMBUS_HAVE_STATUS_TEMP,
> > + .func[9] = PMBUS_HAVE_STATUS_TEMP,
> > + .func[10] = PMBUS_HAVE_STATUS_TEMP,
> > + .func[11] = PMBUS_HAVE_STATUS_TEMP,
> > + .func[12] = PMBUS_HAVE_STATUS_TEMP,
> > + .func[13] = PMBUS_HAVE_STATUS_TEMP,
> > + .func[14] = PMBUS_HAVE_STATUS_TEMP,
> > + .func[15] = PMBUS_HAVE_STATUS_TEMP,
> > + .func[16] = PMBUS_HAVE_STATUS_TEMP,
> > +
> > + .format[PSC_VOLTAGE_OUT] = direct,
> > + .m[PSC_VOLTAGE_OUT] = 1,
> > + .b[PSC_VOLTAGE_OUT] = 0,
> > + .R[PSC_VOLTAGE_OUT] = 0,
> > + .func[17] = PMBUS_HAVE_STATUS_VOUT,
> > + .func[18] = PMBUS_HAVE_STATUS_VOUT,
> > + .func[19] = PMBUS_HAVE_STATUS_VOUT,
> > + .func[20] = PMBUS_HAVE_STATUS_VOUT,
> > + .func[21] = PMBUS_HAVE_STATUS_VOUT,
> > + .func[22] = PMBUS_HAVE_STATUS_VOUT,
> > +};
> > +
> > +static int max31785_probe(struct i2c_client *client,
> > + const struct i2c_device_id *id)
> > +{
> > + struct max31785 *chip;
> > + int rv;
> > + int i;
> > +
> > + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> > + if (!chip)
> > + return -ENOMEM;
> > +
> > + chip->info = max31785_info;
> > +
> > + /*
> > + * Identify the chip firmware and configure capabilities.
> > + *
> > + * Bootstrap with i2c_smbus_*() calls as we need to understand the chip
> > + * capabilities for before invoking pmbus_do_probe(). The pmbus_*()
> > + * calls need access to memory that is only valid after
> > + * pmbus_do_probe().
>
> I think this is common enough in pmbus drivers that the comment is redundant.
>
> > + */
> > + rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 255);
> > + if (rv < 0)
> > + return rv;
> > +
> > + rv = i2c_smbus_read_word_data(client, PMBUS_MFR_REVISION);
> > + if (rv < 0)
> > + return rv;
> > +
> > + if ((rv & 0xff) == 0x40) {
>
> DUAL_TACH_REV? Or a better name from the docs we have?
>
> > + chip->capabilities |= MAX31785_CAP_DUAL_TACH;
> > +
> > + /*
> > + * Punt the dual tach virtual fans to non-existent pages. This
> > + * ensures the pwm attributes appear in a contiguous block
> > + */
> > + chip->info.pages = 29;
> > + chip->info.func[23] = PMBUS_HAVE_FAN12;
> > + chip->info.func[24] = PMBUS_HAVE_FAN12;
> > + chip->info.func[25] = PMBUS_HAVE_FAN12;
> > + chip->info.func[26] = PMBUS_HAVE_FAN12;
> > + chip->info.func[27] = PMBUS_HAVE_FAN12;
> > + chip->info.func[28] = PMBUS_HAVE_FAN12;
> > + }
> > +
> > + rv = pmbus_do_probe(client, id, &chip->info);
> > + if (rv < 0)
> > + return rv;
> > +
> > + for (i = 0; i < max31785_info.pages; i++) {
> > + int reg;
> > +
> > + if (!(max31785_info.func[i] & (PMBUS_HAVE_FAN12)))
> > + continue;
> > +
> > + reg = pmbus_read_word_data(client, i, PMBUS_MFR_FAN_CONFIG);
> > + if (reg < 0)
> > + continue;
> > +
> > + /*
> > + * XXX: Purely for RFC/testing purposes, don't ramp fans on fan
> > + * or temperature sensor fault, or a failure to write
> > + * FAN_COMMAND_1 inside a 10s window (watchdog mode).
> > + *
> > + * The TSFO bit controls both ramping on temp sensor failure
> > + * AND whether FAN_COMMAND_1 is in watchdog mode.
> > + */
> > + reg |= MFR_FAN_CONFIG_TSFO | MFR_FAN_CONFIG_TACHO;
> > + if (chip->capabilities & MAX31785_CAP_DUAL_TACH)
> > + reg |= MFR_FAN_CONFIG_DUAL_TACH;
> > + reg &= 0xffff;
> > +
> > + rv = pmbus_write_word_data(client, i, PMBUS_MFR_FAN_CONFIG,
> > + reg);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static const struct i2c_device_id max31785_id[] = {
> > + { "max31785", 0 },
> > + { },
> > +};
> > +
> > +MODULE_DEVICE_TABLE(i2c, max31785_id);
> > +
> > +static struct i2c_driver max31785_driver = {
> > + .driver = {
> > + .name = "max31785",
> > + },
> > + .probe = max31785_probe,
> > + .remove = pmbus_do_remove,
> > + .id_table = max31785_id,
> > +};
> > +
> > +module_i2c_driver(max31785_driver);
> > +
> > +MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
> > +MODULE_DESCRIPTION("PMBus driver for the Maxim MAX31785");
> > +MODULE_LICENSE("GPL");
> > --
> > 2.11.0
> >
[toc] | [prev] | [next] | [standalone]
| From | Andrew Jeffery <andrew@aj.id.au> |
|---|---|
| Date | 2017-07-20 03:30 +0200 |
| Message-ID | <u58rU-8rs-5@gated-at.bofh.it> |
| In reply to | #1692080 |
[Multipart message — attachments visible in raw view] — view raw
T24gV2VkLCAyMDE3LTA3LTE5IGF0IDExOjExIC0wNzAwLCBHdWVudGVyIFJvZWNrIHdyb3RlOgo+ IE9uIFRodSwgSnVsIDIwLCAyMDE3IGF0IDEyOjM1OjA5QU0gKzA5MzAsIEpvZWwgU3RhbmxleSB3 cm90ZToKPiA+ID4gPiBPbiBUdWUsIEp1bCAxOCwgMjAxNyBhdCAxOjA2IFBNLCBBbmRyZXcgSmVm ZmVyeSA8YW5kcmV3QGFqLmlkLmF1PiB3cm90ZToKPiA+ID4gVGhlIGRyaXZlciBmZWF0dXJlcyBm YW4gY29udHJvbCBhbmQgYmFzaWMgZHVhbC10YWNob21ldGVyIHN1cHBvcnQuCj4gPiAKPiA+IFNh eSBzb21ldGhpbmcgYWJvdXQgdGhlIGhhcmR3YXJlPwo+ID4gCj4gPiDCoG1heDMxNzg1IGlzIGEg ZmFuY3kgZmFuIGNvbnRyb2xsZXIgd2l0aCB0ZW1wIG1lYXN1cmVtZW50LCBwd20sIHRhY2gsCj4g PiBicmVha2Zhc3QgbWFraW5nIGZyb20gTWF4aW0uCj4gPiAKPiA+IAo+ID4gPiAKPiA+ID4gVGhl IGZhbiBjb250cm9sIG1ha2VzIHVzZSBvZiB0aGUgbmV3IHZpcnR1YWwgcmVnaXN0ZXJzIGV4cG9z ZWQgYnkgdGhlCj4gPiA+IHBtYnVzIGNvcmUsIG1peGluZyB1c2Ugb2YgdGhlIGRlZmF1bHQgaW1w bGVtZW50YXRpb25zIHdpdGggc29tZQo+ID4gPiBvdmVycmlkZXMgdmlhIHRoZSByZWFkL3dyaXRl IGhhbmRsZXJzLiBGQU5fQ09NTUFORF8xIG9uIHRoZSBNQVgzMTc4NQo+ID4gPiBicmVha3MgdGhl IHZhbHVlcyBpbnRvIGJhbmRzIHRoYXQgZGVwZW5kIG9uIHRoZSBSUE0gb3IgUFdNIGNvbnRyb2wg bW9kZS4KPiA+ID4gCj4gPiA+IFRoZSBkdWFsIHRhY2hvbWV0ZXIgZmVhdHVyZSBpcyBpbXBsZW1l bnRlZCBpbiBoYXJkd2FyZSB3aXRoIGEgVEFDSFNFTAo+ID4gPiBpbnB1dCB0byBpbmRpY2F0ZSB0 aGUgcm90b3IgdW5kZXIgbWVhc3VyZW1lbnQsIGFuZCBleHBvc2VkIG9uIHRoZSBidXMgYnkKPiA+ ID4gZXh0ZW5kaW5nIHRoZSBSRUFEX0ZBTl9TUEVFRF8xIHdvcmQgd2l0aCB0d28gZXh0cmEgYnl0 ZXMqLgo+ID4gPiBUaGUgbmVlZCB0byByZWFkIHRoZSBub24tc3RhbmRhcmQgZm91ci1ieXRlIHJl c3BvbnNlIGxlYWRzIHRvIGEgY3V0LWRvd24KPiA+ID4gaW1wbGVtZW50YXRpb24gb2YgaTJjX3Nt YnVzX3hmZXJfZW11bGF0ZWQoKSBpbmNsdWRlZCBpbiB0aGUgZHJpdmVyLgo+ID4gPiBGdXJ0aGVy LCB0byBleHBvc2UgdGhlIHNlY29uZCByb3RvciB0YWNob21ldGVyIHZhbHVlIHRvIHVzZXJzcGFj ZSwKPiA+ID4gdmlydHVhbCBmYW5zIGFyZSBpbXBsZW1lbnRlZCBieSByZS1yb3V0aW5nIHRoZSBG QU5fQ09ORklHXzFfMiByZWdpc3Rlcgo+ID4gPiBmcm9tIHRoZSB1bmRlZmluZWQgKGluIGhhcmR3 YXJlKSBwYWdlcyAyMy0yOCB0byB0aGUgc2FtZSByZWdpc3RlciBvbgo+ID4gPiBwYWdlcyAwLTUs IGFuZCBzaW1pbGFybHkgcmUtcm91dGluZyBSRUFEX0ZBTl9TUEVFRF8xIHJlcXVlc3RzIG9uIDIz LTI4Cj4gPiA+IHRvIHBhZ2VzIDAtNSBidXQgZXh0cmFjdGluZyB0aGUgc2Vjb25kIHdvcmQgb2Yg dGhlIGZvdXItYnl0ZSByZXNwb25zZS4KPiA+ID4gCj4gPiA+ICogVGhlIGRvY3VtZW50YXRpb24g cmVjb21tZW5kcyB0aGUgc2xvd2VyIHJvdG9yIGJlIGFzc29jaWF0ZWQgd2l0aAo+ID4gPiBUQUNI U0VMPTAsIHdoaWNoIGlzIHRoZSBpbnB1dCB1c2VkIGJ5IHRoZSBjb250cm9sbGVyJ3MgY2xvc2Vk LWxvb3AgZmFuCj4gPiA+IG1hbmFnZW1lbnQuCj4gPiA+IAo+ID4gPiA+ID4gPiBTaWduZWQtb2Zm LWJ5OiBBbmRyZXcgSmVmZmVyeSA8YW5kcmV3QGFqLmlkLmF1Pgo+ID4gPiAtLS0KPiA+ID4gdjEg LT4gdjI6Cj4gPiA+IAo+ID4gPiAqIEltcGxlbWVudCBpbiB0ZXJtcyBvZiB2aXJ0dWFsIHJlZ2lz dGVycwo+ID4gPiAqIEFkZCBzdXBwb3J0IGZvciBkdWFsLXRhY2hvbWV0ZXIgcmVhZGluZ3MgdGhy b3VnaCAndmlydHVhbCBmYW5zJyAodW51c2VkIHBhZ2VzKQo+ID4gPiAKPiA+ID4gwqBkcml2ZXJz L2h3bW9uL3BtYnVzL0tjb25maWfCoMKgwqDCoHzCoMKgMTAgKysKPiA+ID4gwqBkcml2ZXJzL2h3 bW9uL3BtYnVzL01ha2VmaWxlwqDCoMKgfMKgwqDCoDEgKwo+ID4gPiDCoGRyaXZlcnMvaHdtb24v cG1idXMvbWF4MzE3ODUuYyB8IDM3MiArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysr KysrKysrKwo+ID4gPiDCoDMgZmlsZXMgY2hhbmdlZCwgMzgzIGluc2VydGlvbnMoKykKPiA+ID4g wqBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9od21vbi9wbWJ1cy9tYXgzMTc4NS5jCj4gPiA+ IAo+ID4gPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9od21vbi9wbWJ1cy9LY29uZmlnIGIvZHJpdmVy cy9od21vbi9wbWJ1cy9LY29uZmlnCj4gPiA+IGluZGV4IGNhZDEyMjliN2UxNy4uNWYyZjNjNmM3 NDk5IDEwMDY0NAo+ID4gPiAtLS0gYS9kcml2ZXJzL2h3bW9uL3BtYnVzL0tjb25maWcKPiA+ID4g KysrIGIvZHJpdmVycy9od21vbi9wbWJ1cy9LY29uZmlnCj4gPiA+IEBAIC05NSw2ICs5NSwxNiBA QCBjb25maWcgU0VOU09SU19NQVgyMDc1MQo+ID4gPiDCoMKgwqDCoMKgwqDCoMKgwqDCoFRoaXMg ZHJpdmVyIGNhbiBhbHNvIGJlIGJ1aWx0IGFzIGEgbW9kdWxlLiBJZiBzbywgdGhlIG1vZHVsZSB3 aWxsCj4gPiA+IMKgwqDCoMKgwqDCoMKgwqDCoMKgYmUgY2FsbGVkIG1heDIwNzUxLgo+ID4gPiAK PiA+ID4gK2NvbmZpZyBTRU5TT1JTX01BWDMxNzg1Cj4gPiA+ICvCoMKgwqDCoMKgwqDCoHRyaXN0 YXRlICJNYXhpbSBNQVgzMTc4NSBhbmQgY29tcGF0aWJsZXMiCj4gPiA+ICvCoMKgwqDCoMKgwqDC oGRlZmF1bHQgbgo+ID4gPiArwqDCoMKgwqDCoMKgwqBoZWxwCj4gPiA+ICvCoMKgwqDCoMKgwqDC oMKgwqBJZiB5b3Ugc2F5IHllcyBoZXJlIHlvdSBnZXQgaGFyZHdhcmUgbW9uaXRvcmluZyBzdXBw b3J0IGZvciBNYXhpbQo+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgTUFYMzE3ODUuCj4gPiA+ICsK PiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoFRoaXMgZHJpdmVyIGNhbiBhbHNvIGJlIGJ1aWx0IGFz IGEgbW9kdWxlLiBJZiBzbywgdGhlIG1vZHVsZSB3aWxsCj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKg wqBiZSBjYWxsZWQgbWF4MzE3ODUuCj4gPiA+ICsKPiA+ID4gwqBjb25maWcgU0VOU09SU19NQVgz NDQ0MAo+ID4gPiDCoMKgwqDCoMKgwqDCoMKgdHJpc3RhdGUgIk1heGltIE1BWDM0NDQwIGFuZCBj b21wYXRpYmxlcyIKPiA+ID4gwqDCoMKgwqDCoMKgwqDCoGRlZmF1bHQgbgo+ID4gPiBkaWZmIC0t Z2l0IGEvZHJpdmVycy9od21vbi9wbWJ1cy9NYWtlZmlsZSBiL2RyaXZlcnMvaHdtb24vcG1idXMv TWFrZWZpbGUKPiA+ID4gaW5kZXggNTYyMTMyMDU0YWFmLi40ZWE1NDhhOGFmNDYgMTAwNjQ0Cj4g PiA+IC0tLSBhL2RyaXZlcnMvaHdtb24vcG1idXMvTWFrZWZpbGUKPiA+ID4gKysrIGIvZHJpdmVy cy9od21vbi9wbWJ1cy9NYWtlZmlsZQo+ID4gPiBAQCAtMTAsNiArMTAsNyBAQCBvYmotJChDT05G SUdfU0VOU09SU19MVEMyOTc4KSArPSBsdGMyOTc4Lm8KPiA+ID4gwqBvYmotJChDT05GSUdfU0VO U09SU19MVEMzODE1KcKgwqArPSBsdGMzODE1Lm8KPiA+ID4gwqBvYmotJChDT05GSUdfU0VOU09S U19NQVgxNjA2NCkgKz0gbWF4MTYwNjQubwo+ID4gPiDCoG9iai0kKENPTkZJR19TRU5TT1JTX01B WDIwNzUxKSArPSBtYXgyMDc1MS5vCj4gPiA+ICtvYmotJChDT05GSUdfU0VOU09SU19NQVgzMTc4 NSkgKz0gbWF4MzE3ODUubwo+ID4gPiDCoG9iai0kKENPTkZJR19TRU5TT1JTX01BWDM0NDQwKSAr PSBtYXgzNDQ0MC5vCj4gPiA+IMKgb2JqLSQoQ09ORklHX1NFTlNPUlNfTUFYODY4OCnCoMKgKz0g bWF4ODY4OC5vCj4gPiA+IMKgb2JqLSQoQ09ORklHX1NFTlNPUlNfVFBTNDA0MjIpICs9IHRwczQw NDIyLm8KPiA+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvaHdtb24vcG1idXMvbWF4MzE3ODUuYyBi L2RyaXZlcnMvaHdtb24vcG1idXMvbWF4MzE3ODUuYwo+ID4gPiBuZXcgZmlsZSBtb2RlIDEwMDY0 NAo+ID4gPiBpbmRleCAwMDAwMDAwMDAwMDAuLjFiYWE5NjFmMmViMQo+ID4gPiAtLS0gL2Rldi9u dWxsCj4gPiA+ICsrKyBiL2RyaXZlcnMvaHdtb24vcG1idXMvbWF4MzE3ODUuYwo+ID4gPiBAQCAt MCwwICsxLDM3MiBAQAo+ID4gPiArLyoKPiA+ID4gKyAqIENvcHlyaWdodCAoQykgMjAxNyBJQk0g Q29ycC4KPiA+ID4gKyAqCj4gPiA+ICsgKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsg eW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeQo+ID4gPiArICogaXQgdW5kZXIg dGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQg YnkKPiA+ID4gKyAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9u IDIgb2YgdGhlIExpY2Vuc2UsIG9yCj4gPiA+ICsgKiAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRl ciB2ZXJzaW9uLgo+ID4gPiArICovCj4gPiA+ICsKPiA+ID4gKyNpbmNsdWRlIDxsaW51eC9rZXJu ZWwuaD4KPiA+ID4gKyNpbmNsdWRlIDxsaW51eC9tb2R1bGUuaD4KPiA+ID4gKyNpbmNsdWRlIDxs aW51eC9pbml0Lmg+Cj4gPiA+ICsjaW5jbHVkZSA8bGludXgvZXJyLmg+Cj4gPiA+ICsjaW5jbHVk ZSA8bGludXgvaTJjLmg+Cj4gPiA+ICsjaW5jbHVkZSAicG1idXMuaCIKPiA+ID4gKwo+ID4gPiAr I2RlZmluZSBNRlJfRkFOX0NPTkZJR19EVUFMX1RBQ0jCoMKgwqDCoMKgwqDCoEJJVCgxMikKPiA+ ID4gKyNkZWZpbmUgTUZSX0ZBTl9DT05GSUdfVFNGT8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoEJJ VCg5KQo+ID4gPiArI2RlZmluZSBNRlJfRkFOX0NPTkZJR19UQUNIT8KgwqDCoMKgwqDCoMKgwqDC oMKgwqBCSVQoOCkKPiA+ID4gKwo+ID4gPiArI2RlZmluZSBNQVgzMTc4NV9DQVBfRFVBTF9UQUNI wqDCoMKgwqDCoMKgwqDCoMKgQklUKDApCj4gPiA+ICsKPiA+ID4gK3N0cnVjdCBtYXgzMTc4NSB7 Cj4gPiA+ICvCoMKgwqDCoMKgwqDCoHN0cnVjdCBwbWJ1c19kcml2ZXJfaW5mbyBpbmZvOwo+ID4g PiArCj4gPiA+ICvCoMKgwqDCoMKgwqDCoHUzMiBjYXBhYmlsaXRpZXM7Cj4gPiA+ICt9Owo+ID4g PiArCj4gPiA+ICtlbnVtIG1heDMxNzg1X3JlZ3Mgewo+ID4gPiArwqDCoMKgwqDCoMKgwqBQTUJV U19NRlJfRkFOX0NPTkZJR8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoD0gMHhGMSwKPiA+ID4gK8Kg wqDCoMKgwqDCoMKgUE1CVVNfTUZSX1JFQURfRkFOX1BXTcKgwqDCoMKgwqDCoMKgwqDCoMKgPSAw eEYzLAo+ID4gPiArwqDCoMKgwqDCoMKgwqBQTUJVU19NRlJfRkFOX0ZBVUxUX0xJTUlUwqDCoMKg wqDCoMKgwqA9IDB4RjUsCj4gPiA+ICvCoMKgwqDCoMKgwqDCoFBNQlVTX01GUl9GQU5fV0FSTl9M SU1JVMKgwqDCoMKgwqDCoMKgwqA9IDB4RjYsCj4gPiA+ICvCoMKgwqDCoMKgwqDCoFBNQlVTX01G Ul9GQU5fUFdNX0FWR8KgwqDCoMKgwqDCoMKgwqDCoMKgwqA9IDB4RjgsCj4gPiA+ICt9Owo+ID4g PiArCj4gPiA+ICsjZGVmaW5lIHRvX21heDMxNzg1KF9jKSBjb250YWluZXJfb2YocG1idXNfZ2V0 X2luZm8oX2MpLCBzdHJ1Y3QgbWF4MzE3ODUsIGluZm8pCj4gPiA+ICsKPiA+ID4gK3N0YXRpYyBp bnQgbWF4MzE3ODVfcmVhZF9ieXRlX2RhdGEoc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCwgaW50 IHBhZ2UsCj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoGludCByZWcpCj4gPiA+ICt7Cj4gPiA+ICvCoMKgwqDC oMKgwqDCoHN0cnVjdCBtYXgzMTc4NSAqY2hpcCA9IHRvX21heDMxNzg1KGNsaWVudCk7Cj4gPiA+ ICvCoMKgwqDCoMKgwqDCoGludCBydiA9IC1FTk9EQVRBOwo+ID4gCj4gPiBJJ2QgZHJvcCB0aGlz Lgo+ID4gCj4gPiA+ICsKPiA+ID4gK8KgwqDCoMKgwqDCoMKgc3dpdGNoIChyZWcpIHsKPiA+ID4g K8KgwqDCoMKgwqDCoMKgY2FzZSBQTUJVU19WT1VUX01PREU6Cj4gPiA+ICvCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqBpZiAocGFnZSA8IDIzKQo+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoHJldHVybiAtRU5PREFUQTsKPiA+ID4gKwo+ID4g PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgcmV0dXJuIC1FTk9UU1VQUDsKPiA+ID4g K8KgwqDCoMKgwqDCoMKgY2FzZSBQTUJVU19GQU5fQ09ORklHXzEyOgo+ID4gPiArwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgaWYgKHBhZ2UgPCAyMykKPiA+ID4gK8KgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqByZXR1cm4gLUVOT0RBVEE7Cj4gPiA+ICsK PiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoGlmIChXQVJOX09OKCEoY2hpcC0+ Y2FwYWJpbGl0aWVzICYgTUFYMzE3ODVfQ0FQX0RVQUxfVEFDSCkpKQo+ID4gCj4gPiBOb3Qgc3Vy ZSBhYm91dCB0aGUgV0FSTl9PTiBoZXJlIC0gd29uJ3QgdXNlcnMgZ2V0IHNwYW1tZWQgZXZlcnkg dGltZQo+ID4gc29tZW9uZSByZWFkcyBhIGJ5dGUgb2YgZGF0YT8gV2hlbiBkbyB3ZSBleHBlY3Qg dGhpcyBjYXNlIHRvIGhhcHBlbj8KPiA+IAo+IAo+IFByZXN1bWFibHkgdGhpcyB3b3VsZCBiZSBh biBpbXBsZW1lbnRhdGlvbiBlcnJvciAodGhlcmUgaXMgbm8gcGFnZSBudW1iZXJlZCAyMwo+IG9y IGxhcmdlciBpZiB0aGUgYml0IGlzIG5vdCBzZXQpLiBUaGlzIGNhbid0IGhhcHBlbiwgdGh1cyB0 aGUgY2hlY2sgaXMgcmVhbGx5Cj4gdW5uZWNlc3NhcnkgYW5kIGp1c3QgYmxvYXRzIHRoZSBjb2Rl Lgo+IAo+IFRoaXMgYWxzbyBtZWFucyB0aGF0IHRoZSAnY2FwYWJpbGl0aWVzJyB2YXJpYWJsZSBp cyBhbHNvIHVuZWNlc3NhcnksIHNpbmNlIGl0Cj4gaXMgb25seSB1c2VkIHRvIHZlcmlmeSB0aGF0 IHRoZSBQTUJ1cyBjb3JlIHJlYWxseSB1bmRlcnN0b29kIHRoYXQgdGhlcmUgYXJlCj4gb25seSAy NCBwYWdlcyBpZiBNQVgzMTc4NV9DQVBfRFVBTF9UQUNIIGlzIG5vdCBzZXQgKGFuZCwgdG8gYmUg X3JlYWxseV8gc3VyZSwKPiBpdCBrZWVwcyB2ZXJpZnlpbmcgaXQgb3ZlciBhbmQgb3ZlciBhZ2Fp bikuCgpUaGlzIHdhcyBtYWlubHkgc29tZSAob3ZlcnplYWxvdXMpIHNhbml0eSBjaGVja2luZyB3 aGlsc3QgSSB3YXMKZGV2ZWxvcGluZyB0aGUgZHJpdmVyIChJIGhhdmUgYWxzbyBkZXZlbG9wZWQg YSBQTUJ1cyBRRU1VIG1vZGVsIGluIHRoZQpwcm9jZXNzIC0gd2FzIHRyeWluZyB0byBjYXRjaCB0 aGlua29zIGluIG9uIGJvdGggc2lkZXMpLiBBcyB5b3UgcG9pbnQKb3V0IGl0J3MgdW5uZWNlc3Nh cnkgaWYgZXZlcnl0aGluZyB3b3JrcyBhcyBpdCBzaG91bGQuCgpJJ2xsIHJlbW92ZSB0aGlzIGFu ZCBvdGhlciB1bm5lY2Vzc2FyeSB2ZXJpZmljYXRpb25zIGJlZm9yZSBwb3N0aW5nIHRoZQpuZXh0 IHJldmlzaW9uLgoKPiAKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqByZXR1cm4gLUVOT1RTVVBQOwo+ID4gPiArCj4gPiA+ICvCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqBydiA9IHBtYnVzX3JlYWRfYnl0ZV9kYXRhKGNsaWVudCwgcGFnZSAt IDIzLCByZWcpOwo+ID4gCj4gPiByZXR1cm4gcG1idXNfcmVhZF9ieXRlX2RhdGEoY2xpZW50LCBw YWdlIC0gMjMsIHJlZyk7Cj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqBicmVh azsKPiA+ID4gK8KgwqDCoMKgwqDCoMKgfQo+ID4gPiArCj4gPiA+ICvCoMKgwqDCoMKgwqDCoHJl dHVybiBydjsKPiA+IAo+ID4gcmV0dXJuIC1FTk9EQVRBOwo+ID4gCj4gCj4gLUVOT0RBVEE6IENh bGxpbmcgY29kZSBpcyBleHBlY3RlZCB0byBoYW5kbGUgdGhlIGNvbW1hbmQuCj4gCj4gPiBPciBz b21ldGhpbmcgbGlrZSBFU1VQUCBvciBFSU5WQUw/Cj4gPiAKPiAKPiBPbmx5IGlmIHlvdSB3YW50 IHRvIHJlZGVmaW5lIHRoZSBlbnRpcmUgaW50ZXJuYWwgUE1CdXMgZHJpdmVyIEFQSS4KPiAKPiA+ IEludGVyZXN0aW5nbHkgbWF4MzQ0NDBfcmVhZF9ieXRlX2RhdGEgKG1heSkgcmV0dXJuIHplcm8g aW4gdGhpcyBjYXNlLgo+ID4gCj4gCj4gemVybzogTm8gZXJyb3IuIENvbW1hbmQgaGFzIGJlZW4g aGFuZGxlZC4KPiAKPiA+ID4gK30KPiA+ID4gKwo+ID4gPiArc3RhdGljIGxvbmcgbWF4MzE3ODVf cmVhZF9sb25nX2RhdGEoc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCwgaW50IHBhZ2UsCj4gPiA+ ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgaW50IHJlZykKPiA+ID4gK3sKPiA+ID4gK8KgwqDCoMKgwqDCoMKgdW5z aWduZWQgY2hhciBjbWRidWZbMV07Cj4gPiA+ICvCoMKgwqDCoMKgwqDCoHVuc2lnbmVkIGNoYXIg cnNwYnVmWzRdOwo+ID4gPiArwqDCoMKgwqDCoMKgwqBzNjQgcmM7Cj4gPiAKPiA+IFRoaXMgc2hv dWxkIGJlIHRoZSBzYW1lIHR5cGUgYXMgdGhlIGZ1bmN0aW9uIHJldHVybnMuCj4gPiAKPiAKPiBB bHNvLCBsb25nIGlzIGxpa2VseSBzMzIgb24gMzItYml0IGFyY2hpdGVjdHVyZXMsIG1ha2luZyBp dCBxdWl0ZSBwb2ludGxlc3MKPiBhcyByZXR1cm4gdHlwZS4gSW4gdGhpcyBjYXNlLCBpdCBtYXkg YmUgYmV0dGVyIHRvIGhhbmRsZSBkYXRhIGFuZCBlcnJvciByZXR1cm4KPiBhcyBzZXBhcmF0ZSBw YXJhbWV0ZXJzLCBzdWNoIGFzIGluCj4gCj4gc3RhdGljIGluaXQgbWF4MzE3ODVfcmVhZDMyKHN0 cnVjdCBpMmNfY2xpZW50ICpjbGllbnQsIGludCBwYWdlLCBpbnQgcmVnLAo+IAkJCcKgwqDCoMKg dTMyICpkYXRhKQoKU3VyZSwgSSdsbCB0YWtlIHRoYXQgYXBwcm9hY2guCgo+IAo+ID4gPiArCj4g PiA+ICvCoMKgwqDCoMKgwqDCoHN0cnVjdCBpMmNfbXNnIG1zZ1syXSA9IHsKPiA+ID4gK8KgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoHsKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAuYWRkciA9IGNsaWVudC0+YWRkciwKPiA+ID4gK8KgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAuZmxhZ3MgPSAwLAo+ID4g PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoC5sZW4gPSBz aXplb2YoY21kYnVmKSwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqAuYnVmID0gY21kYnVmLAo+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgfSwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoHsKPiA+ID4gK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAuYWRkciA9IGNsaWVu dC0+YWRkciwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqAuZmxhZ3MgPSBJMkNfTV9SRCwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqAubGVuID0gc2l6ZW9mKHJzcGJ1ZiksCj4gPiA+ICvCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgLmJ1ZiA9IHJzcGJ1ZiwKPiA+ ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoH0sCj4gPiA+ICvCoMKgwqDCoMKgwqDC oH07Cj4gPiA+ICsKPiA+ID4gK8KgwqDCoMKgwqDCoMKgY21kYnVmWzBdID0gcmVnOwo+ID4gPiAr Cj4gPiA+ICvCoMKgwqDCoMKgwqDCoHJjID0gcG1idXNfc2V0X3BhZ2UoY2xpZW50LCBwYWdlKTsK PiA+ID4gK8KgwqDCoMKgwqDCoMKgaWYgKHJjIDwgMCkKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoHJldHVybiByYzsKPiA+ID4gKwo+ID4gPiArwqDCoMKgwqDCoMKgwqByYyA9 IGkyY190cmFuc2ZlcihjbGllbnQtPmFkYXB0ZXIsIG1zZywgQVJSQVlfU0laRShtc2cpKTsKPiA+ ID4gK8KgwqDCoMKgwqDCoMKgaWYgKHJjIDwgMCkKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoHJldHVybiByYzsKPiA+ID4gKwo+ID4gPiArwqDCoMKgwqDCoMKgwqByYyA9IChy c3BidWZbMF0gPDwgKDAgKiA4KSkgfCAocnNwYnVmWzFdIDw8ICgxICogOCkpIHwKPiA+ID4gK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoChyc3BidWZbMl0gPDwgKDIgKiA4KSkgfCAocnNwYnVmWzNd IDw8ICgzICogOCkpOwo+ID4gCj4gPiBJdCdzIGdldHRpbmcgbGF0ZSwgc28gSSBtaWdodCBoYXZl IGNvbmZ1c2VkIG15c2VsZi4gQnV0IGNhbiB5b3UganVzdCBkbzoKPiA+IAo+ID4gcmMgPSBsZTMy X3RvX2NwdXAocnNwYnVmKTsKPiA+IAo+ID4gPiArCj4gPiA+ICvCoMKgwqDCoMKgwqDCoHJldHVy biByYzsKPiA+ID4gK30KPiA+ID4gKwo+ID4gPiArc3RhdGljIGludCBtYXgzMTc4NV9nZXRfcHdt KHN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQsIGludCBwYWdlKQo+ID4gPiArewo+ID4gPiArwqDC oMKgwqDCoMKgwqBpbnQgY29uZmlnOwo+ID4gPiArwqDCoMKgwqDCoMKgwqBpbnQgY29tbWFuZDsK PiA+ID4gKwo+ID4gPiArwqDCoMKgwqDCoMKgwqBjb25maWcgPSBwbWJ1c19yZWFkX2J5dGVfZGF0 YShjbGllbnQsIHBhZ2UsIFBNQlVTX0ZBTl9DT05GSUdfMTIpOwo+ID4gPiArwqDCoMKgwqDCoMKg wqBpZiAoY29uZmlnIDwgMCkKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoHJl dHVybiBjb25maWc7Cj4gPiA+ICsKPiA+ID4gK8KgwqDCoMKgwqDCoMKgY29tbWFuZCA9IHBtYnVz X3JlYWRfd29yZF9kYXRhKGNsaWVudCwgcGFnZSwgUE1CVVNfRkFOX0NPTU1BTkRfMSk7Cj4gPiA+ ICvCoMKgwqDCoMKgwqDCoGlmIChjb21tYW5kIDwgMCkKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoHJldHVybiBjb21tYW5kOwo+ID4gPiArCj4gPiA+ICvCoMKgwqDCoMKgwqDC oGlmICghKGNvbmZpZyAmIFBCX0ZBTl8xX1JQTSkpIHsKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoGlmIChjb21tYW5kID49IDB4ODAwMCkKPiA+ID4gK8KgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqByZXR1cm4gMDsKPiA+ID4gK8KgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoGVsc2UgaWYgKGNvbW1hbmQgPj0gMHgyNzExKQo+ID4gPiAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoHJldHVybiAweDI3 MTA7Cj4gPiAKPiA+IFdoYXQgYXJlIHRoZSBtYWdpYyBudW1iZXJzPwoKTWFnaWMgZnJvbSB0aGUg TWF4aW0gZGF0YXNoZWV0OiBTZWUgRkFOX0NPTU1BTkRfMSwgcGFnZSAzMFsxXS4gSSBmZWx0Cm1h Y3JvcyB3b3VsZCBiZSBtb3JlIHBhaW4gdGhhbiBnYWluIGJ1dCBhbSBoYXBweSB0byBiaWtlc2hl ZC4gSQpwcm9iYWJseSBqdXN0IHdhc24ndCBiZWluZyBjcmVhdGl2ZSBlbm91Z2guIEluIGdlbmVy YWwgSSBhZ3JlZSBtYWdpYwpudW1iZXJzIGFyZSBub3QgdGhlIHdheSB0byBnby4KClsxXSBodHRw czovL2RhdGFzaGVldHMubWF4aW1pbnRlZ3JhdGVkLmNvbS9lbi9kcy9NQVgzMTc4NS5wZGYKCj4g PiAKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoGVsc2UKPiAKPiB1bm5lY2Vz c2FyeSBlbHNlCgpJbmRlZWQuIFdpbGwgZml4IHVwIG90aGVyIGluc3RhbmNlcy4KCj4gCj4gPiA+ ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgcmV0dXJuIGNv bW1hbmQ7Cj4gPiA+ICvCoMKgwqDCoMKgwqDCoH0KPiA+ID4gKwo+ID4gPiArwqDCoMKgwqDCoMKg wqByZXR1cm4gMDsKPiA+ID4gK30KPiA+ID4gKwo+ID4gPiArc3RhdGljIGludCBtYXgzMTc4NV9n ZXRfcHdtX21vZGUoc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCwgaW50IHBhZ2UpCj4gPiA+ICt7 Cj4gPiA+ICvCoMKgwqDCoMKgwqDCoGludCBjb25maWc7Cj4gPiA+ICvCoMKgwqDCoMKgwqDCoGlu dCBjb21tYW5kOwo+ID4gPiArCj4gPiA+ICvCoMKgwqDCoMKgwqDCoGNvbmZpZyA9IHBtYnVzX3Jl YWRfYnl0ZV9kYXRhKGNsaWVudCwgcGFnZSwgUE1CVVNfRkFOX0NPTkZJR18xMik7Cj4gPiA+ICvC oMKgwqDCoMKgwqDCoGlmIChjb25maWcgPCAwKQo+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgcmV0dXJuIGNvbmZpZzsKPiA+ID4gKwo+ID4gPiArwqDCoMKgwqDCoMKgwqBjb21t YW5kID0gcG1idXNfcmVhZF93b3JkX2RhdGEoY2xpZW50LCBwYWdlLCBQTUJVU19GQU5fQ09NTUFO RF8xKTsKPiA+ID4gK8KgwqDCoMKgwqDCoMKgaWYgKGNvbW1hbmQgPCAwKQo+ID4gPiArwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgcmV0dXJuIGNvbW1hbmQ7Cj4gPiA+ICsKPiA+ID4gK8Kg wqDCoMKgwqDCoMKgaWYgKCEoY29uZmlnICYgUEJfRkFOXzFfUlBNKSkgewo+ID4gPiArwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgaWYgKGNvbW1hbmQgPj0gMHg4MDAwKQo+ID4gPiArwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoHJldHVybiAyOwo+ID4g PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgZWxzZSBpZiAoY29tbWFuZCA+PSAweDI3 MTEpCj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg cmV0dXJuIDA7Cj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqBlbHNlCj4gCj4g VW5lY2Vzc2FyeSBlbHNlCj4gCj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgcmV0dXJuIDE7Cj4gPiA+ICvCoMKgwqDCoMKgwqDCoH0KPiA+ID4gKwo+ ID4gPiArwqDCoMKgwqDCoMKgwqByZXR1cm4gKGNvbW1hbmQgPj0gMHg4MDAwKSA/IDIgOiAxOwo+ ID4gPiArfQo+ID4gPiArCj4gPiA+ICtzdGF0aWMgaW50IG1heDMxNzg1X3JlYWRfd29yZF9kYXRh KHN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQsIGludCBwYWdlLAo+ID4gPiArwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqBp bnQgcmVnKQo+ID4gPiArewo+ID4gPiArwqDCoMKgwqDCoMKgwqBzdHJ1Y3QgbWF4MzE3ODUgKmNo aXAgPSB0b19tYXgzMTc4NShjbGllbnQpOwo+ID4gPiArwqDCoMKgwqDCoMKgwqBsb25nIHJ2ID0g LUVOT0RBVEE7Cj4gPiA+ICsKPiA+ID4gK8KgwqDCoMKgwqDCoMKgc3dpdGNoIChyZWcpIHsKPiA+ ID4gK8KgwqDCoMKgwqDCoMKgY2FzZSBQTUJVU19SRUFEX0ZBTl9TUEVFRF8xOgo+ID4gPiArwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgaWYgKGxpa2VseShwYWdlIDwgMjMpKQo+ID4gPiAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoHJldHVybiAtRU5P REFUQTsKPiA+ID4gKwo+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgaWYgKFdB Uk5fT04oIShjaGlwLT5jYXBhYmlsaXRpZXMgJiBNQVgzMTc4NV9DQVBfRFVBTF9UQUNIKSkpCj4g PiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgcmV0dXJu IC1FTk9UU1VQUDsKPiA+ID4gKwo+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg cnYgPSBtYXgzMTc4NV9yZWFkX2xvbmdfZGF0YShjbGllbnQsIHBhZ2UgLSAyMywgcmVnKTsKPiA+ ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoGlmIChydiA8IDApCj4gPiA+ICvCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgcmV0dXJuIHJ2Owo+ID4g PiArCj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqBydiA9IChydiA+PiAxNikg JiAweGZmZmY7Cj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqBicmVhazsKPiA+ ID4gK8KgwqDCoMKgwqDCoMKgY2FzZSBQTUJVU19WSVJUX1BXTV8xOgo+ID4gPiArwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgcnYgPSBtYXgzMTc4NV9nZXRfcHdtKGNsaWVudCwgcGFnZSk7 Cj4gCj4gQW5kIGlnbm9yZSB0aGUgZXJyb3IgPwoKSGFoLiBBcHBhcmVudGx5LiBXaWxsIGZpeC4K Cj4gCj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqBydiAqPSAyNTU7Cj4gPiA+ ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqBydiAvPSAxMDA7Cj4gCj4gbWF4MzE3ODVf Z2V0X3B3bSgpIHJldHVybnMgMC4uMHgyNzEwIChvciAxMDAwMCkuIFRoaXMgaXMgdHJhbnNsYXRl ZCB0byAwLi4yNTUwMC4KPiBOb3QgcmVhbGx5IHN1cmUgaWYgdGhhdCBtYWtlcyBzZW5zZS4gV2Ug ZG9uJ3QgcmVwb3J0IHB3bSB2YWx1ZXMgaW4gZnJhY3Rpb25zIG9mCj4gMTAwIHRvIHVzZXIgc3Bh Y2UuCgpSaWdodCwgYnV0IHRoaXMgZ29lcyB0aHJvdWdoIERJUkVDVCBjb252ZXJzaW9uIHRvIGRp dmlkZSBieSAxMDAgKG0gPSAxLApiID0gMCwgUiA9IDIpIGJlZm9yZSB3ZSBoaXQgdXNlcnNwYWNl LgoKPiAKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoGJyZWFrOwo+ID4gPiAr wqDCoMKgwqDCoMKgwqBjYXNlIFBNQlVTX1ZJUlRfUFdNX0VOQUJMRV8xOgo+ID4gPiArwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgcnYgPSBtYXgzMTc4NV9nZXRfcHdtX21vZGUoY2xpZW50 LCBwYWdlKTsKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoGJyZWFrOwo+IAo+ IE5vdCBzdXJlIGlmIFBNQlVTX1ZJUlRfUFdNXzEgYW5kIFBNQlVTX1ZJUlRfUFdNX0VOQUJMRV8x IHNob3VsZCByZXR1cm4KPiAtRU5PVFNVUFAgZm9yIHBhZ2VzIDIzKy4KClllYWgsIHRoYXQncyBy ZWFzb25hYmxlLCBob3dldmVyIGJ5IHNpbWlsYXIgcmVhc29uaW5nIHlvdSB1c2VkIHRvCmVsaW1p bmF0ZSB0aGUgY2FwYWJpbGl0aWVzIHZhcmlhYmxlIHRoaXMgY2FzZSBzaG91bGQgbmV2ZXIgYmUg aGl0IGFzCnRob3NlIGF0dHJpYnV0ZXMgc2hvdWxkbid0IGV4aXN0LgoKPiAKPiA+ID4gK8KgwqDC oMKgwqDCoMKgfQo+ID4gPiArCj4gPiA+ICvCoMKgwqDCoMKgwqDCoGlmIChydiA9PSAtRU5PREFU QSAmJiBwYWdlID49IDIzKQo+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgcmV0 dXJuIC1FTlhJTzsKPiAKPiBUaGF0IGxvb2tzIGxpa2UgYW5vdGhlciB2ZXJpZmljYXRpb24uIFBs ZWFzZSBkcm9wLgo+IAo+ID4gPiArCj4gPiA+ICvCoMKgwqDCoMKgwqDCoHJldHVybiBydjsKPiA+ ID4gK30KPiA+ID4gKwo+ID4gPiArc3RhdGljIGNvbnN0IGludCBtYXgzMTc4NV9wd21fbW9kZXNb XSA9IHsgMHg3ZmZmLCAweDI3MTAsIDB4ZmZmZiB9Owo+ID4gPiArCj4gPiA+ICtzdGF0aWMgaW50 IG1heDMxNzg1X3dyaXRlX3dvcmRfZGF0YShzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50LCBpbnQg cGFnZSwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqBpbnQgcmVnLCB1MTYgd29yZCkKPiA+ID4gK3sKPiA+ ID4gK8KgwqDCoMKgwqDCoMKgaW50IHJ2ID0gLUVOT0RBVEE7Cj4gPiA+ICsKPiA+ID4gK8KgwqDC oMKgwqDCoMKgaWYgKHBhZ2UgPj0gMjMpCj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqByZXR1cm4gLUVOWElPOwo+ID4gPiArCj4gPiA+ICvCoMKgwqDCoMKgwqDCoHN3aXRjaCAo cmVnKSB7Cj4gPiA+ICvCoMKgwqDCoMKgwqDCoGNhc2UgUE1CVVNfVklSVF9QV01fRU5BQkxFXzE6 Cj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqBpZiAod29yZCA+PSBBUlJBWV9T SVpFKG1heDMxNzg1X3B3bV9tb2RlcykpCj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgcmV0dXJuIC1FTk9UU1VQUDsKPiAKPiBUaGF0IGRvZXNuJ3Qg bG9vayBjb3JyZWN0LiAtRUlOVkFMLCBwb3NzaWJseS4KClllcywgLUVJTlZBTCB3b3VsZCBiZSBi ZXR0ZXIuCgo+IAo+ID4gPiArCj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqBy diA9IHBtYnVzX3VwZGF0ZV9mYW4oY2xpZW50LCBwYWdlLCAwLCAwLCBQQl9GQU5fMV9SUE0sCj4g PiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoG1heDMxNzg1X3B3bV9tb2Rlc1t3b3JkXSk7Cj4g PiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqBicmVhazsKPiA+ID4gK8KgwqDCoMKg wqDCoMKgfQo+ID4gPiArCj4gPiA+ICvCoMKgwqDCoMKgwqDCoHJldHVybiBydjsKPiA+ID4gK30K PiA+ID4gKwo+ID4gPiArc3RhdGljIGludCBtYXgzMTc4NV93cml0ZV9ieXRlKHN0cnVjdCBpMmNf Y2xpZW50ICpjbGllbnQsIGludCBwYWdlLCB1OCB2YWx1ZSkKPiA+ID4gK3sKPiA+ID4gK8KgwqDC oMKgwqDCoMKgaWYgKHBhZ2UgPCAyMykKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoHJldHVybiAtRU5PREFUQTsKPiA+ID4gKwo+ID4gPiArwqDCoMKgwqDCoMKgwqByZXR1cm4g LUVOT1RTVVBQOwo+ID4gPiArfQo+ID4gPiArCj4gPiA+ICtzdGF0aWMgc3RydWN0IHBtYnVzX2Ry aXZlcl9pbmZvIG1heDMxNzg1X2luZm8gPSB7Cj4gPiA+ICvCoMKgwqDCoMKgwqDCoC5wYWdlcyA9 IDIzLAo+ID4gPiArCj4gPiA+ICvCoMKgwqDCoMKgwqDCoC53cml0ZV93b3JkX2RhdGEgPSBtYXgz MTc4NV93cml0ZV93b3JkX2RhdGEsCj4gPiA+ICvCoMKgwqDCoMKgwqDCoC5yZWFkX2J5dGVfZGF0 YSA9IG1heDMxNzg1X3JlYWRfYnl0ZV9kYXRhLAo+ID4gPiArwqDCoMKgwqDCoMKgwqAucmVhZF93 b3JkX2RhdGEgPSBtYXgzMTc4NV9yZWFkX3dvcmRfZGF0YSwKPiA+ID4gK8KgwqDCoMKgwqDCoMKg LndyaXRlX2J5dGUgPSBtYXgzMTc4NV93cml0ZV9ieXRlLAo+ID4gPiArCj4gPiA+ICvCoMKgwqDC oMKgwqDCoC8qIFJQTSAqLwo+ID4gPiArwqDCoMKgwqDCoMKgwqAuZm9ybWF0W1BTQ19GQU5dID0g ZGlyZWN0LAo+ID4gPiArwqDCoMKgwqDCoMKgwqAubVtQU0NfRkFOXSA9IDEsCj4gPiA+ICvCoMKg wqDCoMKgwqDCoC5iW1BTQ19GQU5dID0gMCwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgLlJbUFNDX0ZB Tl0gPSAwLAo+ID4gPiArwqDCoMKgwqDCoMKgwqAvKiBQV00gKi8KPiA+ID4gK8KgwqDCoMKgwqDC oMKgLmZvcm1hdFtQU0NfUFdNXSA9IGRpcmVjdCwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgLm1bUFND X1BXTV0gPSAxLAo+ID4gPiArwqDCoMKgwqDCoMKgwqAuYltQU0NfUFdNXSA9IDAsCj4gPiA+ICvC oMKgwqDCoMKgwqDCoC5SW1BTQ19QV01dID0gMiwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgLmZ1bmNb MF0gPSBQTUJVU19IQVZFX0ZBTjEyIHwgUE1CVVNfSEFWRV9TVEFUVVNfRkFOMTIsCj4gPiA+ICvC oMKgwqDCoMKgwqDCoC5mdW5jWzFdID0gUE1CVVNfSEFWRV9GQU4xMiB8IFBNQlVTX0hBVkVfU1RB VFVTX0ZBTjEyLAo+ID4gPiArwqDCoMKgwqDCoMKgwqAuZnVuY1syXSA9IFBNQlVTX0hBVkVfRkFO MTIgfCBQTUJVU19IQVZFX1NUQVRVU19GQU4xMiwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgLmZ1bmNb M10gPSBQTUJVU19IQVZFX0ZBTjEyIHwgUE1CVVNfSEFWRV9TVEFUVVNfRkFOMTIsCj4gPiA+ICvC oMKgwqDCoMKgwqDCoC5mdW5jWzRdID0gUE1CVVNfSEFWRV9GQU4xMiB8IFBNQlVTX0hBVkVfU1RB VFVTX0ZBTjEyLAo+ID4gPiArwqDCoMKgwqDCoMKgwqAuZnVuY1s1XSA9IFBNQlVTX0hBVkVfRkFO MTIgfCBQTUJVU19IQVZFX1NUQVRVU19GQU4xMiwKPiA+ID4gKwo+ID4gPiArwqDCoMKgwqDCoMKg wqAuZm9ybWF0W1BTQ19URU1QRVJBVFVSRV0gPSBkaXJlY3QsCj4gPiA+ICvCoMKgwqDCoMKgwqDC oC5tW1BTQ19URU1QRVJBVFVSRV0gPSAxLAo+ID4gPiArwqDCoMKgwqDCoMKgwqAuYltQU0NfVEVN UEVSQVRVUkVdID0gMCwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgLlJbUFNDX1RFTVBFUkFUVVJFXSA9 IDIsCj4gPiA+ICvCoMKgwqDCoMKgwqDCoC5mdW5jWzZdwqDCoD0gUE1CVVNfSEFWRV9TVEFUVVNf VEVNUCwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgLmZ1bmNbN13CoMKgPSBQTUJVU19IQVZFX1NUQVRV U19URU1QLAo+ID4gPiArwqDCoMKgwqDCoMKgwqAuZnVuY1s4XcKgwqA9IFBNQlVTX0hBVkVfU1RB VFVTX1RFTVAsCj4gPiA+ICvCoMKgwqDCoMKgwqDCoC5mdW5jWzldwqDCoD0gUE1CVVNfSEFWRV9T VEFUVVNfVEVNUCwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgLmZ1bmNbMTBdID0gUE1CVVNfSEFWRV9T VEFUVVNfVEVNUCwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgLmZ1bmNbMTFdID0gUE1CVVNfSEFWRV9T VEFUVVNfVEVNUCwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgLmZ1bmNbMTJdID0gUE1CVVNfSEFWRV9T VEFUVVNfVEVNUCwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgLmZ1bmNbMTNdID0gUE1CVVNfSEFWRV9T VEFUVVNfVEVNUCwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgLmZ1bmNbMTRdID0gUE1CVVNfSEFWRV9T VEFUVVNfVEVNUCwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgLmZ1bmNbMTVdID0gUE1CVVNfSEFWRV9T VEFUVVNfVEVNUCwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgLmZ1bmNbMTZdID0gUE1CVVNfSEFWRV9T VEFUVVNfVEVNUCwKPiA+ID4gKwo+ID4gPiArwqDCoMKgwqDCoMKgwqAuZm9ybWF0W1BTQ19WT0xU QUdFX09VVF0gPSBkaXJlY3QsCj4gPiA+ICvCoMKgwqDCoMKgwqDCoC5tW1BTQ19WT0xUQUdFX09V VF0gPSAxLAo+ID4gPiArwqDCoMKgwqDCoMKgwqAuYltQU0NfVk9MVEFHRV9PVVRdID0gMCwKPiA+ ID4gK8KgwqDCoMKgwqDCoMKgLlJbUFNDX1ZPTFRBR0VfT1VUXSA9IDAsCj4gPiA+ICvCoMKgwqDC oMKgwqDCoC5mdW5jWzE3XSA9IFBNQlVTX0hBVkVfU1RBVFVTX1ZPVVQsCj4gPiA+ICvCoMKgwqDC oMKgwqDCoC5mdW5jWzE4XSA9IFBNQlVTX0hBVkVfU1RBVFVTX1ZPVVQsCj4gPiA+ICvCoMKgwqDC oMKgwqDCoC5mdW5jWzE5XSA9IFBNQlVTX0hBVkVfU1RBVFVTX1ZPVVQsCj4gPiA+ICvCoMKgwqDC oMKgwqDCoC5mdW5jWzIwXSA9IFBNQlVTX0hBVkVfU1RBVFVTX1ZPVVQsCj4gPiA+ICvCoMKgwqDC oMKgwqDCoC5mdW5jWzIxXSA9IFBNQlVTX0hBVkVfU1RBVFVTX1ZPVVQsCj4gPiA+ICvCoMKgwqDC oMKgwqDCoC5mdW5jWzIyXSA9IFBNQlVTX0hBVkVfU1RBVFVTX1ZPVVQsCj4gPiA+ICt9Owo+ID4g PiArCj4gPiA+ICtzdGF0aWMgaW50IG1heDMxNzg1X3Byb2JlKHN0cnVjdCBpMmNfY2xpZW50ICpj bGllbnQsCj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoGNvbnN0IHN0cnVjdCBpMmNfZGV2aWNlX2lkICppZCkKPiA+ID4gK3sKPiA+ID4gK8Kg wqDCoMKgwqDCoMKgc3RydWN0IG1heDMxNzg1ICpjaGlwOwo+ID4gPiArwqDCoMKgwqDCoMKgwqBp bnQgcnY7Cj4gPiA+ICvCoMKgwqDCoMKgwqDCoGludCBpOwo+ID4gPiArCj4gPiA+ICvCoMKgwqDC oMKgwqDCoGNoaXAgPSBkZXZtX2t6YWxsb2MoJmNsaWVudC0+ZGV2LCBzaXplb2YoKmNoaXApLCBH RlBfS0VSTkVMKTsKPiA+ID4gK8KgwqDCoMKgwqDCoMKgaWYgKCFjaGlwKQo+ID4gPiArwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgcmV0dXJuIC1FTk9NRU07Cj4gPiA+ICsKPiA+ID4gK8Kg wqDCoMKgwqDCoMKgY2hpcC0+aW5mbyA9IG1heDMxNzg1X2luZm87Cj4gPiA+ICsKPiA+ID4gK8Kg wqDCoMKgwqDCoMKgLyoKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqAqIElkZW50aWZ5IHRoZSBjaGlw IGZpcm13YXJlIGFuZCBjb25maWd1cmUgY2FwYWJpbGl0aWVzLgo+ID4gPiArwqDCoMKgwqDCoMKg wqDCoCoKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqAqIEJvb3RzdHJhcCB3aXRoIGkyY19zbWJ1c18q KCkgY2FsbHMgYXMgd2UgbmVlZCB0byB1bmRlcnN0YW5kIHRoZSBjaGlwCj4gPiA+ICvCoMKgwqDC oMKgwqDCoMKgKiBjYXBhYmlsaXRpZXMgZm9yIGJlZm9yZSBpbnZva2luZyBwbWJ1c19kb19wcm9i ZSgpLiBUaGUgcG1idXNfKigpCj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgKiBjYWxscyBuZWVkIGFj Y2VzcyB0byBtZW1vcnkgdGhhdCBpcyBvbmx5IHZhbGlkIGFmdGVyCj4gPiA+ICvCoMKgwqDCoMKg wqDCoMKgKiBwbWJ1c19kb19wcm9iZSgpLgo+ID4gCj4gPiBJIHRoaW5rIHRoaXMgaXMgY29tbW9u IGVub3VnaCBpbiBwbWJ1cyBkcml2ZXJzIHRoYXQgdGhlIGNvbW1lbnQgaXMgcmVkdW5kYW50LgoK V2lsbCBkby4KCj4gPiAKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqAqLwo+ID4gPiArwqDCoMKgwqDC oMKgwqBydiA9IGkyY19zbWJ1c193cml0ZV9ieXRlX2RhdGEoY2xpZW50LCBQTUJVU19QQUdFLCAy NTUpOwo+ID4gPiArwqDCoMKgwqDCoMKgwqBpZiAocnYgPCAwKQo+ID4gPiArwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgcmV0dXJuIHJ2Owo+ID4gPiArCj4gPiA+ICvCoMKgwqDCoMKgwqDC oHJ2ID0gaTJjX3NtYnVzX3JlYWRfd29yZF9kYXRhKGNsaWVudCwgUE1CVVNfTUZSX1JFVklTSU9O KTsKPiA+ID4gK8KgwqDCoMKgwqDCoMKgaWYgKHJ2IDwgMCkKPiA+ID4gK8KgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoHJldHVybiBydjsKPiA+ID4gKwo+ID4gPiArwqDCoMKgwqDCoMKgwqBp ZiAoKHJ2ICYgMHhmZikgPT0gMHg0MCkgewo+ID4gCj4gPiBEVUFMX1RBQ0hfUkVWPyBPciBhIGJl dHRlciBuYW1lIGZyb20gdGhlIGRvY3Mgd2UgaGF2ZT8KCkknbGwgaGF2ZSBhIHRoaW5rIGFib3V0 IGEgbmFtZS4KClRoYW5rcyBmb3IgdGhlIGZlZWRiYWNrIGd1eXMuCgpBbmRyZXcKCj4gPiAKPiA+ ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoGNoaXAtPmNhcGFiaWxpdGllcyB8PSBN QVgzMTc4NV9DQVBfRFVBTF9UQUNIOwo+ID4gPiArCj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqAvKgo+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAqIFB1 bnQgdGhlIGR1YWwgdGFjaCB2aXJ0dWFsIGZhbnMgdG8gbm9uLWV4aXN0ZW50IHBhZ2VzLiBUaGlz Cj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCogZW5zdXJlcyB0aGUgcHdt IGF0dHJpYnV0ZXMgYXBwZWFyIGluIGEgY29udGlndW91cyBibG9jawo+ID4gPiArwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAqLwo+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgY2hpcC0+aW5mby5wYWdlcyA9IDI5Owo+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgY2hpcC0+aW5mby5mdW5jWzIzXSA9IFBNQlVTX0hBVkVfRkFOMTI7Cj4gPiA+ICvC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqBjaGlwLT5pbmZvLmZ1bmNbMjRdID0gUE1CVVNf SEFWRV9GQU4xMjsKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoGNoaXAtPmlu Zm8uZnVuY1syNV0gPSBQTUJVU19IQVZFX0ZBTjEyOwo+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgY2hpcC0+aW5mby5mdW5jWzI2XSA9IFBNQlVTX0hBVkVfRkFOMTI7Cj4gPiA+ ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqBjaGlwLT5pbmZvLmZ1bmNbMjddID0gUE1C VVNfSEFWRV9GQU4xMjsKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoGNoaXAt PmluZm8uZnVuY1syOF0gPSBQTUJVU19IQVZFX0ZBTjEyOwo+ID4gPiArwqDCoMKgwqDCoMKgwqB9 Cj4gPiA+ICsKPiA+ID4gK8KgwqDCoMKgwqDCoMKgcnYgPSBwbWJ1c19kb19wcm9iZShjbGllbnQs IGlkLCAmY2hpcC0+aW5mbyk7Cj4gPiA+ICvCoMKgwqDCoMKgwqDCoGlmIChydiA8IDApCj4gPiA+ ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqByZXR1cm4gcnY7Cj4gPiA+ICsKPiA+ID4g K8KgwqDCoMKgwqDCoMKgZm9yIChpID0gMDsgaSA8IG1heDMxNzg1X2luZm8ucGFnZXM7IGkrKykg ewo+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgaW50IHJlZzsKPiA+ID4gKwo+ ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgaWYgKCEobWF4MzE3ODVfaW5mby5m dW5jW2ldICYgKFBNQlVTX0hBVkVfRkFOMTIpKSkKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqBjb250aW51ZTsKPiA+ID4gKwo+ID4gPiArwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgcmVnID0gcG1idXNfcmVhZF93b3JkX2RhdGEoY2xpZW50 LCBpLCBQTUJVU19NRlJfRkFOX0NPTkZJRyk7Cj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqBpZiAocmVnIDwgMCkKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqBjb250aW51ZTsKPiA+ID4gKwo+ID4gPiArwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgLyoKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg KiBYWFg6IFB1cmVseSBmb3IgUkZDL3Rlc3RpbmcgcHVycG9zZXMsIGRvbid0IHJhbXAgZmFucyBv biBmYW4KPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgKiBvciB0ZW1wZXJh dHVyZSBzZW5zb3IgZmF1bHQsIG9yIGEgZmFpbHVyZSB0byB3cml0ZQo+ID4gPiArwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAqIEZBTl9DT01NQU5EXzEgaW5zaWRlIGEgMTBzIHdpbmRv dyAod2F0Y2hkb2cgbW9kZSkuCj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oCoKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgKiBUaGUgVFNGTyBiaXQg Y29udHJvbHMgYm90aCByYW1waW5nIG9uIHRlbXAgc2Vuc29yIGZhaWx1cmUKPiA+ID4gK8KgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgKiBBTkQgd2hldGhlciBGQU5fQ09NTUFORF8xIGlz IGluIHdhdGNoZG9nIG1vZGUuCj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oCovCj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqByZWcgfD0gTUZSX0ZBTl9D T05GSUdfVFNGTyB8IE1GUl9GQU5fQ09ORklHX1RBQ0hPOwo+ID4gPiArwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgaWYgKGNoaXAtPmNhcGFiaWxpdGllcyAmIE1BWDMxNzg1X0NBUF9EVUFM X1RBQ0gpCj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgcmVnIHw9IE1GUl9GQU5fQ09ORklHX0RVQUxfVEFDSDsKPiA+ID4gK8KgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoHJlZyAmPSAweGZmZmY7Cj4gPiA+ICsKPiA+ID4gK8KgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoHJ2ID0gcG1idXNfd3JpdGVfd29yZF9kYXRhKGNsaWVudCwgaSwg UE1CVVNfTUZSX0ZBTl9DT05GSUcsCj4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqBy ZWcpOwo+ID4gPiArwqDCoMKgwqDCoMKgwqB9Cj4gPiA+ICsKPiA+ID4gK8KgwqDCoMKgwqDCoMKg cmV0dXJuIDA7Cj4gPiA+ICt9Cj4gPiA+ICsKPiA+ID4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgaTJj X2RldmljZV9pZCBtYXgzMTc4NV9pZFtdID0gewo+ID4gPiArwqDCoMKgwqDCoMKgwqB7ICJtYXgz MTc4NSIsIDAgfSwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgeyB9LAo+ID4gPiArfTsKPiA+ID4gKwo+ ID4gPiArTU9EVUxFX0RFVklDRV9UQUJMRShpMmMsIG1heDMxNzg1X2lkKTsKPiA+ID4gKwo+ID4g PiArc3RhdGljIHN0cnVjdCBpMmNfZHJpdmVyIG1heDMxNzg1X2RyaXZlciA9IHsKPiA+ID4gK8Kg wqDCoMKgwqDCoMKgLmRyaXZlciA9IHsKPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoC5uYW1lID0gIm1heDMxNzg1IiwKPiA+ID4gK8KgwqDCoMKgwqDCoMKgfSwKPiA+ID4gK8Kg wqDCoMKgwqDCoMKgLnByb2JlID0gbWF4MzE3ODVfcHJvYmUsCj4gPiA+ICvCoMKgwqDCoMKgwqDC oC5yZW1vdmUgPSBwbWJ1c19kb19yZW1vdmUsCj4gPiA+ICvCoMKgwqDCoMKgwqDCoC5pZF90YWJs ZSA9IG1heDMxNzg1X2lkLAo+ID4gPiArfTsKPiA+ID4gKwo+ID4gPiArbW9kdWxlX2kyY19kcml2 ZXIobWF4MzE3ODVfZHJpdmVyKTsKPiA+ID4gKwo+ID4gPiA+ID4gPiArTU9EVUxFX0FVVEhPUigi QW5kcmV3IEplZmZlcnkgPGFuZHJld0Bhai5pZC5hdT4iKTsKPiA+ID4gK01PRFVMRV9ERVNDUklQ VElPTigiUE1CdXMgZHJpdmVyIGZvciB0aGUgTWF4aW0gTUFYMzE3ODUiKTsKPiA+ID4gK01PRFVM RV9MSUNFTlNFKCJHUEwiKTsKPiA+ID4gLS0KPiA+ID4gMi4xMS4wCj4gPiA+ID==
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web