* [RFC 0/2] *** Broadcom Bluetooth UART Driver *** @ 2015-05-07 20:25 Ilya Faenson 2015-05-07 20:25 ` [RFC 1/2] Bluetooth UART Device Tree bindings Ilya Faenson 2015-05-07 20:25 ` [RFC 2/2] Broadcom Bluetooth UART device driver Ilya Faenson 0 siblings, 2 replies; 6+ messages in thread From: Ilya Faenson @ 2015-05-07 20:25 UTC (permalink / raw) To: Marcel Holtmann; +Cc: linux-bluetooth, Ilya Faenson *** Broadcom Bluetooth UART Driver changed as per checkpatch.pl *** Ilya Faenson (2): Bluetooth UART Device Tree bindings Broadcom Bluetooth UART device driver .../devicetree/bindings/net/bluetooth/btbcm.txt | 54 ++ drivers/bluetooth/Kconfig | 35 +- drivers/bluetooth/Makefile | 1 + drivers/bluetooth/btbcm.c | 173 ++++- drivers/bluetooth/btbcm.h | 19 +- drivers/bluetooth/btbcm_uart.c | 679 +++++++++++++++++ drivers/bluetooth/btbcm_uart.h | 90 +++ drivers/bluetooth/hci_bcm.c | 838 +++++++++++++++++++-- 8 files changed, 1799 insertions(+), 90 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/bluetooth/btbcm.txt create mode 100644 drivers/bluetooth/btbcm_uart.c create mode 100644 drivers/bluetooth/btbcm_uart.h -- 1.9.1 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [RFC 1/2] Bluetooth UART Device Tree bindings 2015-05-07 20:25 [RFC 0/2] *** Broadcom Bluetooth UART Driver *** Ilya Faenson @ 2015-05-07 20:25 ` Ilya Faenson 2015-05-11 19:14 ` Marcel Holtmann 2015-05-07 20:25 ` [RFC 2/2] Broadcom Bluetooth UART device driver Ilya Faenson 1 sibling, 1 reply; 6+ messages in thread From: Ilya Faenson @ 2015-05-07 20:25 UTC (permalink / raw) To: Marcel Holtmann; +Cc: linux-bluetooth, Ilya Faenson Device Tree bindings to configure the Bluetooth UART device. Signed-off-by: Ilya Faenson <ifaenson@broadcom.com> --- .../devicetree/bindings/net/bluetooth/btbcm.txt | 54 ++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/bluetooth/btbcm.txt diff --git a/Documentation/devicetree/bindings/net/bluetooth/btbcm.txt b/Documentation/devicetree/bindings/net/bluetooth/btbcm.txt new file mode 100644 index 0000000..cc9f225 --- /dev/null +++ b/Documentation/devicetree/bindings/net/bluetooth/btbcm.txt @@ -0,0 +1,54 @@ +btbcm +------ + +Required properties: + + - compatible : must be "brcm,brcm-bt-uart". + - tty : tty device connected to this Bluetooth device. + +Optional properties: + + - bt-host-wake-gpios : bt-host-wake input GPIO to be used as an interrupt. + + - bt-wake-gpios : bt-wake output GPIO to be used to suspend / resume device. + + - reg-on-gpios : reg-on output GPIO to be used to power device on/off. + + - baud-rate-before-config-download : initial Bluetooth device baud rate. + Default: 3000000. + + - manual-fc : flow control UART in suspend / resume scenarios. + Default: 0. + + - configure-sleep : configure suspend / resume flag. + Default: 0. + + - configure-audio : configure platform PCM SCO flag. + Default: 0. + + - PCM* : SCO PCM platform parameters. Work with Broadcom on setting. + Defaults: see the example below. + + +Example: + + bcm4354_bt_uart: bcm4354-bt-uart { + compatible = "bcm-bt-uart,bcm4354-bt-uart"; + bt-wake-gpios = <&gpio4 30 GPIO_ACTIVE_HIGH>; + bt-host-wake-gpios = <&gpio4 31 GPIO_ACTIVE_HIGH>; + tty = "ttyS0"; + baud-rate-before-config-download = <3000000>; + configure-sleep = <1>; + configure-audio = <1>; + PCMClockMode = <0>; + PCMFillMethod = <2>; + PCMFillNum = <0>; + PCMFillValue = <3>; + PCMInCallBitclock = <0>; + PCMLSBFirst = <0>; + PCMRightJustify = <0>; + PCMRouting = <0>; + PCMShortFrameSync = <0>; + PCMSyncMode = <0>; + }; + -- 1.9.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [RFC 1/2] Bluetooth UART Device Tree bindings 2015-05-07 20:25 ` [RFC 1/2] Bluetooth UART Device Tree bindings Ilya Faenson @ 2015-05-11 19:14 ` Marcel Holtmann 0 siblings, 0 replies; 6+ messages in thread From: Marcel Holtmann @ 2015-05-11 19:14 UTC (permalink / raw) To: Ilya Faenson; +Cc: linux-bluetooth Hi Ilya, > Device Tree bindings to configure the Bluetooth UART device. > > Signed-off-by: Ilya Faenson <ifaenson@broadcom.com> > --- > .../devicetree/bindings/net/bluetooth/btbcm.txt | 54 ++++++++++++++++++++++ > 1 file changed, 54 insertions(+) > create mode 100644 Documentation/devicetree/bindings/net/bluetooth/btbcm.txt > > diff --git a/Documentation/devicetree/bindings/net/bluetooth/btbcm.txt b/Documentation/devicetree/bindings/net/bluetooth/btbcm.txt > new file mode 100644 > index 0000000..cc9f225 > --- /dev/null > +++ b/Documentation/devicetree/bindings/net/bluetooth/btbcm.txt > @@ -0,0 +1,54 @@ > +btbcm > +------ > + > +Required properties: > + > + - compatible : must be "brcm,brcm-bt-uart". > + - tty : tty device connected to this Bluetooth device. > + > +Optional properties: > + > + - bt-host-wake-gpios : bt-host-wake input GPIO to be used as an interrupt. > + > + - bt-wake-gpios : bt-wake output GPIO to be used to suspend / resume device. > + > + - reg-on-gpios : reg-on output GPIO to be used to power device on/off. > + > + - baud-rate-before-config-download : initial Bluetooth device baud rate. > + Default: 3000000. > + > + - manual-fc : flow control UART in suspend / resume scenarios. > + Default: 0. > + > + - configure-sleep : configure suspend / resume flag. > + Default: 0. > + > + - configure-audio : configure platform PCM SCO flag. > + Default: 0. > + > + - PCM* : SCO PCM platform parameters. Work with Broadcom on setting. > + Defaults: see the example below. I think at some point this needs to be reviewed by the DT guys as well. They surely want to have some say in the naming and how to deal with the Bluetooth devices behind UART controllers. Regards Marcel ^ permalink raw reply [flat|nested] 6+ messages in thread
* [RFC 2/2] Broadcom Bluetooth UART device driver 2015-05-07 20:25 [RFC 0/2] *** Broadcom Bluetooth UART Driver *** Ilya Faenson 2015-05-07 20:25 ` [RFC 1/2] Bluetooth UART Device Tree bindings Ilya Faenson @ 2015-05-07 20:25 ` Ilya Faenson 2015-05-11 19:03 ` Marcel Holtmann 1 sibling, 1 reply; 6+ messages in thread From: Ilya Faenson @ 2015-05-07 20:25 UTC (permalink / raw) To: Marcel Holtmann; +Cc: linux-bluetooth, Ilya Faenson This code implements the Broadcom Bluetooth device driver. It manages device configuration, firmware download and power management. Signed-off-by: Ilya Faenson <ifaenson@broadcom.com> --- drivers/bluetooth/Kconfig | 35 +- drivers/bluetooth/Makefile | 1 + drivers/bluetooth/btbcm.c | 173 ++++++++- drivers/bluetooth/btbcm.h | 19 +- drivers/bluetooth/btbcm_uart.c | 679 +++++++++++++++++++++++++++++++++ drivers/bluetooth/btbcm_uart.h | 90 +++++ drivers/bluetooth/hci_bcm.c | 838 +++++++++++++++++++++++++++++++++++++---- 7 files changed, 1745 insertions(+), 90 deletions(-) create mode 100644 drivers/bluetooth/btbcm_uart.c create mode 100644 drivers/bluetooth/btbcm_uart.h diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index ed5c273..1bfe36b 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -8,6 +8,12 @@ config BT_INTEL config BT_BCM tristate select FW_LOADER + help + This feature is required if you want to use Broadcom Bluetooth + over both USB and UART. + + Say Y here to compile support for Broadcom Bluetooth + kernel or say M to compile it as module (btusb). config BT_HCIBTUSB tristate "HCI USB driver" @@ -22,15 +28,16 @@ config BT_HCIBTUSB kernel or say M to compile it as module (btusb). config BT_HCIBTUSB_BCM - bool "Broadcom protocol support" + bool "Broadcom USB support" depends on BT_HCIBTUSB select BT_BCM default y help - The Broadcom protocol support enables firmware and patchram - download support for Broadcom Bluetooth controllers. + Broadcom Bluetooth USB driver support. + The Broadcom USB support enables firmware and patchram + download for Broadcom Bluetooth USB controllers. - Say Y here to compile support for Broadcom protocol. + Say Y here to compile support for Broadcom USB. config BT_HCIBTSDIO tristate "HCI SDIO driver" @@ -125,15 +132,25 @@ config BT_HCIUART_INTEL Say Y here to compile support for Intel protocol. config BT_HCIUART_BCM - bool "Broadcom protocol support" - depends on BT_HCIUART + bool "Broadcom BT UART serial support" select BT_HCIUART_H4 + select BT_UART_BCM select BT_BCM help - The Broadcom protocol support enables Bluetooth HCI over serial - port interface for Broadcom Bluetooth controllers. + HCI_UART_BCM is a protocol for initializing, managing and + communicating with Broadcom UART Bluetooth devices. + This protocol initializes chips and power-manages them. + Enable this if you have serial Broadcom Bluetooth device. + + Say Y here to compile support for Broadcom UART protocol. + +config BT_UART_BCM + tristate "Broadcom BT UART driver" + depends on BT_HCIUART_H4 && TTY + help + This driver supports the HCI_UART_BT protocol. - Say Y here to compile support for Broadcom protocol. + It manages Bluetooth UART device properties and GPIOs. config BT_HCIBCM203X tristate "HCI BCM203x USB driver" diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index dd0d9c4..0e5fd66 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_BT_MRVL) += btmrvl.o obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o obj-$(CONFIG_BT_WILINK) += btwilink.o obj-$(CONFIG_BT_BCM) += btbcm.o +obj-$(CONFIG_BT_UART_BCM) += btbcm_uart.o btmrvl-y := btmrvl_main.o btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index 4bba866..3e9ac30 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -2,7 +2,8 @@ * * Bluetooth support for Broadcom devices * - * Copyright (C) 2015 Intel Corporation + * Copyright (C) 2015 Intel Corporation + * Copyright (C) 2015 Broadcom Corporation * * * This program is free software; you can redistribute it and/or modify @@ -15,24 +16,22 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include <linux/module.h> #include <linux/firmware.h> +#include <linux/tty.h> #include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> +#include "hci_uart.h" #include "btbcm.h" -#define VERSION "0.1" +#define VERSION "0.2" -#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}}) +#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00} }) int btbcm_check_bdaddr(struct hci_dev *hdev) { @@ -43,6 +42,7 @@ int btbcm_check_bdaddr(struct hci_dev *hdev) HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { int err = PTR_ERR(skb); + BT_ERR("%s: BCM: Reading device address failed (%d)", hdev->name, err); return err; @@ -159,6 +159,8 @@ int btbcm_patchram(struct hci_dev *hdev, const char *firmware) } /* 250 msec delay after Launch Ram completes */ + BT_INFO("%s: BCM: Delaying upon the patch download completion...", + hdev->name); msleep(250); done: @@ -174,6 +176,7 @@ static int btbcm_reset(struct hci_dev *hdev) skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { int err = PTR_ERR(skb); + BT_ERR("%s: BCM: Reset failed (%d)", hdev->name, err); return err; } @@ -246,8 +249,10 @@ static struct sk_buff *btbcm_read_usb_product(struct hci_dev *hdev) static const struct { u16 subver; const char *name; + u32 baud_rate; /* operational baud rate */ } bcm_uart_subver_table[] = { - { 0x410e, "BCM43341B0" }, /* 002.001.014 */ + { 0x410e, "BCM43341B0", 3000000}, /* 002.001.014 */ + { 0x610c, "BCM4354_003.001.012.0306.0659", 3000000}, /* 003.001.012 */ { } }; @@ -268,6 +273,133 @@ static const struct { { } }; +/* + * Set the UART into the defaults + */ +int btbcm_init_uart(struct hci_uart *hu) +{ + struct ktermios ktermios; + struct tty_struct *tty = hu->tty; + int status, speed; + + /* Bring UART into default setting at 115200 */ + if (tty->ldisc->ops->flush_buffer) + tty->ldisc->ops->flush_buffer(tty); + tty_driver_flush_buffer(tty); + ktermios = tty->termios; + BT_DBG("init_uart def flags c_o %x c_l %x c_c %x spd %d/%d", + ktermios.c_oflag, ktermios.c_lflag, ktermios.c_cflag, + ktermios.c_ispeed, ktermios.c_ospeed); + ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP + | INLCR | IGNCR | ICRNL | IXON); + ktermios.c_oflag &= ~OPOST; + ktermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + ktermios.c_cflag &= ~(CSIZE | PARENB | CBAUD); + ktermios.c_cflag |= CS8; + ktermios.c_cflag |= CRTSCTS; + ktermios.c_cflag |= B115200; + ktermios.c_ispeed = 115200; + ktermios.c_ospeed = 115200; + status = tty_set_termios(tty, &ktermios); + if (status) { + BT_DBG("init_uart set_termios failure %d", status); + return status; + } + + speed = tty_get_baud_rate(tty); + BT_DBG("init_uart set_termios completed, spd %d", speed); + ktermios = tty->termios; + BT_DBG("init_uart new flags c_o %x c_l %x c_c %x spd %d/%d", + ktermios.c_oflag, ktermios.c_lflag, ktermios.c_cflag, + ktermios.c_ispeed, ktermios.c_ospeed); + + return 0; +} +EXPORT_SYMBOL_GPL(btbcm_init_uart); + +/* + * Set the baud rate on the UART and the device + */ +int btbcm_set_baud_rate(struct hci_uart *hu, int baud_rate) +{ + struct ktermios ktermios; + struct tty_struct *tty = hu->tty; + int status, speed, cflag; + struct sk_buff *skb; + unsigned char enable = 1; + unsigned char baud_rate_vsc_pars[] = {0, 0, 0, 0x10, 0x0e, 0}; + + /* If the baud rate is higher than 3000000, change the clock */ + if (baud_rate > 3000000) { + skb = __hci_cmd_sync(hu->hdev, 0xfc45, 1, &enable, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + status = PTR_ERR(skb); + return status; + } + + kfree_skb(skb); + BT_DBG("set_baud_rate write UART 48 MHz VSC succeeded"); + } + + /* Now let the device know about the rate change */ + baud_rate_vsc_pars[2] = (unsigned char)(baud_rate & 0xff); + baud_rate_vsc_pars[3] = (unsigned char)((baud_rate >> 8) & 0xff); + baud_rate_vsc_pars[4] = (unsigned char)((baud_rate >> 16) & 0xff); + baud_rate_vsc_pars[5] = (unsigned char)((baud_rate >> 24) & 0xff); + skb = __hci_cmd_sync(hu->hdev, 0xfc18, sizeof(baud_rate_vsc_pars), + baud_rate_vsc_pars, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + status = PTR_ERR(skb); + BT_ERR("set_baud_rate VSC failed (%d)", status); + return status; + } + + kfree_skb(skb); + BT_DBG("set_baud_rate VSC succeeded"); + + /* Set UART into this rate as well */ + ktermios = tty->termios; + BT_DBG("set_baud_rate start flags c_o %x c_l %x c_c %x spd %d/%d", + ktermios.c_oflag, ktermios.c_lflag, ktermios.c_cflag, + ktermios.c_ispeed, ktermios.c_ospeed); + switch (baud_rate) { + case 115200: + cflag |= B115200; break; + case 921600: + cflag |= B921600; break; + case 3000000: + cflag |= B3000000; break; + case 3500000: + cflag |= B3500000; break; + case 4000000: + cflag |= B4000000; break; + default: + BT_DBG("set_baud_rate unknown rate %d", baud_rate); + return -EINVAL; + } + + ktermios.c_cflag &= ~CBAUD; + ktermios.c_cflag |= cflag; + ktermios.c_ispeed = baud_rate; + ktermios.c_ospeed = baud_rate; + status = tty_set_termios(tty, &ktermios); + if (status) { + BT_DBG("set_baud_rate set_termios failure %d", status); + return status; + } + + speed = tty_get_baud_rate(tty); + BT_DBG("set_baud_rate set_termios completed, spd %d", speed); + ktermios = tty->termios; + BT_DBG("set_baud_rate flags c_o %x c_l %x c_c %x spd %d/%d", + ktermios.c_oflag, ktermios.c_lflag, ktermios.c_cflag, + ktermios.c_ispeed, ktermios.c_ospeed); + + return 0; +} +EXPORT_SYMBOL_GPL(btbcm_set_baud_rate); + int btbcm_setup_patchram(struct hci_dev *hdev) { char fw_name[64]; @@ -275,7 +407,8 @@ int btbcm_setup_patchram(struct hci_dev *hdev) const char *hw_name = NULL; struct sk_buff *skb; struct hci_rp_read_local_version *ver; - int i, err; + int i, err, is_uart = false; + struct hci_uart *hu = hci_get_drvdata(hdev); /* Reset */ err = btbcm_reset(hdev); @@ -297,14 +430,18 @@ int btbcm_setup_patchram(struct hci_dev *hdev) if (IS_ERR(skb)) return PTR_ERR(skb); - BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]); + BT_INFO("%s: BCM: chip id %u, rev 0x%x subver 0x%x", + hdev->name, skb->data[1], rev, subver); kfree_skb(skb); switch ((rev & 0xf000) >> 12) { case 0: + case 1: for (i = 0; bcm_uart_subver_table[i].name; i++) { if (subver == bcm_uart_subver_table[i].subver) { hw_name = bcm_uart_subver_table[i].name; + BT_INFO("UART firmware found: %s", hw_name); + is_uart = true; break; } } @@ -312,7 +449,7 @@ int btbcm_setup_patchram(struct hci_dev *hdev) snprintf(fw_name, sizeof(fw_name), "brcm/%s.hcd", hw_name ? : "BCM"); break; - case 1: + case 2: /* Read USB Product Info */ skb = btbcm_read_usb_product(hdev); @@ -345,11 +482,25 @@ int btbcm_setup_patchram(struct hci_dev *hdev) if (err == -ENOENT) return 0; + /* Once the patch is downloaded, the device is back at default rate */ + if (is_uart) { + err = btbcm_init_uart(hu); + if (err) + return 0; + } + /* Reset */ err = btbcm_reset(hdev); if (err) return err; + if (is_uart) { + err = btbcm_set_baud_rate(hu, + bcm_uart_subver_table[i].baud_rate); + if (err) + return 0; + } + /* Read Local Version Info */ skb = btbcm_read_local_version(hdev); if (IS_ERR(skb)) diff --git a/drivers/bluetooth/btbcm.h b/drivers/bluetooth/btbcm.h index eb6ab5f..f7d30c6 100644 --- a/drivers/bluetooth/btbcm.h +++ b/drivers/bluetooth/btbcm.h @@ -2,7 +2,8 @@ * * Bluetooth support for Broadcom devices * - * Copyright (C) 2015 Intel Corporation + * Copyright (C) 2015 Intel Corporation + * Copyright (C) 2015 Broadcom Corporation * * * This program is free software; you can redistribute it and/or modify @@ -15,10 +16,6 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #if IS_ENABLED(CONFIG_BT_BCM) @@ -30,6 +27,8 @@ int btbcm_patchram(struct hci_dev *hdev, const char *firmware); int btbcm_setup_patchram(struct hci_dev *hdev); int btbcm_setup_apple(struct hci_dev *hdev); +int btbcm_init_uart(struct hci_uart *hu); +int btbcm_set_baud_rate(struct hci_uart *hu, int baud_rate); #else static inline int btbcm_check_bdaddr(struct hci_dev *hdev) @@ -57,4 +56,14 @@ static inline int btbcm_setup_apple(struct hci_dev *hdev) return 0; } +static int btbcm_init_uart(void *hu) +{ + return 0; +} + +static int btbcm_set_baud_rate(void *hu, int baud_rate); +{ + return 0; +} + #endif diff --git a/drivers/bluetooth/btbcm_uart.c b/drivers/bluetooth/btbcm_uart.c new file mode 100644 index 0000000..3308bdb --- /dev/null +++ b/drivers/bluetooth/btbcm_uart.c @@ -0,0 +1,679 @@ +/* + * + * Bluetooth BCM UART Driver + * + * Copyright (c) 2015 Broadcom Corporation + * + * 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. + * + */ + +#include <linux/module.h> + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/interrupt.h> +#include <linux/ptrace.h> +#include <linux/poll.h> + +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/signal.h> +#include <linux/ioctl.h> +#include <linux/skbuff.h> +#include <linux/list.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + +#include <linux/gpio/consumer.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/of_platform.h> + +#include "btbcm_uart.h" + +static int idleTimeout = 5; +module_param(idleTimeout, int, 0); +MODULE_PARM_DESC(idleTimeout, "Bluetooth idle timeout in seconds"); + +/* Device context */ +struct bcm_device { + struct list_head list; + + struct platform_device *pdev; + struct gpio_desc *bt_wake_gpio; + struct gpio_desc *dev_wake_gpio; + struct gpio_desc *reg_on_gpio; + int bt_wake_irq; + int dev_wake_active_low; + int reg_on_active_low; + int bt_wake_active_low; + u32 configure_sleep; + u32 manual_fc; + u32 baud_rate_before_config_download; + u32 configure_audio; + u32 PCMClockMode; + u32 PCMFillMethod; + u32 PCMFillNum; + u32 PCMFillValue; + u32 PCMInCallBitclock; + u32 PCMLSBFirst; + u32 PCMRightJustify; + u32 PCMRouting; + u32 PCMShortFrameSync; + u32 PCMSyncMode; + + char tty_name[64]; + + struct btbcm_uart_callbacks protocol_callbacks; + struct work_struct wakeup_work; +}; + +/* List of BCM BT UART devices */ +static DEFINE_SPINLOCK(device_list_lock); +static LIST_HEAD(device_list); + +/* + * Calling the BCM protocol at lower execution priority + */ +static void bcm_bt_wakeup_task(struct work_struct *ws) +{ + int resume_flag; + struct bcm_device *p_bcm_device = + container_of(ws, struct bcm_device, wakeup_work); + + if (!p_bcm_device) { + BT_DBG("bcm_bt_wakeup_task - failing, no device"); + return; + } + + /* Make sure the device is resumed */ + resume_flag = !p_bcm_device->dev_wake_active_low; + if (p_bcm_device->dev_wake_gpio) { + gpiod_set_value(p_bcm_device->dev_wake_gpio, resume_flag); + BT_DBG("bcm_bt_wakeup_task - resume %d written, delaying 15 ms", + resume_flag); + mdelay(15); + } + + /* Let the protocol know it's time to wake up */ + if (p_bcm_device->protocol_callbacks.p_wakeup) + p_bcm_device->protocol_callbacks.p_wakeup( + p_bcm_device->protocol_callbacks.context); +} + +/* + * Interrupt routine for the wake from the device + */ +static irqreturn_t bcm_bt_uart_isr(int irq, void *context) +{ + unsigned int bt_wake; + struct bcm_device *p = (struct bcm_device *)context; + + bt_wake = gpiod_get_value(p->bt_wake_gpio); + BT_DBG("bcm_bt_uart_isr with bt_wake of %d (active_low %d), req bh", + bt_wake, p->bt_wake_active_low); + + /* Defer the actual processing to the platform work queue */ + schedule_work(&p->wakeup_work); + return IRQ_HANDLED; +} + +/* + * Device instance startup + */ +static int bcm_bt_uart_probe(struct platform_device *pdev) +{ + int ret = 0; + struct device_node *np = pdev->dev.of_node; + const char *tty_name; + struct bcm_device *p_bcm_device = NULL; + + p_bcm_device = devm_kzalloc(&pdev->dev, sizeof(*p_bcm_device), + GFP_KERNEL); + if (!p_bcm_device) { + BT_DBG("bcm_bt_uart_probe - failing due to no memory"); + return -ENOMEM; + } + p_bcm_device->pdev = pdev; + BT_DBG("bcm_bt_uart_probe %p context", p_bcm_device); + + /* Get dev wake GPIO */ + p_bcm_device->dev_wake_gpio = gpiod_get(&pdev->dev, "bt-wake"); + BT_DBG("bcm_bt_uart_probe - gpiod_get for bt-wake returned %p", + p_bcm_device->dev_wake_gpio); + if (IS_ERR(p_bcm_device->dev_wake_gpio)) { + ret = PTR_ERR(p_bcm_device->dev_wake_gpio); + if (ret != -ENOENT) { + dev_err(&pdev->dev, + "bcm_bt_uart_probe - dev_wake GPIO: %d\n", ret); + } + p_bcm_device->dev_wake_gpio = NULL; + } else { + int resume_flag; + + p_bcm_device->dev_wake_active_low = gpiod_is_active_low + (p_bcm_device->dev_wake_gpio); + BT_DBG("bcm_bt_uart_probe - dev_wake a-low is %d (cans %d)", + p_bcm_device->dev_wake_active_low, + gpiod_cansleep(p_bcm_device->dev_wake_gpio)); + + /* configure dev_wake as output with init resumed state */ + resume_flag = !p_bcm_device->dev_wake_active_low; + ret = gpiod_direction_output(p_bcm_device->dev_wake_gpio, + resume_flag); + if (ret < 0) { + dev_err(&pdev->dev, + "bcm_bt_uart_probe s dev_wake GPIO: %d\n", ret); + gpiod_put(p_bcm_device->dev_wake_gpio); + p_bcm_device->dev_wake_gpio = NULL; + goto end; + } else { + BT_DBG("bcm_bt_uart_probe - dev_wake set to %d", + resume_flag); + } + } + + /* Get power on/off GPIO */ + p_bcm_device->reg_on_gpio = gpiod_get(&pdev->dev, "reg-on"); + BT_DBG("bcm_bt_uart_probe - gpiod_get for reg-on returned %p", + p_bcm_device->reg_on_gpio); + if (IS_ERR(p_bcm_device->reg_on_gpio)) { + ret = PTR_ERR(p_bcm_device->reg_on_gpio); + if (ret != -ENOENT) { + dev_err(&pdev->dev, + "bcm_bt_uart_probe - reg_on GPIO: %d\n", ret); + } + p_bcm_device->reg_on_gpio = NULL; + } else { + int poweron_flag; + + p_bcm_device->reg_on_active_low = gpiod_is_active_low + (p_bcm_device->reg_on_gpio); + BT_DBG("bcm_bt_uart_probe - reg_on a-low is %d (cans %d)", + p_bcm_device->reg_on_active_low, + gpiod_cansleep(p_bcm_device->reg_on_gpio)); + + /* configure reg_on as output with init on state */ + poweron_flag = !p_bcm_device->reg_on_active_low; + ret = gpiod_direction_output(p_bcm_device->reg_on_gpio, + poweron_flag); + if (ret < 0) { + dev_err(&pdev->dev, + "bcm_bt_uart_probe s reg_on GPIO: %d\n", ret); + gpiod_put(p_bcm_device->reg_on_gpio); + p_bcm_device->reg_on_gpio = NULL; + } else { + BT_DBG("bcm_bt_uart_probe - reg_on initially set to %d", + poweron_flag); + } + } + + platform_set_drvdata(pdev, p_bcm_device); + /* Must be done before interrupt is requested */ + INIT_WORK(&p_bcm_device->wakeup_work, bcm_bt_wakeup_task); + + /* Get bt host wake GPIO */ + p_bcm_device->bt_wake_gpio = gpiod_get(&pdev->dev, "bt-host-wake"); + BT_DBG("bcm_bt_uart_probe - gpiod_get for bt-host-wake returned %p", + p_bcm_device->bt_wake_gpio); + if (IS_ERR(p_bcm_device->bt_wake_gpio)) { + ret = PTR_ERR(p_bcm_device->bt_wake_gpio); + if (ret != -ENOENT) { + dev_err(&pdev->dev, + "bcm_bt_uart_probe - bt_wake GPIO: %d\n", ret); + } + p_bcm_device->bt_wake_gpio = NULL; + } else { + /* configure bt_wake as input */ + ret = gpiod_direction_input(p_bcm_device->bt_wake_gpio); + if (ret < 0) { + dev_err(&pdev->dev, + "bcm_bt_uart_probe s bt_wake GPIO: %d\n", ret); + gpiod_put(p_bcm_device->bt_wake_gpio); + p_bcm_device->bt_wake_gpio = NULL; + } else { + p_bcm_device->bt_wake_active_low = gpiod_is_active_low + (p_bcm_device->bt_wake_gpio); + BT_DBG("bcm_bt_uart_probe -bt_wake a-low is %d(cans%d)", + p_bcm_device->bt_wake_active_low, + gpiod_cansleep(p_bcm_device->bt_wake_gpio)); + p_bcm_device->bt_wake_irq = gpiod_to_irq + (p_bcm_device->bt_wake_gpio); + if (p_bcm_device->bt_wake_irq < 0) { + dev_err(&pdev->dev, + "bcm_bt_uart_probe - HOST_WAKE IRQ: %d\n", ret); + } else { + unsigned long intflags = IRQF_TRIGGER_RISING; + + if (p_bcm_device->bt_wake_active_low) + intflags = IRQF_TRIGGER_FALLING; + + ret = request_irq(p_bcm_device->bt_wake_irq, + bcm_bt_uart_isr, + intflags, "bt_host_wake", + p_bcm_device); + if (ret < 0) { + dev_err(&pdev->dev, "bcm_bt_uart_probe - failed to conf IRQ %d: %d", + p_bcm_device->bt_wake_irq, ret); + } else { + BT_DBG("bcm_bt_uart_probe - IRQ %d", + p_bcm_device->bt_wake_irq); + } + } + } + } + + p_bcm_device->configure_sleep = 0; + if (!of_property_read_u32(np, "configure-sleep", + &p_bcm_device->configure_sleep)) { + BT_DBG("configure-sleep read as %d", + p_bcm_device->configure_sleep); + } + p_bcm_device->manual_fc = 0; + if (!of_property_read_u32(np, "manual-fc", + &p_bcm_device->manual_fc)) { + BT_DBG("manual-fc read as %d", + p_bcm_device->manual_fc); + } + p_bcm_device->baud_rate_before_config_download = 3000000; + if (!of_property_read_u32( + np, "baud-rate-before-config-download", + &p_bcm_device->baud_rate_before_config_download)) { + BT_DBG("baud-rate-before-config-download read as %d", + p_bcm_device->baud_rate_before_config_download); + } + p_bcm_device->configure_audio = 0; + if (!of_property_read_u32(np, "configure-audio", + &p_bcm_device->configure_audio)) { + BT_DBG("configure-audio read as %d", + p_bcm_device->configure_audio); + } + if (p_bcm_device->configure_audio) { + /* Defaults for audio */ + p_bcm_device->PCMClockMode = 0; + p_bcm_device->PCMFillMethod = 2; + p_bcm_device->PCMFillNum = 0; + p_bcm_device->PCMFillValue = 3; + p_bcm_device->PCMInCallBitclock = 0; + p_bcm_device->PCMLSBFirst = 0; + p_bcm_device->PCMRightJustify = 0; + p_bcm_device->PCMRouting = 0; + p_bcm_device->PCMShortFrameSync = 0; + p_bcm_device->PCMSyncMode = 0; + + if (!of_property_read_u32(np, "PCMClockMode", + &p_bcm_device->PCMClockMode)) + BT_DBG("PCMClockMode read as %d", + p_bcm_device->PCMClockMode); + if (!of_property_read_u32(np, "PCMFillMethod", + &p_bcm_device->PCMFillMethod)) + BT_DBG("PCMFillMethod readas %d", + p_bcm_device->PCMFillMethod); + if (!of_property_read_u32(np, "PCMFillNum", + &p_bcm_device->PCMFillNum)) + BT_DBG("PCMFillNum read as %d", + p_bcm_device->PCMFillNum); + if (!of_property_read_u32(np, "PCMFillValue", + &p_bcm_device->PCMFillValue)) + BT_DBG("PCMFillValue read as %d", + p_bcm_device->PCMFillValue); + if (!of_property_read_u32(np, "PCMInCallBitclock", + &p_bcm_device->PCMInCallBitclock)) + BT_DBG("PCMInCallBitclock read as %d", + p_bcm_device->PCMInCallBitclock); + if (!of_property_read_u32(np, "PCMLSBFirst", + &p_bcm_device->PCMLSBFirst)) + BT_DBG("PCMLSBFirst read as %d", + p_bcm_device->PCMLSBFirst); + if (!of_property_read_u32(np, "PCMRightJustify", + &p_bcm_device->PCMRightJustify)) + BT_DBG("PCMRightJustify read as %d", + p_bcm_device->PCMRightJustify); + if (!of_property_read_u32(np, "PCMRouting", + &p_bcm_device->PCMRouting)) + BT_DBG("PCMRouting read as %d", + p_bcm_device->PCMRouting); + if (!of_property_read_u32(np, "PCMShortFrameSync", + &p_bcm_device->PCMShortFrameSync)) + BT_DBG("PCMShortFrameSync read as %d", + p_bcm_device->PCMShortFrameSync); + if (!of_property_read_u32(np, "PCMSyncMode", + &p_bcm_device->PCMSyncMode)) + BT_DBG("PCMSyncMode read as %d", + p_bcm_device->PCMSyncMode); + } + + if (!of_property_read_string(np, "tty", &tty_name)) { + strcpy(p_bcm_device->tty_name, tty_name); + BT_DBG("tty name read as %s", p_bcm_device->tty_name); + } + + BT_DBG("idleTimeout set as %d", idleTimeout); + + ret = 0; /* If we made it here, we're fine */ + + /* Place this instance on the device list */ + spin_lock(&device_list_lock); + list_add_tail(&p_bcm_device->list, &device_list); + spin_unlock(&device_list_lock); + +end: + if (ret) { + if (p_bcm_device->reg_on_gpio) { + gpiod_put(p_bcm_device->reg_on_gpio); + p_bcm_device->reg_on_gpio = NULL; + } + if (p_bcm_device->bt_wake_gpio) { + gpiod_put(p_bcm_device->bt_wake_gpio); + p_bcm_device->bt_wake_gpio = NULL; + } + if (p_bcm_device->dev_wake_gpio) { + gpiod_put(p_bcm_device->dev_wake_gpio); + p_bcm_device->dev_wake_gpio = NULL; + } + } + + BT_DBG("bcm_bt_uart_probe with the result %d", ret); + return ret; +} + +/* + * Device instance removal + */ +static int bcm_bt_uart_remove(struct platform_device *pdev) +{ + struct bcm_device *p_bcm_device = platform_get_drvdata(pdev); + + if (p_bcm_device == NULL) { + BT_DBG("bcm_bt_uart_remove - logic error, no probe?!"); + return 0; + } + + BT_DBG("bcm_bt_uart_remove %p context", p_bcm_device); + + spin_lock(&device_list_lock); + list_del(&p_bcm_device->list); + spin_unlock(&device_list_lock); + + BT_DBG("bcm_bt_uart_remove - freeing interrupt %d", + p_bcm_device->bt_wake_irq); + free_irq(p_bcm_device->bt_wake_irq, p_bcm_device); + + if (p_bcm_device->reg_on_gpio) { + BT_DBG("bcm_bt_uart_remove - releasing reg_on_gpio"); + gpiod_put(p_bcm_device->reg_on_gpio); + p_bcm_device->reg_on_gpio = NULL; + } + + if (p_bcm_device->dev_wake_gpio) { + BT_DBG("bcm_bt_uart_remove - releasing dev_wake_gpio"); + gpiod_put(p_bcm_device->dev_wake_gpio); + p_bcm_device->dev_wake_gpio = NULL; + } + + if (p_bcm_device->bt_wake_gpio) { + BT_DBG("bcm_bt_uart_remove - releasing bt_wake_gpio"); + gpiod_put(p_bcm_device->bt_wake_gpio); + p_bcm_device->bt_wake_gpio = NULL; + } + + BT_DBG("bcm_bt_uart_remove %p done", p_bcm_device); + return 0; +} + +/* + * Platform resume callback + */ +static int bcm_bt_uart_resume(struct device *pdev) +{ + int resume_flag; + struct bcm_device *p_bcm_device = platform_get_drvdata( + to_platform_device(pdev)); + + if (p_bcm_device == NULL) { + BT_DBG("bcm_bt_uart_resume - logic error, no device?!"); + return 0; + } + + BT_DBG("bcm_bt_uart_resume %p", p_bcm_device); + + resume_flag = !p_bcm_device->dev_wake_active_low; + if (p_bcm_device->dev_wake_gpio) { + gpiod_set_value(p_bcm_device->dev_wake_gpio, resume_flag); + BT_DBG("bcm_bt_uart_resume: %d written, delaying 15 ms", + resume_flag); + mdelay(15); + } + + /* Let the protocol know the platform is resuming */ + if (p_bcm_device->protocol_callbacks.p_resume) + p_bcm_device->protocol_callbacks.p_resume( + p_bcm_device->protocol_callbacks.context); + + return 0; +} + +/* + * Platform suspend callback + */ +static int bcm_bt_uart_suspend(struct device *pdev) +{ + int resume_flag; + struct bcm_device *p_bcm_device = platform_get_drvdata( + to_platform_device(pdev)); + + if (p_bcm_device == NULL) { + BT_DBG("bcm_bt_uart_suspend - logic error, no device?!"); + return 0; + } + + BT_DBG("bcm_bt_uart_suspend %p", p_bcm_device); + + /* Let the protocol know the platform is suspending */ + if (p_bcm_device->protocol_callbacks.p_suspend) + p_bcm_device->protocol_callbacks.p_suspend( + p_bcm_device->protocol_callbacks.context); + + /* Suspend the device */ + if (p_bcm_device->dev_wake_gpio) { + resume_flag = !p_bcm_device->dev_wake_active_low; + gpiod_set_value(p_bcm_device->dev_wake_gpio, !resume_flag); + BT_DBG("bcm_bt_uart_suspend: %d written, delaying 15 ms", + !resume_flag); + mdelay(15); + } + + return 0; +} + +/* + * Entry point for calls from the protocol + */ +int btbcm_uart_control(int action, void *device_context, + void *p_data, unsigned long *p_size) +{ + struct btbcm_uart_callbacks *pc; + struct btbcm_uart_parameters *pp = p_data; /* for pars action only */ + int ret = 0; + int resume_flag, poweron_flag; + struct bcm_device *p_bcm_device = device_context; + struct list_head *ptr; + bool is_found = false; + + /* Special processing for the callback configuration */ + if (action == BTBCM_UART_ACTION_CONFIGURE_CALLBACKS) { + pc = p_data; + + BT_DBG("btbcm_uart_control - configure callbacks"); + if ((p_data == NULL) || *p_size != sizeof(struct + btbcm_uart_callbacks) || (pc->interface_version != + BTBCM_UART_INTERFACE_VERSION)) { + BT_DBG("btbcm_uart_control - callbacks mismatch!"); + return -E2BIG; + } + + BT_DBG("btbcm_uart_control - configure callbacks for %s(%p)", + pc->name, pc->context); + if (p_bcm_device == NULL) { + spin_lock(&device_list_lock); + list_for_each(ptr, &device_list) { + p_bcm_device = list_entry(ptr, struct + bcm_device, list); + if (!strcmp(p_bcm_device->tty_name, pc->name)) { + is_found = true; + break; + } + } + + spin_unlock(&device_list_lock); + if (!is_found) { + BT_DBG("btbcm_uart_control - no device!"); + return -ENOENT; + } + } + + p_bcm_device->protocol_callbacks = *pc; + memcpy(p_data, &p_bcm_device, sizeof(p_bcm_device)); + *p_size = sizeof(p_bcm_device); + return ret; + } + + /* All other requests must have the right context */ + if (p_bcm_device == NULL) { + BT_DBG("btbcm_uart_control - failing, no device"); + return -ENOENT; + } + + switch (action) { + case BTBCM_UART_ACTION_POWER_ON: + BT_DBG("btbcm_uart_control %p - power on", device_context); + if (p_bcm_device->reg_on_gpio) { + poweron_flag = !p_bcm_device->reg_on_active_low; + gpiod_set_value(p_bcm_device->reg_on_gpio, + poweron_flag); + BT_DBG("btbcm_uart_control - pwron %d, delay 15 ms", + poweron_flag); + mdelay(15); + } + break; + + case BTBCM_UART_ACTION_POWER_OFF: + BT_DBG("btbcm_uart_control %p - power off", device_context); + if (p_bcm_device->reg_on_gpio) { + poweron_flag = p_bcm_device->reg_on_active_low; + gpiod_set_value(p_bcm_device->reg_on_gpio, + poweron_flag); + BT_DBG("btbcm_uart_control - pwroff %d, delay 15 ms", + poweron_flag); + mdelay(15); + } + break; + + case BTBCM_UART_ACTION_RESUME: + BT_DBG("btbcm_uart_control %p - resume", device_context); + if (p_bcm_device->dev_wake_gpio) { + resume_flag = !p_bcm_device->dev_wake_active_low; + gpiod_set_value(p_bcm_device->dev_wake_gpio, + resume_flag); + BT_DBG("btbcm_uart_control - resume %d, delay 15 ms", + resume_flag); + mdelay(15); + } + break; + + case BTBCM_UART_ACTION_SUSPEND: + BT_DBG("btbcm_uart_control %p - suspend", device_context); + if (p_bcm_device->dev_wake_gpio) { + resume_flag = !p_bcm_device->dev_wake_active_low; + gpiod_set_value(p_bcm_device->dev_wake_gpio, + !resume_flag); + BT_DBG("btbcm_uart_control - suspend %d, delay 15ms", + !resume_flag); + mdelay(15); + } + break; + + case BTBCM_UART_ACTION_GET_PARAMETERS: + BT_DBG("btbcm_uart_control %p - get pars", device_context); + if ((p_data == NULL) || + (*p_size < sizeof(struct btbcm_uart_parameters))) { + BT_DBG("btbcm_uart_control - failing, wrong par size"); + return -E2BIG; + } + + memset(pp, 0, sizeof(struct btbcm_uart_parameters)); + pp->interface_version = BTBCM_UART_INTERFACE_VERSION; + pp->configure_sleep = p_bcm_device->configure_sleep; + pp->manual_fc = p_bcm_device->manual_fc; + pp->dev_wake_active_low = p_bcm_device->dev_wake_active_low; + pp->bt_wake_active_low = p_bcm_device->bt_wake_active_low; + pp->idle_timeout_in_secs = idleTimeout; + pp->baud_rate_before_config_download = + p_bcm_device->baud_rate_before_config_download; + pp->configure_audio = p_bcm_device->configure_audio; + pp->PCMClockMode = p_bcm_device->PCMClockMode; + pp->PCMFillMethod = p_bcm_device->PCMFillMethod; + pp->PCMFillNum = p_bcm_device->PCMFillNum; + pp->PCMFillValue = p_bcm_device->PCMFillValue; + pp->PCMInCallBitclock = p_bcm_device->PCMInCallBitclock; + pp->PCMLSBFirst = p_bcm_device->PCMLSBFirst; + pp->PCMRightJustify = p_bcm_device->PCMRightJustify; + pp->PCMRouting = p_bcm_device->PCMRouting; + pp->PCMShortFrameSync = p_bcm_device->PCMShortFrameSync; + pp->PCMSyncMode = p_bcm_device->PCMSyncMode; + *p_size = sizeof(struct btbcm_uart_parameters); + break; + + default: + BT_DBG("btbcm_uart_control %p unknown act %d", + device_context, action); + ret = -EINVAL; + break; + } + + return ret; +} +EXPORT_SYMBOL(btbcm_uart_control); + +/* Platform susp and resume callbacks */ +static SIMPLE_DEV_PM_OPS(bcm_bt_uart_pm_ops, + bcm_bt_uart_suspend, bcm_bt_uart_resume); + +/* Driver match table */ +static const struct of_device_id bcm_bt_uart_match_table[] = { + { .compatible = "brcm,brcm-bt-uart" }, + {} +}; + +/* Driver configuration */ +static struct platform_driver bcm_bt_uart_platform_driver = { + .probe = bcm_bt_uart_probe, + .remove = bcm_bt_uart_remove, + .driver = { + .name = "brcm_bt_uart", + .of_match_table = of_match_ptr(bcm_bt_uart_match_table), + .owner = THIS_MODULE, + .pm = &bcm_bt_uart_pm_ops, + }, +}; + +module_platform_driver(bcm_bt_uart_platform_driver); + +MODULE_AUTHOR("Ilya Faenson"); +MODULE_DESCRIPTION("Broadcom Bluetooth UART Driver"); +MODULE_LICENSE("Dual BSD/GPL"); + diff --git a/drivers/bluetooth/btbcm_uart.h b/drivers/bluetooth/btbcm_uart.h new file mode 100644 index 0000000..5801753 --- /dev/null +++ b/drivers/bluetooth/btbcm_uart.h @@ -0,0 +1,90 @@ +/* + * + * Bluetooth BCM UART Driver Header + * + * Copyright (c) 2015 Broadcom Corporation + * + * 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. + * + */ +#ifndef BTBCM_UART_H +#define BTBCM_UART_H + +/* Change the version if you change anything in this header */ +#define BTBCM_UART_INTERFACE_VERSION 1 + +/* Callbacks from the driver into the protocol */ +typedef void (*p_suspend_callback)(void *context); +typedef void (*p_resume_callback)(void *context); +typedef void (*p_wakeup_callback)(void *context); +struct btbcm_uart_callbacks { + int interface_version; /* interface # compiled against */ + void *context; /* protocol instance context */ + char name[64]; /* protocol tty device, for example, ttyS0 */ + + /* Callbacks proper */ + p_suspend_callback p_suspend; + p_resume_callback p_resume; + p_wakeup_callback p_wakeup; +}; + +/* Driver parameters retrieved from the DT or ACPI */ +struct btbcm_uart_parameters { + int interface_version; /* interface # compiled against */ + + /* Parameters proper */ + int configure_sleep; + int manual_fc; + int dev_wake_active_low; + int bt_wake_active_low; + int idle_timeout_in_secs; + int baud_rate_before_config_download; + int configure_audio; + int PCMClockMode; + int PCMFillMethod; + int PCMFillNum; + int PCMFillValue; + int PCMInCallBitclock; + int PCMLSBFirst; + int PCMRightJustify; + int PCMRouting; + int PCMShortFrameSync; + int PCMSyncMode; +}; + +/* + * Actions on the BTBCM_UART driver + */ + +/* Configure protocol callbacks */ +#define BTBCM_UART_ACTION_CONFIGURE_CALLBACKS 0 + +/* Retrieve BT device parameters */ +#define BTBCM_UART_ACTION_GET_PARAMETERS 1 + +/* Resume the BT device via GPIO */ +#define BTBCM_UART_ACTION_RESUME 2 + +/* Suspend the BT device via GPIO */ +#define BTBCM_UART_ACTION_SUSPEND 3 + +/* Power the BT device off via GPIO */ +#define BTBCM_UART_ACTION_POWER_OFF 4 + +/* Power the BT device on via GPIO */ +#define BTBCM_UART_ACTION_POWER_ON 5 + +/* Execute an action on the BT device */ +extern int btbcm_uart_control(int action, void *device_context, + void *p_data, unsigned long *p_size); + +#endif + diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index 1ec0b4a..e70f89b 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -1,8 +1,13 @@ /* * - * Bluetooth HCI UART driver for Broadcom devices + * Bluetooth UART H4 protocol for Broadcom devices * - * Copyright (C) 2015 Intel Corporation + * Copyright (c) 2015 Intel Corporation + * Copyright (c) 2015 Broadcom Corporation + * + * Acknowledgements: + * This file has been based on hci_h4.c originally developed + * by Maxim Krasnyansky and Marcel Holtmann. * * * This program is free software; you can redistribute it and/or modify @@ -15,139 +20,842 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ +#include <linux/module.h> + #include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/interrupt.h> +#include <linux/ptrace.h> +#include <linux/poll.h> + +#include <linux/slab.h> +#include <linux/tty.h> #include <linux/errno.h> +#include <linux/string.h> +#include <linux/signal.h> +#include <linux/ioctl.h> #include <linux/skbuff.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> -#include "btbcm.h" +#include <linux/gpio/consumer.h> +#include <linux/of_gpio.h> +#include <linux/of_platform.h> + #include "hci_uart.h" +#include "btbcm.h" +#include "btbcm_uart.h" -struct bcm_data { - struct sk_buff *rx_skb; +/* Protocol context */ +struct bcm_h4_struct { struct sk_buff_head txq; + struct hci_uart *hu; + + bool is_suspended; /* suspend/resume flag */ + + /* Recv data parsing is not used in normal operation */ + bool parse_recv; + /* buffer includes the type */ + unsigned char reassembly[1 + HCI_MAX_FRAME_SIZE]; + unsigned int rsize; + u16 rexpected; + + struct timer_list timer; /* idle timer */ + + struct btbcm_uart_parameters pars; /* device parameters */ + void *device_context; /* ACPI/DT device context */ }; -static int bcm_open(struct hci_uart *hu) +/* Static function prototypes for forward references */ +static void suspend_notification(void *context); +static void resume_notification(void *context); +static void wakeup_notification(void *context); +static void bcm_ensure_wakeup(struct hci_uart *hu); + +/* Suspend/resume synchronization mutex */ +static DEFINE_MUTEX(plock); + +/* + * Idle timer callback + */ +static void bcm_idle_timeout(unsigned long arg) { - struct bcm_data *bcm; + struct hci_uart *hu = (struct hci_uart *)arg; + struct bcm_h4_struct *h4 = hu->priv; + int status; - BT_DBG("hu %p", hu); + BT_DBG("bcm_idle_timeout hu %p", hu); + + /* Suspend/resume operations are serialized */ + mutex_lock(&plock); + + if (!h4->is_suspended) { + /* Flow control the port if configured */ + suspend_notification(hu); + + /* Suspend the device */ + status = btbcm_uart_control(BTBCM_UART_ACTION_SUSPEND, + h4->device_context, NULL, NULL); + if (status) + BT_DBG("bcm_idle_timeout failed to suspend device %d", + status); + } - bcm = kzalloc(sizeof(*bcm), GFP_KERNEL); - if (!bcm) + mutex_unlock(&plock); +} + +/* + * Initialize protocol + */ +static int bcm_h4_open(struct hci_uart *hu) +{ + struct btbcm_uart_callbacks callbacks; + unsigned long callbacks_size = sizeof(callbacks); + int status; + struct bcm_h4_struct *h4; + struct tty_struct *tty = hu->tty; + + BT_DBG("bcm_h4_open hu %p", hu); + + h4 = kzalloc(sizeof(*h4), GFP_KERNEL); + if (!h4) return -ENOMEM; - skb_queue_head_init(&bcm->txq); + skb_queue_head_init(&h4->txq); + hu->priv = h4; + h4->hu = hu; + h4->is_suspended = false; + h4->parse_recv = false; + h4->rsize = 0; + + /* Configure callbacks on the driver */ + callbacks.interface_version = BTBCM_UART_INTERFACE_VERSION; + callbacks.context = hu; + strcpy(callbacks.name, tty->name); + callbacks.p_suspend = suspend_notification; + callbacks.p_resume = resume_notification; + callbacks.p_wakeup = wakeup_notification; + status = btbcm_uart_control(BTBCM_UART_ACTION_CONFIGURE_CALLBACKS, + NULL, &callbacks, &callbacks_size); + if (status) { + BT_DBG("bcm_h4_open failed to set driver callbacks %d", status); + return status; + } + if (callbacks_size != sizeof(void *)) { + BT_DBG("bcm_h4_open got back %d bytes from callbacks?!", + (int)callbacks_size); + return -EMSGSIZE; + } + memcpy(&h4->device_context, &callbacks, sizeof(void *)); + BT_DBG("bcm_h4_open callbacks context %p", h4->device_context); + + /* Retrieve device parameters */ + callbacks_size = sizeof(h4->pars); + status = btbcm_uart_control(BTBCM_UART_ACTION_GET_PARAMETERS, + h4->device_context, &h4->pars, + &callbacks_size); + if (status) { + BT_DBG("bcm_h4_open failed to get dev parameters %d", status); + return status; + } + BT_DBG("Pars ver %d csleep %d dalow %d balow %d idle %d", + h4->pars.interface_version, h4->pars.configure_sleep, + h4->pars.dev_wake_active_low, h4->pars.bt_wake_active_low, + h4->pars.idle_timeout_in_secs); + + /* Cycle power to make sure the device is in the known state */ + status = btbcm_uart_control(BTBCM_UART_ACTION_POWER_OFF, + h4->device_context, NULL, NULL); + if (status) { + BT_DBG("bcm_h4_open failed to power off %d", status); + } else { + status = btbcm_uart_control(BTBCM_UART_ACTION_POWER_ON, + h4->device_context, NULL, NULL); + if (status) + BT_DBG("bcm_h4_open failed to power on %d", status); + } + + /* Start the idle timer */ + if (h4->pars.configure_sleep) { + setup_timer(&h4->timer, bcm_idle_timeout, (unsigned long)hu); + if (h4->pars.configure_sleep) + mod_timer(&h4->timer, jiffies + msecs_to_jiffies( + h4->pars.idle_timeout_in_secs * 1000)); + } + + return 0; +} + +/* + * Flush protocol data + */ +static int bcm_h4_flush(struct hci_uart *hu) +{ + struct bcm_h4_struct *h4 = hu->priv; - hu->priv = bcm; + BT_DBG("bcm_h4_flush hu %p", hu); + + skb_queue_purge(&h4->txq); return 0; } -static int bcm_close(struct hci_uart *hu) +/* + * Make sure we're awake + * (called when the resumed state is required) + */ +static void bcm_ensure_wakeup(struct hci_uart *hu) { - struct bcm_data *bcm = hu->priv; + struct bcm_h4_struct *h4 = hu->priv; + int status; + + if (!h4->pars.configure_sleep) + return; + + /* Suspend/resume operations are serialized */ + mutex_lock(&plock); + + /* Nothing to do if resumed already */ + if (!h4->is_suspended) { + mutex_unlock(&plock); - BT_DBG("hu %p", hu); + /* Just reset the timer */ + status = mod_timer(&h4->timer, jiffies + msecs_to_jiffies( + h4->pars.idle_timeout_in_secs * 1000)); + return; + } + + /* Wakeup the device */ + status = btbcm_uart_control(BTBCM_UART_ACTION_RESUME, + h4->device_context, NULL, NULL); + if (status) + BT_DBG("bcm_ensure_wakeup failed to resume driver %d", status); - skb_queue_purge(&bcm->txq); - kfree_skb(bcm->rx_skb); - kfree(bcm); + /* Unflow control the port if configured */ + resume_notification(hu); + + mutex_unlock(&plock); +} + +/* + * Close protocol + */ +static int bcm_h4_close(struct hci_uart *hu) +{ + struct btbcm_uart_callbacks callbacks; + unsigned long callbacks_size = sizeof(callbacks); + struct bcm_h4_struct *h4 = hu->priv; + int status; hu->priv = NULL; + + BT_DBG("bcm_h4_close hu %p", hu); + + /* If we're being closed, we must suspend */ + if (h4->pars.configure_sleep) { + mutex_lock(&plock); + + if (!h4->is_suspended) { + /* Flow control the port */ + suspend_notification(hu); + + /* Suspend the device */ + status = btbcm_uart_control(BTBCM_UART_ACTION_SUSPEND, + h4->device_context, NULL, + NULL); + if (status) { + BT_DBG("bcm_h4_close suspend driver fail %d", + status); + } + } + + mutex_unlock(&plock); + + del_timer_sync(&h4->timer); + } + + /* Power off the device if possible */ + status = btbcm_uart_control(BTBCM_UART_ACTION_POWER_OFF, + h4->device_context, NULL, NULL); + if (status) + BT_DBG("bcm_h4_close failed to power off %d", status); + + /* de-configure callbacks on the driver */ + callbacks.interface_version = BTBCM_UART_INTERFACE_VERSION; + callbacks.context = hu; + callbacks.p_suspend = NULL; + callbacks.p_resume = NULL; + callbacks.p_wakeup = NULL; + status = btbcm_uart_control(BTBCM_UART_ACTION_CONFIGURE_CALLBACKS, + h4->device_context, &callbacks, + &callbacks_size); + if (status) + BT_DBG("bcm_h4_close failed to reset drv callbacks %d", status); + skb_queue_purge(&h4->txq); + + hu->priv = NULL; + kfree(h4); + return 0; } -static int bcm_flush(struct hci_uart *hu) +/* + * Enqueue frame for transmittion (padding, crc, etc) + */ +static int bcm_h4_enqueue(struct hci_uart *hu, struct sk_buff *skb) { - struct bcm_data *bcm = hu->priv; + struct bcm_h4_struct *h4 = hu->priv; + + BT_DBG("bcm_h4_enqueue hu %p skb %p type %d len %d (%x %x %x)", + hu, skb, bt_cb(skb)->pkt_type, skb->len, + skb->data[0], skb->data[1], skb->data[2]); - BT_DBG("hu %p", hu); + /* Make sure we're resumed */ + bcm_ensure_wakeup(hu); - skb_queue_purge(&bcm->txq); + /* Prepend skb with frame type */ + memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); + skb_queue_tail(&h4->txq, skb); return 0; } -static int bcm_setup(struct hci_uart *hu) +/* + * HCI event processing if our own parsing of events is required + * NOTE: return 0 if the event is not to be passed up to BlueZ + */ +static bool bcm_process_hci_event(struct hci_uart *hu) +{ + struct bcm_h4_struct *h4 = hu->priv; + int status; + unsigned char evt_code = h4->reassembly[1]; + unsigned char len = h4->reassembly[2]; + + BT_DBG("bcm_process_hci_event %02x event %02x len %02x %02x", + h4->reassembly[0], evt_code, len, h4->reassembly[3]); + + /* switch (evt_code) { case HCI_EV_CMD_COMPLETE: break } */ + + status = hci_recv_stream_fragment(hu->hdev, h4->reassembly, h4->rsize); + if (status < 0) + BT_ERR("bcm_process_hci_event - reassembly failed %d", status); + return true; +} + +/* + * ACL data processing if our own parsing of data is required + * NOTE: return 0 if the data is not to be passed up to BlueZ + */ +static bool bcm_process_acl_data(struct hci_uart *hu) { - BT_DBG("hu %p", hu); + struct bcm_h4_struct *h4 = hu->priv; + int ret; - hu->hdev->set_bdaddr = btbcm_set_bdaddr; + BT_DBG("bcm_process_acl_data %02x %02x %02x %02x %02x", + h4->reassembly[0], h4->reassembly[1], h4->reassembly[2], + h4->reassembly[3], h4->reassembly[4]); - return btbcm_setup_patchram(hu->hdev); + ret = hci_recv_stream_fragment(hu->hdev, h4->reassembly, h4->rsize); + if (ret < 0) + BT_ERR("bcm_process_acl_data - Frame Reassembly Failed"); + return true; } -static const struct h4_recv_pkt bcm_recv_pkts[] = { - { H4_RECV_ACL, .recv = hci_recv_frame }, - { H4_RECV_SCO, .recv = hci_recv_frame }, - { H4_RECV_EVENT, .recv = hci_recv_frame }, -}; +/* + * Fragment parsing in the active filtering phase + * (not currently actively used) + */ +static void parse_fragment(struct hci_uart *hu, unsigned char *data, int count) +{ + struct bcm_h4_struct *h4 = hu->priv; + + if (h4->rsize) + BT_DBG("parse_fragment type %x expected %d", + h4->reassembly[0], h4->rexpected); + + while (count) { + if (!h4->rsize) { + /* Start of the frame */ + h4->reassembly[0] = *data++; + h4->rsize++; + count--; + continue; + } + + switch (h4->reassembly[0]) { + case HCI_EVENT_PKT: + if (h4->rsize == 1) { + /* event proper */ + h4->reassembly[h4->rsize++] = *data++; + count--; + continue; + } + if (h4->rsize == 2) { + /* length */ + h4->rexpected = *data; + h4->reassembly[h4->rsize++] = *data++; + count--; + BT_DBG("evthdr len %d, left %d", h4->rexpected, count); + continue; + } + if (count >= h4->rexpected) { + memcpy(&h4->reassembly[h4->rsize], data, h4->rexpected); + h4->rsize += h4->rexpected; + data += h4->rexpected; + count -= h4->rexpected; + bcm_process_hci_event(hu); + h4->rsize = 0; /* starting anew */ + continue; + } + /* only piece of the event received */ + memcpy(&h4->reassembly[h4->rsize], data, count); + h4->rsize += count; + data += count; + h4->rexpected -= count; + count = 0; + break; + + case HCI_ACLDATA_PKT: + if ((h4->rsize == 1) || (h4->rsize == 2) || (h4->rsize == 3)) { + /* handle and first byte of length */ + h4->reassembly[h4->rsize++] = *data++; + count--; + continue; + } + if (h4->rsize == 4) { + /* last byte of the length */ + h4->reassembly[h4->rsize++] = *data++; + h4->rexpected = h4->reassembly[h4->rsize - 2] + + (h4->reassembly[h4->rsize - 1] << 8); + count--; + BT_DBG("dathdr len %d, left %d", h4->rexpected, count); + continue; + } + if (count >= h4->rexpected) { + memcpy(&h4->reassembly[h4->rsize], data, h4->rexpected); + h4->rsize += h4->rexpected; + data += h4->rexpected; + count -= h4->rexpected; + bcm_process_acl_data(hu); + h4->rsize = 0; /* starting anew */ + continue; + } + /* only piece of data received */ + memcpy(&h4->reassembly[h4->rsize], data, count); + h4->rsize += count; + data += count; + h4->rexpected -= count; + count = 0; + break; + + default: /* Note that SCO may NOT come through the UART */ + if (count >= 3) + BT_DBG("unexpected pkt type of %x (%02x %02x %02x)?!", + h4->reassembly[0], data[0], data[1], data[2]); + else if (count == 2) + BT_DBG("unexpected pkt type of %x (%02x %02x)?!", + h4->reassembly[0], data[0], data[1]); + else if (count == 1) + BT_DBG("unexpected pkt type of %x (%02x)?!", + h4->reassembly[0], data[0]); + else + BT_DBG("unexpected pkt type of %x?!", + h4->reassembly[0]); + h4->rsize = 0; + return; + } + } +} -static int bcm_recv(struct hci_uart *hu, const void *data, int count) +/* + * Data indication from the line discipline + */ +static int bcm_h4_recv(struct hci_uart *hu, void *data, int count) { - struct bcm_data *bcm = hu->priv; + struct bcm_h4_struct *h4 = hu->priv; + int ret; - if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) + BT_DBG("bcm_h4_recv hu %p len %d", hu, count); + + if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) { + BT_DBG("h4_recv UART not registered!"); return -EUNATCH; + } - bcm->rx_skb = h4_recv_buf(hu->hdev, bcm->rx_skb, data, count, - bcm_recv_pkts, ARRAY_SIZE(bcm_recv_pkts)); - if (IS_ERR(bcm->rx_skb)) { - int err = PTR_ERR(bcm->rx_skb); - BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); - return err; + /* Make sure we're resumed */ + bcm_ensure_wakeup(hu); + + /* If we're in the active phase, parse what we get */ + if (h4->parse_recv) { + parse_fragment(hu, data, count); + } else { + ret = hci_recv_stream_fragment(hu->hdev, data, count); + if (ret < 0) { + BT_ERR("bcm_h4_recv: frame reassembly failed"); + return ret; + } } return count; } -static int bcm_enqueue(struct hci_uart *hu, struct sk_buff *skb) +/* + * Line discipline is grabbing a packet from the tx queue + */ +static struct sk_buff *bcm_h4_dequeue(struct hci_uart *hu) { - struct bcm_data *bcm = hu->priv; + struct bcm_h4_struct *h4 = hu->priv; + int is_qempty = skb_queue_empty(&h4->txq); - BT_DBG("hu %p skb %p", hu, skb); + if (!is_qempty) + BT_DBG("bcm_h4_dequeue with non-empty queue"); + return skb_dequeue(&h4->txq); +} - /* Prepend skb with frame type */ - memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); - skb_queue_tail(&bcm->txq, skb); +/* + * Callbacks from the BCMBT_UART device + */ - return 0; +/* + * The platform is suspending. Stop UART activity + */ +static void suspend_notification(void *context) +{ + struct ktermios ktermios; + struct hci_uart *hu = (struct hci_uart *)context; + struct bcm_h4_struct *h4 = hu->priv; + struct tty_struct *tty = hu->tty; + int status; + unsigned int set = 0; + unsigned int clear = 0; + + BT_DBG("suspend_notification with is_suspended %d", h4->is_suspended); + + if (!h4->pars.configure_sleep) + return; + + if (!h4->is_suspended) { + if (h4->pars.manual_fc) { + /* Disable hardware flow control */ + ktermios = tty->termios; + ktermios.c_cflag &= ~CRTSCTS; + status = tty_set_termios(tty, &ktermios); + if (status) + BT_DBG("suspend_notification dis fc fail %d", + status); + else + BT_DBG("suspend_notification hw fc disabled"); + + /* Clear RTS to prevent the device from sending */ + /* (most PCs need OUT2 to enable interrupts) */ + status = tty->driver->ops->tiocmget(tty); + BT_DBG("suspend_notification cur tiocm 0x%x", status); + set &= ~(TIOCM_OUT2 | TIOCM_RTS); + clear = ~set; + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | + TIOCM_OUT2 | TIOCM_LOOP; + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | + TIOCM_OUT2 | TIOCM_LOOP; + status = tty->driver->ops->tiocmset(tty, set, clear); + if (status) + BT_DBG("suspend_notification clr RTS fail %d", + status); + else + BT_DBG("suspend_notification RTS cleared"); + status = tty->driver->ops->tiocmget(tty); + BT_DBG("suspend_notification end tiocm 0x%x", status); + } + + /* Once this callback returns, driver suspends BT via GPIO */ + h4->is_suspended = true; + } +} + +/* + * The platform is resuming. Resume UART activity. + */ +static void resume_notification(void *context) +{ + struct ktermios ktermios; + struct hci_uart *hu = (struct hci_uart *)context; + struct bcm_h4_struct *h4 = hu->priv; + struct tty_struct *tty = hu->tty; + int status; + unsigned int set = 0; + unsigned int clear = 0; + + BT_DBG("resume_notification with is_suspended %d", h4->is_suspended); + + if (!h4->pars.configure_sleep) + return; + + /* When this callback executes, the device has woken up already */ + if (h4->is_suspended) { + h4->is_suspended = false; + + if (h4->pars.manual_fc) { + status = tty->driver->ops->tiocmget(tty); + BT_DBG("resume_notification cur tiocm 0x%x", status); + set |= (TIOCM_OUT2 | TIOCM_RTS); + clear = ~set; + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | + TIOCM_OUT2 | TIOCM_LOOP; + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | + TIOCM_OUT2 | TIOCM_LOOP; + status = tty->driver->ops->tiocmset(tty, set, clear); + if (status) + BT_DBG("resume_notification set RTS fail %d", + status); + else + BT_DBG("resume_notification RTS set"); + + /* Re-enable hardware flow control */ + ktermios = tty->termios; + ktermios.c_cflag |= CRTSCTS; + status = tty_set_termios(tty, &ktermios); + if (status) + BT_DBG("resume_notification enable fc fail %d", + status); + else + BT_DBG("resume_notification hw fc re-enabled"); + } + } + + /* If we're resumed, the idle timer must be running */ + status = mod_timer(&h4->timer, jiffies + + msecs_to_jiffies(h4->pars.idle_timeout_in_secs * 1000)); } -static struct sk_buff *bcm_dequeue(struct hci_uart *hu) +/* + * The BT device is resuming. Resume UART activity if suspended + */ +static void wakeup_notification(void *context) { - struct bcm_data *bcm = hu->priv; + struct ktermios ktermios; + struct hci_uart *hu = (struct hci_uart *)context; + struct bcm_h4_struct *h4 = hu->priv; + struct tty_struct *tty = hu->tty; + int status; + unsigned int set = 0; + unsigned int clear = 0; + + if (!h4->pars.configure_sleep) + return; + + status = tty->driver->ops->tiocmget(tty); + BT_DBG("wakeup_notification hu %p current tiocm 0x%x", hu, status); + if (h4->is_suspended) { + if (h4->pars.manual_fc) { + set |= (TIOCM_OUT2 | TIOCM_RTS); + clear = ~set; + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | + TIOCM_OUT2 | TIOCM_LOOP; + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | + TIOCM_OUT2 | TIOCM_LOOP; + status = tty->driver->ops->tiocmset(tty, set, clear); + if (status) + BT_DBG("wakeup_notification set RTS fail %d", + status); + else + BT_DBG("wakeup_notification RTS set"); + + /* Re-enable hardware flow control */ + ktermios = tty->termios; + ktermios.c_cflag |= CRTSCTS; + status = tty_set_termios(tty, &ktermios); + if (status) + BT_DBG("wakeup_notification fc-en failure %d", + status); + else + BT_DBG("wakeup_notification hw fc re-enabled"); + } + + h4->is_suspended = false; + } - return skb_dequeue(&bcm->txq); + /* If we're resumed, the idle timer must be running */ + status = mod_timer(&h4->timer, jiffies + msecs_to_jiffies( + h4->pars.idle_timeout_in_secs * 1000)); } -static const struct hci_uart_proto bcm_proto = { +/* + * Device setup that follows the protocol open + */ +static int bcm_h4_setup(struct hci_uart *hu) +{ + struct bcm_h4_struct *h4 = hu->priv; + int status; + struct sk_buff *skb; + unsigned char sleep_pars[] = { + 0x01, /* sleep mode 1=UART */ + 0x02, /* idle threshold HOST (value * 300ms) */ + 0x02, /* idle threshold HC (value * 300ms) */ + 0x01, /* BT_WAKE active mode - 1=active high, 0 = active low */ + 0x00, /* HOST_WAKE active mode - 1=active high, 0 = active low */ + 0x01, /* Allow host sleep during SCO - FALSE */ + 0x01, /* combine sleep mode and LPM - 1 == TRUE */ + 0x00, /* enable tristate control of UART TX line - FALSE */ + 0x00, /* USB auto-sleep on USB SUSPEND */ + 0x00, /* USB USB RESUME timeout (seconds) */ + 0x00, /* Pulsed Host Wake */ + 0x00 /* Enable Break To Host */ + }; + unsigned char pcm_int_pars[] = { + 0x00, /* 0=PCM routing, 1=SCO over HCI */ + 0x02, /* 0=128Kbps,1=256Kbps,2=512Kbps,3=1024Kbps,4=2048Kbps */ + 0x00, /* short frame sync 0=short, 1=long */ + 0x00, /* sync mode 0=slave, 1=master */ + 0x00 /* clock mode 0=slave, 1=master */ + }; + unsigned char pcm_format_pars[] = { + 0x00, /* LSB_First 1=TRUE, 0=FALSE */ + 0x00, /* Fill_Value (use 0-7 for fill bits value) */ + 0x02, /* Fill_Method (2=sign extended) */ + 0x03, /* Fill_Num # of fill bits 0-3) */ + 0x01 /* Right_Justify 1=TRUE, 0=FALSE */ + }; + unsigned char time_slot_number = 0; + + BT_DBG("bcm_h4_setup hu %p", hu); + + /* Bring the UART into known default state */ + status = btbcm_init_uart(hu); + if (status) { + BT_DBG("bcm_h4_setup failed to init BT device %d", status); + return status; + } + + /* Basic sanity check */ + skb = __hci_cmd_sync(hu->hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + status = PTR_ERR(skb); + BT_ERR("bcm_h4_setup HCI Reset failed (%d)", status); + return status; + } + kfree_skb(skb); + BT_DBG("bcm_h4_setup HCI Reset succeeded"); + + /* Set the new baud rate */ + status = btbcm_set_baud_rate(hu, + h4->pars.baud_rate_before_config_download); + if (status) { + BT_ERR("bcm_h4_setup set_baud_rate faiilure %d", status); + return status; + } + + hu->hdev->set_bdaddr = btbcm_set_bdaddr; + + /* Download the firmware and reconfigure the UART afterwards */ + status = btbcm_setup_patchram(hu->hdev); + if (status) { + BT_ERR("bcm_h4_setup setup_patchram faiilure %d", status); + return status; + } + + /* Configure SCO PCM parameters */ + if (h4->pars.configure_audio) { + pcm_int_pars[0] = h4->pars.PCMRouting; + pcm_int_pars[1] = h4->pars.PCMInCallBitclock; + pcm_int_pars[2] = h4->pars.PCMShortFrameSync; + pcm_int_pars[3] = h4->pars.PCMSyncMode; + pcm_int_pars[4] = h4->pars.PCMClockMode; + skb = __hci_cmd_sync(hu->hdev, 0xfc1c, sizeof(pcm_int_pars), + pcm_int_pars, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + status = PTR_ERR(skb); + BT_ERR("bcm_h4_setup PCM INT VSC failed (%d)", status); + return status; + } + kfree_skb(skb); + BT_DBG("bcm_h4_setup PCM INT Parameters VSC succeeded"); + + pcm_format_pars[0] = h4->pars.PCMLSBFirst; + pcm_format_pars[1] = h4->pars.PCMFillValue; + pcm_format_pars[2] = h4->pars.PCMFillMethod; + pcm_format_pars[3] = h4->pars.PCMFillNum; + pcm_format_pars[4] = h4->pars.PCMRightJustify; + skb = __hci_cmd_sync(hu->hdev, 0xfc1e, sizeof(pcm_format_pars), + pcm_format_pars, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + status = PTR_ERR(skb); + BT_ERR("bcm_h4_setup PCM Format VSC failed (%d)", + status); + return status; + } + kfree_skb(skb); + BT_DBG("bcm_h4_setup PCM Format VSC succeeded"); + + skb = __hci_cmd_sync(hu->hdev, 0xfc22, sizeof(time_slot_number), + &time_slot_number, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + status = PTR_ERR(skb); + BT_ERR("bcm_h4_setup SCO Time Slot VSC failed (%d)", + status); + return status; + } + kfree_skb(skb); + BT_DBG("bcm_h4_setup SCO Time Slot VSC succeeded"); + } + + /* Configure device's suspend/resume operation */ + if (h4->pars.configure_sleep) { + /* Override the default */ + sleep_pars[3] = (unsigned char)!h4->pars.bt_wake_active_low; + sleep_pars[4] = (unsigned char)!h4->pars.dev_wake_active_low; + skb = __hci_cmd_sync(hu->hdev, 0xfc27, sizeof(sleep_pars), + sleep_pars, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + status = PTR_ERR(skb); + BT_ERR("bcm_h4_setup Sleep VSC failed (%d)", status); + return status; + } + kfree_skb(skb); + BT_DBG("bcm_h4_setup Set Sleep Parameters VSC succeeded"); + } + + return 0; +} + +/* + * Protocol callbacks + */ +static struct hci_uart_proto h4p = { .id = HCI_UART_BCM, - .name = "BCM", - .open = bcm_open, - .close = bcm_close, - .flush = bcm_flush, - .setup = bcm_setup, - .recv = bcm_recv, - .enqueue = bcm_enqueue, - .dequeue = bcm_dequeue, + .name = "UARTBCM", + .open = bcm_h4_open, + .close = bcm_h4_close, + .flush = bcm_h4_flush, + .setup = bcm_h4_setup, + .recv = bcm_h4_recv, + .enqueue = bcm_h4_enqueue, + .dequeue = bcm_h4_dequeue, }; +/* + * Protocol init + */ int __init bcm_init(void) { - return hci_uart_register_proto(&bcm_proto); + int status = hci_uart_register_proto(&h4p); + + if (!status) + BT_INFO("Broadcom H4 protocol initialized"); + else + BT_ERR("Broadcom H4 protocol registration failed %d", status); + + return status; } +/* + * Protocol shutdown + */ int __exit bcm_deinit(void) { - return hci_uart_unregister_proto(&bcm_proto); + BT_INFO("Broadcom H4 protocol de-initialized"); + return hci_uart_unregister_proto(&h4p); } + -- 1.9.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [RFC 2/2] Broadcom Bluetooth UART device driver 2015-05-07 20:25 ` [RFC 2/2] Broadcom Bluetooth UART device driver Ilya Faenson @ 2015-05-11 19:03 ` Marcel Holtmann 2015-05-13 21:50 ` Ilya Faenson 0 siblings, 1 reply; 6+ messages in thread From: Marcel Holtmann @ 2015-05-11 19:03 UTC (permalink / raw) To: Ilya Faenson; +Cc: linux-bluetooth Hi Ilya, > This code implements the Broadcom Bluetooth device driver. > It manages device configuration, firmware download and > power management. > > Signed-off-by: Ilya Faenson <ifaenson@broadcom.com> > --- > drivers/bluetooth/Kconfig | 35 +- > drivers/bluetooth/Makefile | 1 + > drivers/bluetooth/btbcm.c | 173 ++++++++- > drivers/bluetooth/btbcm.h | 19 +- > drivers/bluetooth/btbcm_uart.c | 679 +++++++++++++++++++++++++++++++++ > drivers/bluetooth/btbcm_uart.h | 90 +++++ > drivers/bluetooth/hci_bcm.c | 838 +++++++++++++++++++++++++++++++++++++---- > 7 files changed, 1745 insertions(+), 90 deletions(-) > create mode 100644 drivers/bluetooth/btbcm_uart.c > create mode 100644 drivers/bluetooth/btbcm_uart.h > > diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig > index ed5c273..1bfe36b 100644 > --- a/drivers/bluetooth/Kconfig > +++ b/drivers/bluetooth/Kconfig > @@ -8,6 +8,12 @@ config BT_INTEL > config BT_BCM > tristate > select FW_LOADER > + help > + This feature is required if you want to use Broadcom Bluetooth > + over both USB and UART. I think this should say “over either USB or UART”. > + > + Say Y here to compile support for Broadcom Bluetooth > + kernel or say M to compile it as module (btusb). The reason why I never bothered adding a help text description to this entry is because it is a hidden entry. Selecting either the Broadcom USB or its UART version causes this module to be built. You will never see this entry in the kernel configuration user interface. That means you can not actually select Y or M or N here. It is selected for you based on other choices made by actual exposed options. So it is up to you if you want to keep this or not. If you do, then this should be a separate patch since it is fixing some existing piece. And you might also want to fix up the BT_INTEL one since that has the same “problem”. If we fix something, then we fix it for all current existences. And s/btusb/btbcm/ in case you overlooked that small copy&paste bug. > > config BT_HCIBTUSB > tristate "HCI USB driver" > @@ -22,15 +28,16 @@ config BT_HCIBTUSB > kernel or say M to compile it as module (btusb). > > config BT_HCIBTUSB_BCM > - bool "Broadcom protocol support" > + bool "Broadcom USB support” I preferred “protocol” over “USB” here when I added it for the simple reason since this is the Generic USB driver. No need to repeat the USB part of it. That is pretty obvious. > depends on BT_HCIBTUSB > select BT_BCM > default y > help > - The Broadcom protocol support enables firmware and patchram > - download support for Broadcom Bluetooth controllers. > + Broadcom Bluetooth USB driver support. > + The Broadcom USB support enables firmware and patchram > + download for Broadcom Bluetooth USB controllers. > > - Say Y here to compile support for Broadcom protocol. > + Say Y here to compile support for Broadcom USB. I am not convinced that this makes it clearer. It is an option of the USB driver. It is not a different driver. It is still the same driver. It is just enabling the support for Broadcom based devices. > > config BT_HCIBTSDIO > tristate "HCI SDIO driver" > @@ -125,15 +132,25 @@ config BT_HCIUART_INTEL > Say Y here to compile support for Intel protocol. > > config BT_HCIUART_BCM > - bool "Broadcom protocol support" > - depends on BT_HCIUART > + bool "Broadcom BT UART serial support” Same explanation as above. It is an option of the UART driver. No need to repeat that information. That is why I choose to use the word “protocol” in the first place. > select BT_HCIUART_H4 > + select BT_UART_BCM > select BT_BCM > help > - The Broadcom protocol support enables Bluetooth HCI over serial > - port interface for Broadcom Bluetooth controllers. > + HCI_UART_BCM is a protocol for initializing, managing and > + communicating with Broadcom UART Bluetooth devices. > + This protocol initializes chips and power-manages them. > + Enable this if you have serial Broadcom Bluetooth device. > + > + Say Y here to compile support for Broadcom UART protocol. > + > +config BT_UART_BCM > + tristate "Broadcom BT UART driver" > + depends on BT_HCIUART_H4 && TTY > + help > + This driver supports the HCI_UART_BT protocol. > > - Say Y here to compile support for Broadcom protocol. > + It manages Bluetooth UART device properties and GPIOs. My idea was actually not putting this into a separate kernel module. So I have to read through this whole patch set to see if that makes sense or not. My initial thought has been that this is in the drivers/bluetooth/hci_bcm.c. Just as a note, in case of a separate driver, that driver should have been in its own patch and not intermixed with this one. Mixing them together makes it really hard to review it. > > config BT_HCIBCM203X > tristate "HCI BCM203x USB driver" > diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile > index dd0d9c4..0e5fd66 100644 > --- a/drivers/bluetooth/Makefile > +++ b/drivers/bluetooth/Makefile > @@ -21,6 +21,7 @@ obj-$(CONFIG_BT_MRVL) += btmrvl.o > obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o > obj-$(CONFIG_BT_WILINK) += btwilink.o > obj-$(CONFIG_BT_BCM) += btbcm.o > +obj-$(CONFIG_BT_UART_BCM) += btbcm_uart.o > > btmrvl-y := btmrvl_main.o > btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o > diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c > index 4bba866..3e9ac30 100644 > --- a/drivers/bluetooth/btbcm.c > +++ b/drivers/bluetooth/btbcm.c > @@ -2,7 +2,8 @@ > * > * Bluetooth support for Broadcom devices > * > - * Copyright (C) 2015 Intel Corporation > + * Copyright (C) 2015 Intel Corporation > + * Copyright (C) 2015 Broadcom Corporation Just follow the double spaces that we normally do for separating the year from the company. > * > * > * This program is free software; you can redistribute it and/or modify > @@ -15,24 +16,22 @@ > * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > - * I know that eventually we have to remove the FSF address from the code, but that is clearly an individual cleanup patch that can come later. Mixing these in early on just adds clutter for the review. > */ > > #include <linux/module.h> > #include <linux/firmware.h> > +#include <linux/tty.h> > #include <asm/unaligned.h> > > #include <net/bluetooth/bluetooth.h> > #include <net/bluetooth/hci_core.h> > > +#include “hci_uart.h" This screams layer violation. btbcm.[ch] should be independent so that the USB and also the UART driver can utilise it. Also changes to btbcm.[ch] should come as separate patches. They should come first and introduce new common used functionality. > #include "btbcm.h" > > -#define VERSION "0.1" > +#define VERSION "0.2" > > -#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}}) > +#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00} }) Remove this one. That whitespace fix you are doing here is wrong. > > int btbcm_check_bdaddr(struct hci_dev *hdev) > { > @@ -43,6 +42,7 @@ int btbcm_check_bdaddr(struct hci_dev *hdev) > HCI_INIT_TIMEOUT); > if (IS_ERR(skb)) { > int err = PTR_ERR(skb); > + If you want to fix some coding style, then please do that in a separate patch. If they are valid fixes, then they are easy to apply. Intermixed with adding features it is a bad idea. > BT_ERR("%s: BCM: Reading device address failed (%d)", > hdev->name, err); > return err; > @@ -159,6 +159,8 @@ int btbcm_patchram(struct hci_dev *hdev, const char *firmware) > } > > /* 250 msec delay after Launch Ram completes */ > + BT_INFO("%s: BCM: Delaying upon the patch download completion...", > + hdev->name); Same on this one. If this adds value, please split this out and have a separate patch for it. I know this might sound a bit like extra overhead, but when having to look back at this in 2 years it helps a look to see the reasoning for it. So far we have gotten away with not printing this information and nobody complained. If this is just for debugging purposes, then keeping it as a separate patch is better. You can just drop it at the end. > msleep(250); > > done: > @@ -174,6 +176,7 @@ static int btbcm_reset(struct hci_dev *hdev) > skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); > if (IS_ERR(skb)) { > int err = PTR_ERR(skb); > + > BT_ERR("%s: BCM: Reset failed (%d)", hdev->name, err); > return err; > } > @@ -246,8 +249,10 @@ static struct sk_buff *btbcm_read_usb_product(struct hci_dev *hdev) > static const struct { > u16 subver; > const char *name; > + u32 baud_rate; /* operational baud rate */ > } bcm_uart_subver_table[] = { > - { 0x410e, "BCM43341B0" }, /* 002.001.014 */ > + { 0x410e, "BCM43341B0", 3000000}, /* 002.001.014 */ > + { 0x610c, "BCM4354_003.001.012.0306.0659", 3000000}, /* 003.001.012 */ These are not firmware names. It is just suppose to the the first part of the string. So just adding firmware filenames here is the wrong approach. And as we talked, soon, this needs to be replaced by a “manifest” file that will be loaded via request_firmware() from the firmware directory that allows to make the right selection of firmware file. We are just not there yet. So it will be easy to just add the new subver entry here as it is. Also this table is not appropriate for the the operational baud rate. I prefer we do that exactly as Fred did in his patches and then maybe later add a feature to overwrite this via ACPI or DTS entries. > { } > }; > > @@ -268,6 +273,133 @@ static const struct { > { } > }; > > +/* > + * Set the UART into the defaults > + */ > +int btbcm_init_uart(struct hci_uart *hu) > +{ > + struct ktermios ktermios; > + struct tty_struct *tty = hu->tty; As a general rule the variables that carry an assignment from some other struct come first. > + int status, speed; > + > + /* Bring UART into default setting at 115200 */ I don’t think this comment belong here before flushing the buffer. I think here you want a comment that explain that we are flushing the line discipline buffers and the TTY buffers. > + if (tty->ldisc->ops->flush_buffer) > + tty->ldisc->ops->flush_buffer(tty); > + tty_driver_flush_buffer(tty); And this should have an extra space in between here and then add the comment to put the UART back into default mode. I would actually list all default options we are requiring and not just the speed. > + ktermios = tty->termios; > + BT_DBG("init_uart def flags c_o %x c_l %x c_c %x spd %d/%d", > + ktermios.c_oflag, ktermios.c_lflag, ktermios.c_cflag, > + ktermios.c_ispeed, ktermios.c_ospeed); > + ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP > + | INLCR | IGNCR | ICRNL | IXON); > + ktermios.c_oflag &= ~OPOST; > + ktermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); > + ktermios.c_cflag &= ~(CSIZE | PARENB | CBAUD); > + ktermios.c_cflag |= CS8; > + ktermios.c_cflag |= CRTSCTS; > + ktermios.c_cflag |= B115200; > + ktermios.c_ispeed = 115200; > + ktermios.c_ospeed = 115200; > + status = tty_set_termios(tty, &ktermios); In general the variable name err is mostly used for this and not status. > + if (status) { > + BT_DBG("init_uart set_termios failure %d", status); > + return status; > + } > + > + speed = tty_get_baud_rate(tty); > + BT_DBG("init_uart set_termios completed, spd %d", speed); This warrants an extra empty line for easier readability. > + ktermios = tty->termios; > + BT_DBG("init_uart new flags c_o %x c_l %x c_c %x spd %d/%d", > + ktermios.c_oflag, ktermios.c_lflag, ktermios.c_cflag, > + ktermios.c_ispeed, ktermios.c_ospeed); However a lot of this pure debug code during development. Do you want to keep it around? > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(btbcm_init_uart); I wonder if this code actually belongs into btbcm module. It sounds like pretty generic code that could be just done in hci_ldisc.c and could be done beforehand. Mainly since all vendors have some sort of default baud rate and operational baud rate. We want to limit messing with the TTY code to a central location. I do not want to duplicate this code for Intel, Realtek or any other hardware manufacturer. I think that Fred was doing that in a central location in hci_ldisc.c to have the HCI UART core handling prepare this. > + > +/* > + * Set the baud rate on the UART and the device > + */ > +int btbcm_set_baud_rate(struct hci_uart *hu, int baud_rate) > +{ As I said above. This is a layer violation. struct hci_uart is internal to the hci_uart.ko driver. You can not expose this from the btbcm.ko driver. > + struct ktermios ktermios; > + struct tty_struct *tty = hu->tty; > + int status, speed, cflag; > + struct sk_buff *skb; > + unsigned char enable = 1; > + unsigned char baud_rate_vsc_pars[] = {0, 0, 0, 0x10, 0x0e, 0}; Might want to use u8 here instead. And 0x01 instead of 1 for these assignments. > + > + /* If the baud rate is higher than 3000000, change the clock */ > + if (baud_rate > 3000000) { > + skb = __hci_cmd_sync(hu->hdev, 0xfc45, 1, &enable, > + HCI_INIT_TIMEOUT); > + if (IS_ERR(skb)) { > + status = PTR_ERR(skb); > + return status; > + } > + > + kfree_skb(skb); > + BT_DBG("set_baud_rate write UART 48 MHz VSC succeeded"); > + } I wonder if can always assume that the clock is set correctly and not better switch the clock back in case the value is lower. Also is this now really enable or just a clock mode selection? > + > + /* Now let the device know about the rate change */ > + baud_rate_vsc_pars[2] = (unsigned char)(baud_rate & 0xff); > + baud_rate_vsc_pars[3] = (unsigned char)((baud_rate >> 8) & 0xff); > + baud_rate_vsc_pars[4] = (unsigned char)((baud_rate >> 16) & 0xff); > + baud_rate_vsc_pars[5] = (unsigned char)((baud_rate >> 24) & 0xff); We have function like put_unaligned_le32 for this. Or just define the vendor command struct for this. > + skb = __hci_cmd_sync(hu->hdev, 0xfc18, sizeof(baud_rate_vsc_pars), > + baud_rate_vsc_pars, HCI_INIT_TIMEOUT); > + if (IS_ERR(skb)) { > + status = PTR_ERR(skb); > + BT_ERR("set_baud_rate VSC failed (%d)", status); > + return status; > + } The } is at the wrong indentation. > + > + kfree_skb(skb); > + BT_DBG("set_baud_rate VSC succeeded"); > + > + /* Set UART into this rate as well */ > + ktermios = tty->termios; > + BT_DBG("set_baud_rate start flags c_o %x c_l %x c_c %x spd %d/%d", > + ktermios.c_oflag, ktermios.c_lflag, ktermios.c_cflag, > + ktermios.c_ispeed, ktermios.c_ospeed); > + switch (baud_rate) { > + case 115200: > + cflag |= B115200; break; > + case 921600: > + cflag |= B921600; break; > + case 3000000: > + cflag |= B3000000; break; > + case 3500000: > + cflag |= B3500000; break; > + case 4000000: > + cflag |= B4000000; break; > + default: > + BT_DBG("set_baud_rate unknown rate %d", baud_rate); > + return -EINVAL; > + } > + > + ktermios.c_cflag &= ~CBAUD; > + ktermios.c_cflag |= cflag; > + ktermios.c_ispeed = baud_rate; > + ktermios.c_ospeed = baud_rate; > + status = tty_set_termios(tty, &ktermios); > + if (status) { > + BT_DBG("set_baud_rate set_termios failure %d", status); > + return status; > + } > + > + speed = tty_get_baud_rate(tty); > + BT_DBG("set_baud_rate set_termios completed, spd %d", speed); > + ktermios = tty->termios; > + BT_DBG("set_baud_rate flags c_o %x c_l %x c_c %x spd %d/%d", > + ktermios.c_oflag, ktermios.c_lflag, ktermios.c_cflag, > + ktermios.c_ispeed, ktermios.c_ospeed); Duplicating the actual TTY baud rate change code here makes it clear that we want that centralised in hci_ldisc. > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(btbcm_set_baud_rate); > + > int btbcm_setup_patchram(struct hci_dev *hdev) > { > char fw_name[64]; > @@ -275,7 +407,8 @@ int btbcm_setup_patchram(struct hci_dev *hdev) > const char *hw_name = NULL; > struct sk_buff *skb; > struct hci_rp_read_local_version *ver; > - int i, err; > + int i, err, is_uart = false; > + struct hci_uart *hu = hci_get_drvdata(hdev); > > /* Reset */ > err = btbcm_reset(hdev); > @@ -297,14 +430,18 @@ int btbcm_setup_patchram(struct hci_dev *hdev) > if (IS_ERR(skb)) > return PTR_ERR(skb); > > - BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]); > + BT_INFO("%s: BCM: chip id %u, rev 0x%x subver 0x%x", > + hdev->name, skb->data[1], rev, subver); > kfree_skb(skb); > > switch ((rev & 0xf000) >> 12) { > case 0: > + case 1: > for (i = 0; bcm_uart_subver_table[i].name; i++) { > if (subver == bcm_uart_subver_table[i].subver) { > hw_name = bcm_uart_subver_table[i].name; > + BT_INFO("UART firmware found: %s", hw_name); > + is_uart = true; > break; > } > } > @@ -312,7 +449,7 @@ int btbcm_setup_patchram(struct hci_dev *hdev) > snprintf(fw_name, sizeof(fw_name), "brcm/%s.hcd", > hw_name ? : "BCM"); > break; > - case 1: > + > case 2: > /* Read USB Product Info */ > skb = btbcm_read_usb_product(hdev); > @@ -345,11 +482,25 @@ int btbcm_setup_patchram(struct hci_dev *hdev) > if (err == -ENOENT) > return 0; > > + /* Once the patch is downloaded, the device is back at default rate */ > + if (is_uart) { > + err = btbcm_init_uart(hu); > + if (err) > + return 0; > + } > + > /* Reset */ > err = btbcm_reset(hdev); > if (err) > return err; > > + if (is_uart) { > + err = btbcm_set_baud_rate(hu, > + bcm_uart_subver_table[i].baud_rate); > + if (err) > + return 0; > + } > + The is_uart decision is something that the driver should make. So while right now it is easy to just reference the setup function from the common code, I think the reality is that each driver (USB and UART) has to provide its own ->setup function for Broadcom devices and then stick the needed pieces together. So lets try to figure out what needs to be done when and what can be generic in hci_ldisc.c and then we move pieces into the right location. > /* Read Local Version Info */ > skb = btbcm_read_local_version(hdev); > if (IS_ERR(skb)) > diff --git a/drivers/bluetooth/btbcm.h b/drivers/bluetooth/btbcm.h > index eb6ab5f..f7d30c6 100644 > --- a/drivers/bluetooth/btbcm.h > +++ b/drivers/bluetooth/btbcm.h > @@ -2,7 +2,8 @@ > * > * Bluetooth support for Broadcom devices > * > - * Copyright (C) 2015 Intel Corporation > + * Copyright (C) 2015 Intel Corporation > + * Copyright (C) 2015 Broadcom Corporation > * > * > * This program is free software; you can redistribute it and/or modify > @@ -15,10 +16,6 @@ > * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > - * > */ > > #if IS_ENABLED(CONFIG_BT_BCM) > @@ -30,6 +27,8 @@ int btbcm_patchram(struct hci_dev *hdev, const char *firmware); > int btbcm_setup_patchram(struct hci_dev *hdev); > int btbcm_setup_apple(struct hci_dev *hdev); > > +int btbcm_init_uart(struct hci_uart *hu); > +int btbcm_set_baud_rate(struct hci_uart *hu, int baud_rate); > #else > > static inline int btbcm_check_bdaddr(struct hci_dev *hdev) > @@ -57,4 +56,14 @@ static inline int btbcm_setup_apple(struct hci_dev *hdev) > return 0; > } > > +static int btbcm_init_uart(void *hu) These should be static inline. Not that we can keep them this way, but just for future reference. > +{ > + return 0; > +} > + > +static int btbcm_set_baud_rate(void *hu, int baud_rate); > +{ > + return 0; > +} > + > #endif > diff --git a/drivers/bluetooth/btbcm_uart.c b/drivers/bluetooth/btbcm_uart.c > new file mode 100644 > index 0000000..3308bdb > --- /dev/null > +++ b/drivers/bluetooth/btbcm_uart.c > @@ -0,0 +1,679 @@ > +/* > + * > + * Bluetooth BCM UART Driver > + * > + * Copyright (c) 2015 Broadcom Corporation > + * > + * 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. > + * > + */ > + > +#include <linux/module.h> > + > +#include <linux/kernel.h> > +#include <linux/init.h> > +#include <linux/types.h> > +#include <linux/fcntl.h> > +#include <linux/interrupt.h> > +#include <linux/ptrace.h> > +#include <linux/poll.h> > + > +#include <linux/slab.h> > +#include <linux/tty.h> > +#include <linux/errno.h> > +#include <linux/string.h> > +#include <linux/signal.h> > +#include <linux/ioctl.h> > +#include <linux/skbuff.h> > +#include <linux/list.h> > + > +#include <net/bluetooth/bluetooth.h> > +#include <net/bluetooth/hci_core.h> > + > +#include <linux/gpio/consumer.h> > +#include <linux/of.h> > +#include <linux/of_gpio.h> > +#include <linux/of_platform.h> > + > +#include "btbcm_uart.h" > + > +static int idleTimeout = 5; We do not name variables in camel case. This would be idle_timeout. > +module_param(idleTimeout, int, 0); > +MODULE_PARM_DESC(idleTimeout, "Bluetooth idle timeout in seconds"); > + > +/* Device context */ > +struct bcm_device { > + struct list_head list; > + > + struct platform_device *pdev; > + struct gpio_desc *bt_wake_gpio; > + struct gpio_desc *dev_wake_gpio; > + struct gpio_desc *reg_on_gpio; > + int bt_wake_irq; > + int dev_wake_active_low; > + int reg_on_active_low; > + int bt_wake_active_low; > + u32 configure_sleep; > + u32 manual_fc; > + u32 baud_rate_before_config_download; > + u32 configure_audio; > + u32 PCMClockMode; > + u32 PCMFillMethod; > + u32 PCMFillNum; > + u32 PCMFillValue; > + u32 PCMInCallBitclock; > + u32 PCMLSBFirst; > + u32 PCMRightJustify; > + u32 PCMRouting; > + u32 PCMShortFrameSync; > + u32 PCMSyncMode; > + > + char tty_name[64]; > + > + struct btbcm_uart_callbacks protocol_callbacks; > + struct work_struct wakeup_work; > +}; > + > +/* List of BCM BT UART devices */ > +static DEFINE_SPINLOCK(device_list_lock); > +static LIST_HEAD(device_list); > + > +/* > + * Calling the BCM protocol at lower execution priority > + */ > +static void bcm_bt_wakeup_task(struct work_struct *ws) > +{ > + int resume_flag; > + struct bcm_device *p_bcm_device = > + container_of(ws, struct bcm_device, wakeup_work); > + > + if (!p_bcm_device) { > + BT_DBG("bcm_bt_wakeup_task - failing, no device"); > + return; > + } > + > + /* Make sure the device is resumed */ > + resume_flag = !p_bcm_device->dev_wake_active_low; > + if (p_bcm_device->dev_wake_gpio) { > + gpiod_set_value(p_bcm_device->dev_wake_gpio, resume_flag); > + BT_DBG("bcm_bt_wakeup_task - resume %d written, delaying 15 ms", > + resume_flag); > + mdelay(15); > + } > + > + /* Let the protocol know it's time to wake up */ > + if (p_bcm_device->protocol_callbacks.p_wakeup) > + p_bcm_device->protocol_callbacks.p_wakeup( > + p_bcm_device->protocol_callbacks.context); > +} > + > +/* > + * Interrupt routine for the wake from the device > + */ > +static irqreturn_t bcm_bt_uart_isr(int irq, void *context) > +{ > + unsigned int bt_wake; > + struct bcm_device *p = (struct bcm_device *)context; > + > + bt_wake = gpiod_get_value(p->bt_wake_gpio); > + BT_DBG("bcm_bt_uart_isr with bt_wake of %d (active_low %d), req bh", > + bt_wake, p->bt_wake_active_low); > + > + /* Defer the actual processing to the platform work queue */ > + schedule_work(&p->wakeup_work); > + return IRQ_HANDLED; > +} > + > +/* > + * Device instance startup > + */ > +static int bcm_bt_uart_probe(struct platform_device *pdev) > +{ > + int ret = 0; > + struct device_node *np = pdev->dev.of_node; > + const char *tty_name; > + struct bcm_device *p_bcm_device = NULL; > + > + p_bcm_device = devm_kzalloc(&pdev->dev, sizeof(*p_bcm_device), > + GFP_KERNEL); > + if (!p_bcm_device) { > + BT_DBG("bcm_bt_uart_probe - failing due to no memory"); > + return -ENOMEM; > + } > + p_bcm_device->pdev = pdev; > + BT_DBG("bcm_bt_uart_probe %p context", p_bcm_device); > + > + /* Get dev wake GPIO */ > + p_bcm_device->dev_wake_gpio = gpiod_get(&pdev->dev, "bt-wake"); > + BT_DBG("bcm_bt_uart_probe - gpiod_get for bt-wake returned %p", > + p_bcm_device->dev_wake_gpio); > + if (IS_ERR(p_bcm_device->dev_wake_gpio)) { > + ret = PTR_ERR(p_bcm_device->dev_wake_gpio); > + if (ret != -ENOENT) { > + dev_err(&pdev->dev, > + "bcm_bt_uart_probe - dev_wake GPIO: %d\n", ret); > + } > + p_bcm_device->dev_wake_gpio = NULL; > + } else { > + int resume_flag; > + > + p_bcm_device->dev_wake_active_low = gpiod_is_active_low > + (p_bcm_device->dev_wake_gpio); > + BT_DBG("bcm_bt_uart_probe - dev_wake a-low is %d (cans %d)", > + p_bcm_device->dev_wake_active_low, > + gpiod_cansleep(p_bcm_device->dev_wake_gpio)); > + > + /* configure dev_wake as output with init resumed state */ > + resume_flag = !p_bcm_device->dev_wake_active_low; > + ret = gpiod_direction_output(p_bcm_device->dev_wake_gpio, > + resume_flag); > + if (ret < 0) { > + dev_err(&pdev->dev, > + "bcm_bt_uart_probe s dev_wake GPIO: %d\n", ret); > + gpiod_put(p_bcm_device->dev_wake_gpio); > + p_bcm_device->dev_wake_gpio = NULL; > + goto end; > + } else { > + BT_DBG("bcm_bt_uart_probe - dev_wake set to %d", > + resume_flag); > + } > + } > + > + /* Get power on/off GPIO */ > + p_bcm_device->reg_on_gpio = gpiod_get(&pdev->dev, "reg-on"); > + BT_DBG("bcm_bt_uart_probe - gpiod_get for reg-on returned %p", > + p_bcm_device->reg_on_gpio); > + if (IS_ERR(p_bcm_device->reg_on_gpio)) { > + ret = PTR_ERR(p_bcm_device->reg_on_gpio); > + if (ret != -ENOENT) { > + dev_err(&pdev->dev, > + "bcm_bt_uart_probe - reg_on GPIO: %d\n", ret); > + } > + p_bcm_device->reg_on_gpio = NULL; > + } else { > + int poweron_flag; > + > + p_bcm_device->reg_on_active_low = gpiod_is_active_low > + (p_bcm_device->reg_on_gpio); > + BT_DBG("bcm_bt_uart_probe - reg_on a-low is %d (cans %d)", > + p_bcm_device->reg_on_active_low, > + gpiod_cansleep(p_bcm_device->reg_on_gpio)); > + > + /* configure reg_on as output with init on state */ > + poweron_flag = !p_bcm_device->reg_on_active_low; > + ret = gpiod_direction_output(p_bcm_device->reg_on_gpio, > + poweron_flag); > + if (ret < 0) { > + dev_err(&pdev->dev, > + "bcm_bt_uart_probe s reg_on GPIO: %d\n", ret); > + gpiod_put(p_bcm_device->reg_on_gpio); > + p_bcm_device->reg_on_gpio = NULL; > + } else { > + BT_DBG("bcm_bt_uart_probe - reg_on initially set to %d", > + poweron_flag); > + } > + } > + > + platform_set_drvdata(pdev, p_bcm_device); > + /* Must be done before interrupt is requested */ > + INIT_WORK(&p_bcm_device->wakeup_work, bcm_bt_wakeup_task); > + > + /* Get bt host wake GPIO */ > + p_bcm_device->bt_wake_gpio = gpiod_get(&pdev->dev, "bt-host-wake"); > + BT_DBG("bcm_bt_uart_probe - gpiod_get for bt-host-wake returned %p", > + p_bcm_device->bt_wake_gpio); > + if (IS_ERR(p_bcm_device->bt_wake_gpio)) { > + ret = PTR_ERR(p_bcm_device->bt_wake_gpio); > + if (ret != -ENOENT) { > + dev_err(&pdev->dev, > + "bcm_bt_uart_probe - bt_wake GPIO: %d\n", ret); > + } > + p_bcm_device->bt_wake_gpio = NULL; > + } else { > + /* configure bt_wake as input */ > + ret = gpiod_direction_input(p_bcm_device->bt_wake_gpio); > + if (ret < 0) { > + dev_err(&pdev->dev, > + "bcm_bt_uart_probe s bt_wake GPIO: %d\n", ret); > + gpiod_put(p_bcm_device->bt_wake_gpio); > + p_bcm_device->bt_wake_gpio = NULL; > + } else { > + p_bcm_device->bt_wake_active_low = gpiod_is_active_low > + (p_bcm_device->bt_wake_gpio); > + BT_DBG("bcm_bt_uart_probe -bt_wake a-low is %d(cans%d)", > + p_bcm_device->bt_wake_active_low, > + gpiod_cansleep(p_bcm_device->bt_wake_gpio)); > + p_bcm_device->bt_wake_irq = gpiod_to_irq > + (p_bcm_device->bt_wake_gpio); > + if (p_bcm_device->bt_wake_irq < 0) { > + dev_err(&pdev->dev, > + "bcm_bt_uart_probe - HOST_WAKE IRQ: %d\n", ret); > + } else { > + unsigned long intflags = IRQF_TRIGGER_RISING; > + > + if (p_bcm_device->bt_wake_active_low) > + intflags = IRQF_TRIGGER_FALLING; > + > + ret = request_irq(p_bcm_device->bt_wake_irq, > + bcm_bt_uart_isr, > + intflags, "bt_host_wake", > + p_bcm_device); > + if (ret < 0) { > + dev_err(&pdev->dev, "bcm_bt_uart_probe - failed to conf IRQ %d: %d", > + p_bcm_device->bt_wake_irq, ret); > + } else { > + BT_DBG("bcm_bt_uart_probe - IRQ %d", > + p_bcm_device->bt_wake_irq); > + } > + } > + } > + } > + > + p_bcm_device->configure_sleep = 0; > + if (!of_property_read_u32(np, "configure-sleep", > + &p_bcm_device->configure_sleep)) { > + BT_DBG("configure-sleep read as %d", > + p_bcm_device->configure_sleep); > + } > + p_bcm_device->manual_fc = 0; > + if (!of_property_read_u32(np, "manual-fc", > + &p_bcm_device->manual_fc)) { > + BT_DBG("manual-fc read as %d", > + p_bcm_device->manual_fc); > + } > + p_bcm_device->baud_rate_before_config_download = 3000000; > + if (!of_property_read_u32( > + np, "baud-rate-before-config-download", > + &p_bcm_device->baud_rate_before_config_download)) { > + BT_DBG("baud-rate-before-config-download read as %d", > + p_bcm_device->baud_rate_before_config_download); > + } > + p_bcm_device->configure_audio = 0; > + if (!of_property_read_u32(np, "configure-audio", > + &p_bcm_device->configure_audio)) { > + BT_DBG("configure-audio read as %d", > + p_bcm_device->configure_audio); > + } > + if (p_bcm_device->configure_audio) { > + /* Defaults for audio */ > + p_bcm_device->PCMClockMode = 0; > + p_bcm_device->PCMFillMethod = 2; > + p_bcm_device->PCMFillNum = 0; > + p_bcm_device->PCMFillValue = 3; > + p_bcm_device->PCMInCallBitclock = 0; > + p_bcm_device->PCMLSBFirst = 0; > + p_bcm_device->PCMRightJustify = 0; > + p_bcm_device->PCMRouting = 0; > + p_bcm_device->PCMShortFrameSync = 0; > + p_bcm_device->PCMSyncMode = 0; > + > + if (!of_property_read_u32(np, "PCMClockMode", > + &p_bcm_device->PCMClockMode)) > + BT_DBG("PCMClockMode read as %d", > + p_bcm_device->PCMClockMode); > + if (!of_property_read_u32(np, "PCMFillMethod", > + &p_bcm_device->PCMFillMethod)) > + BT_DBG("PCMFillMethod readas %d", > + p_bcm_device->PCMFillMethod); > + if (!of_property_read_u32(np, "PCMFillNum", > + &p_bcm_device->PCMFillNum)) > + BT_DBG("PCMFillNum read as %d", > + p_bcm_device->PCMFillNum); > + if (!of_property_read_u32(np, "PCMFillValue", > + &p_bcm_device->PCMFillValue)) > + BT_DBG("PCMFillValue read as %d", > + p_bcm_device->PCMFillValue); > + if (!of_property_read_u32(np, "PCMInCallBitclock", > + &p_bcm_device->PCMInCallBitclock)) > + BT_DBG("PCMInCallBitclock read as %d", > + p_bcm_device->PCMInCallBitclock); > + if (!of_property_read_u32(np, "PCMLSBFirst", > + &p_bcm_device->PCMLSBFirst)) > + BT_DBG("PCMLSBFirst read as %d", > + p_bcm_device->PCMLSBFirst); > + if (!of_property_read_u32(np, "PCMRightJustify", > + &p_bcm_device->PCMRightJustify)) > + BT_DBG("PCMRightJustify read as %d", > + p_bcm_device->PCMRightJustify); > + if (!of_property_read_u32(np, "PCMRouting", > + &p_bcm_device->PCMRouting)) > + BT_DBG("PCMRouting read as %d", > + p_bcm_device->PCMRouting); > + if (!of_property_read_u32(np, "PCMShortFrameSync", > + &p_bcm_device->PCMShortFrameSync)) > + BT_DBG("PCMShortFrameSync read as %d", > + p_bcm_device->PCMShortFrameSync); > + if (!of_property_read_u32(np, "PCMSyncMode", > + &p_bcm_device->PCMSyncMode)) > + BT_DBG("PCMSyncMode read as %d", > + p_bcm_device->PCMSyncMode); > + } > + > + if (!of_property_read_string(np, "tty", &tty_name)) { > + strcpy(p_bcm_device->tty_name, tty_name); > + BT_DBG("tty name read as %s", p_bcm_device->tty_name); > + } > + > + BT_DBG("idleTimeout set as %d", idleTimeout); > + > + ret = 0; /* If we made it here, we're fine */ > + > + /* Place this instance on the device list */ > + spin_lock(&device_list_lock); > + list_add_tail(&p_bcm_device->list, &device_list); > + spin_unlock(&device_list_lock); > + > +end: > + if (ret) { > + if (p_bcm_device->reg_on_gpio) { > + gpiod_put(p_bcm_device->reg_on_gpio); > + p_bcm_device->reg_on_gpio = NULL; > + } > + if (p_bcm_device->bt_wake_gpio) { > + gpiod_put(p_bcm_device->bt_wake_gpio); > + p_bcm_device->bt_wake_gpio = NULL; > + } > + if (p_bcm_device->dev_wake_gpio) { > + gpiod_put(p_bcm_device->dev_wake_gpio); > + p_bcm_device->dev_wake_gpio = NULL; > + } > + } > + > + BT_DBG("bcm_bt_uart_probe with the result %d", ret); > + return ret; > +} > + > +/* > + * Device instance removal > + */ > +static int bcm_bt_uart_remove(struct platform_device *pdev) > +{ > + struct bcm_device *p_bcm_device = platform_get_drvdata(pdev); > + > + if (p_bcm_device == NULL) { > + BT_DBG("bcm_bt_uart_remove - logic error, no probe?!"); > + return 0; > + } > + > + BT_DBG("bcm_bt_uart_remove %p context", p_bcm_device); > + > + spin_lock(&device_list_lock); > + list_del(&p_bcm_device->list); > + spin_unlock(&device_list_lock); > + > + BT_DBG("bcm_bt_uart_remove - freeing interrupt %d", > + p_bcm_device->bt_wake_irq); > + free_irq(p_bcm_device->bt_wake_irq, p_bcm_device); > + > + if (p_bcm_device->reg_on_gpio) { > + BT_DBG("bcm_bt_uart_remove - releasing reg_on_gpio"); > + gpiod_put(p_bcm_device->reg_on_gpio); > + p_bcm_device->reg_on_gpio = NULL; > + } > + > + if (p_bcm_device->dev_wake_gpio) { > + BT_DBG("bcm_bt_uart_remove - releasing dev_wake_gpio"); > + gpiod_put(p_bcm_device->dev_wake_gpio); > + p_bcm_device->dev_wake_gpio = NULL; > + } > + > + if (p_bcm_device->bt_wake_gpio) { > + BT_DBG("bcm_bt_uart_remove - releasing bt_wake_gpio"); > + gpiod_put(p_bcm_device->bt_wake_gpio); > + p_bcm_device->bt_wake_gpio = NULL; > + } > + > + BT_DBG("bcm_bt_uart_remove %p done", p_bcm_device); > + return 0; > +} > + > +/* > + * Platform resume callback > + */ > +static int bcm_bt_uart_resume(struct device *pdev) > +{ > + int resume_flag; > + struct bcm_device *p_bcm_device = platform_get_drvdata( > + to_platform_device(pdev)); > + > + if (p_bcm_device == NULL) { > + BT_DBG("bcm_bt_uart_resume - logic error, no device?!"); > + return 0; > + } > + > + BT_DBG("bcm_bt_uart_resume %p", p_bcm_device); > + > + resume_flag = !p_bcm_device->dev_wake_active_low; > + if (p_bcm_device->dev_wake_gpio) { > + gpiod_set_value(p_bcm_device->dev_wake_gpio, resume_flag); > + BT_DBG("bcm_bt_uart_resume: %d written, delaying 15 ms", > + resume_flag); > + mdelay(15); > + } > + > + /* Let the protocol know the platform is resuming */ > + if (p_bcm_device->protocol_callbacks.p_resume) > + p_bcm_device->protocol_callbacks.p_resume( > + p_bcm_device->protocol_callbacks.context); > + > + return 0; > +} > + > +/* > + * Platform suspend callback > + */ > +static int bcm_bt_uart_suspend(struct device *pdev) > +{ > + int resume_flag; > + struct bcm_device *p_bcm_device = platform_get_drvdata( > + to_platform_device(pdev)); > + > + if (p_bcm_device == NULL) { > + BT_DBG("bcm_bt_uart_suspend - logic error, no device?!"); > + return 0; > + } > + > + BT_DBG("bcm_bt_uart_suspend %p", p_bcm_device); > + > + /* Let the protocol know the platform is suspending */ > + if (p_bcm_device->protocol_callbacks.p_suspend) > + p_bcm_device->protocol_callbacks.p_suspend( > + p_bcm_device->protocol_callbacks.context); > + > + /* Suspend the device */ > + if (p_bcm_device->dev_wake_gpio) { > + resume_flag = !p_bcm_device->dev_wake_active_low; > + gpiod_set_value(p_bcm_device->dev_wake_gpio, !resume_flag); > + BT_DBG("bcm_bt_uart_suspend: %d written, delaying 15 ms", > + !resume_flag); > + mdelay(15); > + } > + > + return 0; > +} > + > +/* > + * Entry point for calls from the protocol > + */ > +int btbcm_uart_control(int action, void *device_context, > + void *p_data, unsigned long *p_size) > +{ > + struct btbcm_uart_callbacks *pc; > + struct btbcm_uart_parameters *pp = p_data; /* for pars action only */ > + int ret = 0; > + int resume_flag, poweron_flag; For true boolean variable, please use bool instead of int. > + struct bcm_device *p_bcm_device = device_context; > + struct list_head *ptr; > + bool is_found = false; > + > + /* Special processing for the callback configuration */ > + if (action == BTBCM_UART_ACTION_CONFIGURE_CALLBACKS) { > + pc = p_data; > + > + BT_DBG("btbcm_uart_control - configure callbacks"); > + if ((p_data == NULL) || *p_size != sizeof(struct Extra () around x == y are not needed. Do bother with them. > + btbcm_uart_callbacks) || (pc->interface_version != > + BTBCM_UART_INTERFACE_VERSION)) { Wrong indentation. > + BT_DBG("btbcm_uart_control - callbacks mismatch!"); > + return -E2BIG; > + } > + > + BT_DBG("btbcm_uart_control - configure callbacks for %s(%p)", > + pc->name, pc->context); > + if (p_bcm_device == NULL) { > + spin_lock(&device_list_lock); > + list_for_each(ptr, &device_list) { > + p_bcm_device = list_entry(ptr, struct > + bcm_device, list); > + if (!strcmp(p_bcm_device->tty_name, pc->name)) { > + is_found = true; > + break; > + } > + } > + > + spin_unlock(&device_list_lock); > + if (!is_found) { > + BT_DBG("btbcm_uart_control - no device!"); > + return -ENOENT; > + } > + } > + > + p_bcm_device->protocol_callbacks = *pc; > + memcpy(p_data, &p_bcm_device, sizeof(p_bcm_device)); > + *p_size = sizeof(p_bcm_device); > + return ret; > + } > + > + /* All other requests must have the right context */ > + if (p_bcm_device == NULL) { > + BT_DBG("btbcm_uart_control - failing, no device"); > + return -ENOENT; > + } > + > + switch (action) { > + case BTBCM_UART_ACTION_POWER_ON: > + BT_DBG("btbcm_uart_control %p - power on", device_context); > + if (p_bcm_device->reg_on_gpio) { > + poweron_flag = !p_bcm_device->reg_on_active_low; > + gpiod_set_value(p_bcm_device->reg_on_gpio, > + poweron_flag); > + BT_DBG("btbcm_uart_control - pwron %d, delay 15 ms", > + poweron_flag); > + mdelay(15); > + } > + break; > + > + case BTBCM_UART_ACTION_POWER_OFF: > + BT_DBG("btbcm_uart_control %p - power off", device_context); > + if (p_bcm_device->reg_on_gpio) { > + poweron_flag = p_bcm_device->reg_on_active_low; > + gpiod_set_value(p_bcm_device->reg_on_gpio, > + poweron_flag); > + BT_DBG("btbcm_uart_control - pwroff %d, delay 15 ms", > + poweron_flag); > + mdelay(15); > + } > + break; > + > + case BTBCM_UART_ACTION_RESUME: > + BT_DBG("btbcm_uart_control %p - resume", device_context); > + if (p_bcm_device->dev_wake_gpio) { > + resume_flag = !p_bcm_device->dev_wake_active_low; > + gpiod_set_value(p_bcm_device->dev_wake_gpio, > + resume_flag); > + BT_DBG("btbcm_uart_control - resume %d, delay 15 ms", > + resume_flag); > + mdelay(15); > + } > + break; > + > + case BTBCM_UART_ACTION_SUSPEND: > + BT_DBG("btbcm_uart_control %p - suspend", device_context); > + if (p_bcm_device->dev_wake_gpio) { > + resume_flag = !p_bcm_device->dev_wake_active_low; > + gpiod_set_value(p_bcm_device->dev_wake_gpio, > + !resume_flag); > + BT_DBG("btbcm_uart_control - suspend %d, delay 15ms", > + !resume_flag); > + mdelay(15); > + } > + break; > + > + case BTBCM_UART_ACTION_GET_PARAMETERS: > + BT_DBG("btbcm_uart_control %p - get pars", device_context); > + if ((p_data == NULL) || > + (*p_size < sizeof(struct btbcm_uart_parameters))) { > + BT_DBG("btbcm_uart_control - failing, wrong par size"); > + return -E2BIG; > + } > + > + memset(pp, 0, sizeof(struct btbcm_uart_parameters)); > + pp->interface_version = BTBCM_UART_INTERFACE_VERSION; > + pp->configure_sleep = p_bcm_device->configure_sleep; > + pp->manual_fc = p_bcm_device->manual_fc; > + pp->dev_wake_active_low = p_bcm_device->dev_wake_active_low; > + pp->bt_wake_active_low = p_bcm_device->bt_wake_active_low; > + pp->idle_timeout_in_secs = idleTimeout; > + pp->baud_rate_before_config_download = > + p_bcm_device->baud_rate_before_config_download; > + pp->configure_audio = p_bcm_device->configure_audio; > + pp->PCMClockMode = p_bcm_device->PCMClockMode; > + pp->PCMFillMethod = p_bcm_device->PCMFillMethod; > + pp->PCMFillNum = p_bcm_device->PCMFillNum; > + pp->PCMFillValue = p_bcm_device->PCMFillValue; > + pp->PCMInCallBitclock = p_bcm_device->PCMInCallBitclock; > + pp->PCMLSBFirst = p_bcm_device->PCMLSBFirst; > + pp->PCMRightJustify = p_bcm_device->PCMRightJustify; > + pp->PCMRouting = p_bcm_device->PCMRouting; > + pp->PCMShortFrameSync = p_bcm_device->PCMShortFrameSync; > + pp->PCMSyncMode = p_bcm_device->PCMSyncMode; > + *p_size = sizeof(struct btbcm_uart_parameters); > + break; > + > + default: > + BT_DBG("btbcm_uart_control %p unknown act %d", > + device_context, action); > + ret = -EINVAL; > + break; > + } > + > + return ret; > +} > +EXPORT_SYMBOL(btbcm_uart_control); > + > +/* Platform susp and resume callbacks */ > +static SIMPLE_DEV_PM_OPS(bcm_bt_uart_pm_ops, > + bcm_bt_uart_suspend, bcm_bt_uart_resume); > + > +/* Driver match table */ > +static const struct of_device_id bcm_bt_uart_match_table[] = { No need to call it match_table. Just table as suffice is fine. > + { .compatible = "brcm,brcm-bt-uart" }, > + {} > +}; > + > +/* Driver configuration */ > +static struct platform_driver bcm_bt_uart_platform_driver = { No need to call it platform_driver. Just driver as suffix is fine. > + .probe = bcm_bt_uart_probe, > + .remove = bcm_bt_uart_remove, > + .driver = { > + .name = "brcm_bt_uart", > + .of_match_table = of_match_ptr(bcm_bt_uart_match_table), > + .owner = THIS_MODULE, > + .pm = &bcm_bt_uart_pm_ops, > + }, > +}; > + > +module_platform_driver(bcm_bt_uart_platform_driver); > + > +MODULE_AUTHOR("Ilya Faenson"); > +MODULE_DESCRIPTION("Broadcom Bluetooth UART Driver"); > +MODULE_LICENSE("Dual BSD/GPL”); Copyright header says GPLv2. So lets reflect the correct license here. > + > diff --git a/drivers/bluetooth/btbcm_uart.h b/drivers/bluetooth/btbcm_uart.h > new file mode 100644 > index 0000000..5801753 > --- /dev/null > +++ b/drivers/bluetooth/btbcm_uart.h > @@ -0,0 +1,90 @@ > +/* > + * > + * Bluetooth BCM UART Driver Header > + * > + * Copyright (c) 2015 Broadcom Corporation > + * > + * 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. > + * > + */ > +#ifndef BTBCM_UART_H > +#define BTBCM_UART_H > + > +/* Change the version if you change anything in this header */ > +#define BTBCM_UART_INTERFACE_VERSION 1 I do not see the need for this. Why would we do that? > + > +/* Callbacks from the driver into the protocol */ > +typedef void (*p_suspend_callback)(void *context); > +typedef void (*p_resume_callback)(void *context); > +typedef void (*p_wakeup_callback)(void *context); Extra empty line here. > +struct btbcm_uart_callbacks { > + int interface_version; /* interface # compiled against */ > + void *context; /* protocol instance context */ > + char name[64]; /* protocol tty device, for example, ttyS0 */ Why would we record the TTY name. It might actually change. > + > + /* Callbacks proper */ > + p_suspend_callback p_suspend; > + p_resume_callback p_resume; > + p_wakeup_callback p_wakeup; I do not get this p_ prefix naming. What is that for? > +}; > + > +/* Driver parameters retrieved from the DT or ACPI */ > +struct btbcm_uart_parameters { > + int interface_version; /* interface # compiled against */ > + > + /* Parameters proper */ What is a “proper”? > + int configure_sleep; > + int manual_fc; > + int dev_wake_active_low; > + int bt_wake_active_low; > + int idle_timeout_in_secs; > + int baud_rate_before_config_download; > + int configure_audio; > + int PCMClockMode; > + int PCMFillMethod; > + int PCMFillNum; > + int PCMFillValue; > + int PCMInCallBitclock; > + int PCMLSBFirst; > + int PCMRightJustify; > + int PCMRouting; > + int PCMShortFrameSync; > + int PCMSyncMode; > +}; > + > +/* > + * Actions on the BTBCM_UART driver > + */ > + > +/* Configure protocol callbacks */ > +#define BTBCM_UART_ACTION_CONFIGURE_CALLBACKS 0 > + > +/* Retrieve BT device parameters */ > +#define BTBCM_UART_ACTION_GET_PARAMETERS 1 > + > +/* Resume the BT device via GPIO */ > +#define BTBCM_UART_ACTION_RESUME 2 > + > +/* Suspend the BT device via GPIO */ > +#define BTBCM_UART_ACTION_SUSPEND 3 > + > +/* Power the BT device off via GPIO */ > +#define BTBCM_UART_ACTION_POWER_OFF 4 > + > +/* Power the BT device on via GPIO */ > +#define BTBCM_UART_ACTION_POWER_ON 5 > + > +/* Execute an action on the BT device */ > +extern int btbcm_uart_control(int action, void *device_context, > + void *p_data, unsigned long *p_size); Can these be 6 individual function instead of trying to fiddle this through a single one? > + > +#endif > + > diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c > index 1ec0b4a..e70f89b 100644 > --- a/drivers/bluetooth/hci_bcm.c > +++ b/drivers/bluetooth/hci_bcm.c > @@ -1,8 +1,13 @@ > /* > * > - * Bluetooth HCI UART driver for Broadcom devices > + * Bluetooth UART H4 protocol for Broadcom devices > * > - * Copyright (C) 2015 Intel Corporation > + * Copyright (c) 2015 Intel Corporation > + * Copyright (c) 2015 Broadcom Corporation > + * > + * Acknowledgements: > + * This file has been based on hci_h4.c originally developed > + * by Maxim Krasnyansky and Marcel Holtmann. > * > * > * This program is free software; you can redistribute it and/or modify > @@ -15,139 +20,842 @@ > * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > - * > */ > > +#include <linux/module.h> > + > #include <linux/kernel.h> > +#include <linux/init.h> > +#include <linux/types.h> > +#include <linux/fcntl.h> > +#include <linux/interrupt.h> > +#include <linux/ptrace.h> > +#include <linux/poll.h> > + > +#include <linux/slab.h> > +#include <linux/tty.h> > #include <linux/errno.h> > +#include <linux/string.h> > +#include <linux/signal.h> > +#include <linux/ioctl.h> > #include <linux/skbuff.h> > > #include <net/bluetooth/bluetooth.h> > #include <net/bluetooth/hci_core.h> > > -#include "btbcm.h" > +#include <linux/gpio/consumer.h> > +#include <linux/of_gpio.h> > +#include <linux/of_platform.h> > + > #include "hci_uart.h" > +#include "btbcm.h" > +#include "btbcm_uart.h" > > -struct bcm_data { > - struct sk_buff *rx_skb; > +/* Protocol context */ > +struct bcm_h4_struct { I am missing the reason for this renaming. > struct sk_buff_head txq; > + struct hci_uart *hu; > + > + bool is_suspended; /* suspend/resume flag */ > + > + /* Recv data parsing is not used in normal operation */ > + bool parse_recv; > + /* buffer includes the type */ > + unsigned char reassembly[1 + HCI_MAX_FRAME_SIZE]; > + unsigned int rsize; > + u16 rexpected; So the nice H:4 RX helper function that I build is not good enough? Really? You need to really make a good case for not using it. > + > + struct timer_list timer; /* idle timer */ > + > + struct btbcm_uart_parameters pars; /* device parameters */ > + void *device_context; /* ACPI/DT device context */ > }; > > -static int bcm_open(struct hci_uart *hu) > +/* Static function prototypes for forward references */ > +static void suspend_notification(void *context); > +static void resume_notification(void *context); > +static void wakeup_notification(void *context); > +static void bcm_ensure_wakeup(struct hci_uart *hu); I dislike forward declaration. If they can be avoid, lets avoid them and the function into the better location. > + > +/* Suspend/resume synchronization mutex */ > +static DEFINE_MUTEX(plock); > + > +/* > + * Idle timer callback > + */ > +static void bcm_idle_timeout(unsigned long arg) > { > - struct bcm_data *bcm; > + struct hci_uart *hu = (struct hci_uart *)arg; > + struct bcm_h4_struct *h4 = hu->priv; > + int status; > > - BT_DBG("hu %p", hu); > + BT_DBG("bcm_idle_timeout hu %p", hu); > + > + /* Suspend/resume operations are serialized */ > + mutex_lock(&plock); > + > + if (!h4->is_suspended) { > + /* Flow control the port if configured */ > + suspend_notification(hu); > + > + /* Suspend the device */ > + status = btbcm_uart_control(BTBCM_UART_ACTION_SUSPEND, > + h4->device_context, NULL, NULL); > + if (status) > + BT_DBG("bcm_idle_timeout failed to suspend device %d", > + status); > + } > > - bcm = kzalloc(sizeof(*bcm), GFP_KERNEL); > - if (!bcm) > + mutex_unlock(&plock); > +} > + > +/* > + * Initialize protocol > + */ > +static int bcm_h4_open(struct hci_uart *hu) > +{ > + struct btbcm_uart_callbacks callbacks; > + unsigned long callbacks_size = sizeof(callbacks); > + int status; > + struct bcm_h4_struct *h4; > + struct tty_struct *tty = hu->tty; > + > + BT_DBG("bcm_h4_open hu %p", hu); > + > + h4 = kzalloc(sizeof(*h4), GFP_KERNEL); > + if (!h4) > return -ENOMEM; > > - skb_queue_head_init(&bcm->txq); > + skb_queue_head_init(&h4->txq); > + hu->priv = h4; > + h4->hu = hu; > + h4->is_suspended = false; > + h4->parse_recv = false; > + h4->rsize = 0; > + > + /* Configure callbacks on the driver */ > + callbacks.interface_version = BTBCM_UART_INTERFACE_VERSION; > + callbacks.context = hu; > + strcpy(callbacks.name, tty->name); > + callbacks.p_suspend = suspend_notification; > + callbacks.p_resume = resume_notification; > + callbacks.p_wakeup = wakeup_notification; > + status = btbcm_uart_control(BTBCM_UART_ACTION_CONFIGURE_CALLBACKS, > + NULL, &callbacks, &callbacks_size); > + if (status) { > + BT_DBG("bcm_h4_open failed to set driver callbacks %d", status); > + return status; > + } > + if (callbacks_size != sizeof(void *)) { > + BT_DBG("bcm_h4_open got back %d bytes from callbacks?!", > + (int)callbacks_size); > + return -EMSGSIZE; > + } > + memcpy(&h4->device_context, &callbacks, sizeof(void *)); > + BT_DBG("bcm_h4_open callbacks context %p", h4->device_context); > + > + /* Retrieve device parameters */ > + callbacks_size = sizeof(h4->pars); > + status = btbcm_uart_control(BTBCM_UART_ACTION_GET_PARAMETERS, > + h4->device_context, &h4->pars, > + &callbacks_size); > + if (status) { > + BT_DBG("bcm_h4_open failed to get dev parameters %d", status); > + return status; > + } > + BT_DBG("Pars ver %d csleep %d dalow %d balow %d idle %d", > + h4->pars.interface_version, h4->pars.configure_sleep, > + h4->pars.dev_wake_active_low, h4->pars.bt_wake_active_low, > + h4->pars.idle_timeout_in_secs); > + > + /* Cycle power to make sure the device is in the known state */ > + status = btbcm_uart_control(BTBCM_UART_ACTION_POWER_OFF, > + h4->device_context, NULL, NULL); > + if (status) { > + BT_DBG("bcm_h4_open failed to power off %d", status); > + } else { > + status = btbcm_uart_control(BTBCM_UART_ACTION_POWER_ON, > + h4->device_context, NULL, NULL); > + if (status) > + BT_DBG("bcm_h4_open failed to power on %d", status); > + } > + > + /* Start the idle timer */ > + if (h4->pars.configure_sleep) { > + setup_timer(&h4->timer, bcm_idle_timeout, (unsigned long)hu); > + if (h4->pars.configure_sleep) > + mod_timer(&h4->timer, jiffies + msecs_to_jiffies( > + h4->pars.idle_timeout_in_secs * 1000)); > + } > + > + return 0; > +} > + > +/* > + * Flush protocol data > + */ > +static int bcm_h4_flush(struct hci_uart *hu) > +{ > + struct bcm_h4_struct *h4 = hu->priv; > > - hu->priv = bcm; > + BT_DBG("bcm_h4_flush hu %p", hu); > + > + skb_queue_purge(&h4->txq); > return 0; > } > > -static int bcm_close(struct hci_uart *hu) > +/* > + * Make sure we're awake > + * (called when the resumed state is required) > + */ > +static void bcm_ensure_wakeup(struct hci_uart *hu) > { > - struct bcm_data *bcm = hu->priv; > + struct bcm_h4_struct *h4 = hu->priv; > + int status; > + > + if (!h4->pars.configure_sleep) > + return; > + > + /* Suspend/resume operations are serialized */ > + mutex_lock(&plock); > + > + /* Nothing to do if resumed already */ > + if (!h4->is_suspended) { > + mutex_unlock(&plock); > > - BT_DBG("hu %p", hu); > + /* Just reset the timer */ > + status = mod_timer(&h4->timer, jiffies + msecs_to_jiffies( > + h4->pars.idle_timeout_in_secs * 1000)); > + return; > + } Using a timer is pretty dangerous. We are trying to get away from them as much as possible unless we really need them. Can we just use a delayed work struct here? > + > + /* Wakeup the device */ > + status = btbcm_uart_control(BTBCM_UART_ACTION_RESUME, > + h4->device_context, NULL, NULL); > + if (status) > + BT_DBG("bcm_ensure_wakeup failed to resume driver %d", status); > > - skb_queue_purge(&bcm->txq); > - kfree_skb(bcm->rx_skb); > - kfree(bcm); > + /* Unflow control the port if configured */ > + resume_notification(hu); > + > + mutex_unlock(&plock); > +} > + > +/* > + * Close protocol > + */ > +static int bcm_h4_close(struct hci_uart *hu) > +{ > + struct btbcm_uart_callbacks callbacks; > + unsigned long callbacks_size = sizeof(callbacks); > + struct bcm_h4_struct *h4 = hu->priv; > + int status; > > hu->priv = NULL; > + > + BT_DBG("bcm_h4_close hu %p", hu); > + > + /* If we're being closed, we must suspend */ > + if (h4->pars.configure_sleep) { > + mutex_lock(&plock); > + > + if (!h4->is_suspended) { > + /* Flow control the port */ > + suspend_notification(hu); > + > + /* Suspend the device */ > + status = btbcm_uart_control(BTBCM_UART_ACTION_SUSPEND, > + h4->device_context, NULL, > + NULL); > + if (status) { > + BT_DBG("bcm_h4_close suspend driver fail %d", > + status); > + } > + } > + > + mutex_unlock(&plock); > + > + del_timer_sync(&h4->timer); > + } > + > + /* Power off the device if possible */ > + status = btbcm_uart_control(BTBCM_UART_ACTION_POWER_OFF, > + h4->device_context, NULL, NULL); > + if (status) > + BT_DBG("bcm_h4_close failed to power off %d", status); > + > + /* de-configure callbacks on the driver */ > + callbacks.interface_version = BTBCM_UART_INTERFACE_VERSION; > + callbacks.context = hu; > + callbacks.p_suspend = NULL; > + callbacks.p_resume = NULL; > + callbacks.p_wakeup = NULL; > + status = btbcm_uart_control(BTBCM_UART_ACTION_CONFIGURE_CALLBACKS, > + h4->device_context, &callbacks, > + &callbacks_size); > + if (status) > + BT_DBG("bcm_h4_close failed to reset drv callbacks %d", status); > + skb_queue_purge(&h4->txq); > + > + hu->priv = NULL; > + kfree(h4); > + > return 0; > } > > -static int bcm_flush(struct hci_uart *hu) > +/* > + * Enqueue frame for transmittion (padding, crc, etc) > + */ > +static int bcm_h4_enqueue(struct hci_uart *hu, struct sk_buff *skb) > { > - struct bcm_data *bcm = hu->priv; > + struct bcm_h4_struct *h4 = hu->priv; > + > + BT_DBG("bcm_h4_enqueue hu %p skb %p type %d len %d (%x %x %x)", > + hu, skb, bt_cb(skb)->pkt_type, skb->len, > + skb->data[0], skb->data[1], skb->data[2]); > > - BT_DBG("hu %p", hu); > + /* Make sure we're resumed */ > + bcm_ensure_wakeup(hu); > > - skb_queue_purge(&bcm->txq); > + /* Prepend skb with frame type */ > + memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); > + skb_queue_tail(&h4->txq, skb); > > return 0; > } > > -static int bcm_setup(struct hci_uart *hu) > +/* > + * HCI event processing if our own parsing of events is required > + * NOTE: return 0 if the event is not to be passed up to BlueZ > + */ > +static bool bcm_process_hci_event(struct hci_uart *hu) > +{ > + struct bcm_h4_struct *h4 = hu->priv; > + int status; > + unsigned char evt_code = h4->reassembly[1]; > + unsigned char len = h4->reassembly[2]; > + > + BT_DBG("bcm_process_hci_event %02x event %02x len %02x %02x", > + h4->reassembly[0], evt_code, len, h4->reassembly[3]); > + > + /* switch (evt_code) { case HCI_EV_CMD_COMPLETE: break } */ > + > + status = hci_recv_stream_fragment(hu->hdev, h4->reassembly, h4->rsize); > + if (status < 0) > + BT_ERR("bcm_process_hci_event - reassembly failed %d", status); > + return true; > +} > + > +/* > + * ACL data processing if our own parsing of data is required > + * NOTE: return 0 if the data is not to be passed up to BlueZ > + */ > +static bool bcm_process_acl_data(struct hci_uart *hu) > { > - BT_DBG("hu %p", hu); > + struct bcm_h4_struct *h4 = hu->priv; > + int ret; > > - hu->hdev->set_bdaddr = btbcm_set_bdaddr; > + BT_DBG("bcm_process_acl_data %02x %02x %02x %02x %02x", > + h4->reassembly[0], h4->reassembly[1], h4->reassembly[2], > + h4->reassembly[3], h4->reassembly[4]); > > - return btbcm_setup_patchram(hu->hdev); > + ret = hci_recv_stream_fragment(hu->hdev, h4->reassembly, h4->rsize); > + if (ret < 0) > + BT_ERR("bcm_process_acl_data - Frame Reassembly Failed"); > + return true; > } > > -static const struct h4_recv_pkt bcm_recv_pkts[] = { > - { H4_RECV_ACL, .recv = hci_recv_frame }, > - { H4_RECV_SCO, .recv = hci_recv_frame }, > - { H4_RECV_EVENT, .recv = hci_recv_frame }, > -}; > +/* > + * Fragment parsing in the active filtering phase > + * (not currently actively used) > + */ > +static void parse_fragment(struct hci_uart *hu, unsigned char *data, int count) > +{ > + struct bcm_h4_struct *h4 = hu->priv; > + > + if (h4->rsize) > + BT_DBG("parse_fragment type %x expected %d", > + h4->reassembly[0], h4->rexpected); > + > + while (count) { > + if (!h4->rsize) { > + /* Start of the frame */ > + h4->reassembly[0] = *data++; > + h4->rsize++; > + count--; > + continue; > + } > + > + switch (h4->reassembly[0]) { > + case HCI_EVENT_PKT: > + if (h4->rsize == 1) { > + /* event proper */ > + h4->reassembly[h4->rsize++] = *data++; > + count--; > + continue; > + } > + if (h4->rsize == 2) { > + /* length */ > + h4->rexpected = *data; > + h4->reassembly[h4->rsize++] = *data++; > + count--; > + BT_DBG("evthdr len %d, left %d", h4->rexpected, count); > + continue; > + } > + if (count >= h4->rexpected) { > + memcpy(&h4->reassembly[h4->rsize], data, h4->rexpected); > + h4->rsize += h4->rexpected; > + data += h4->rexpected; > + count -= h4->rexpected; > + bcm_process_hci_event(hu); > + h4->rsize = 0; /* starting anew */ > + continue; > + } > + /* only piece of the event received */ > + memcpy(&h4->reassembly[h4->rsize], data, count); > + h4->rsize += count; > + data += count; > + h4->rexpected -= count; > + count = 0; > + break; > + > + case HCI_ACLDATA_PKT: > + if ((h4->rsize == 1) || (h4->rsize == 2) || (h4->rsize == 3)) { > + /* handle and first byte of length */ > + h4->reassembly[h4->rsize++] = *data++; > + count--; > + continue; > + } > + if (h4->rsize == 4) { > + /* last byte of the length */ > + h4->reassembly[h4->rsize++] = *data++; > + h4->rexpected = h4->reassembly[h4->rsize - 2] + > + (h4->reassembly[h4->rsize - 1] << 8); > + count--; > + BT_DBG("dathdr len %d, left %d", h4->rexpected, count); > + continue; > + } > + if (count >= h4->rexpected) { > + memcpy(&h4->reassembly[h4->rsize], data, h4->rexpected); > + h4->rsize += h4->rexpected; > + data += h4->rexpected; > + count -= h4->rexpected; > + bcm_process_acl_data(hu); > + h4->rsize = 0; /* starting anew */ > + continue; > + } > + /* only piece of data received */ > + memcpy(&h4->reassembly[h4->rsize], data, count); > + h4->rsize += count; > + data += count; > + h4->rexpected -= count; > + count = 0; > + break; > + > + default: /* Note that SCO may NOT come through the UART */ You can not really make this statement. This has to work even with platform where SCO might actually come through an UART. The automotive platforms historically preferred SCO over UART. Then again, I am not even reviewing this piece of code. Use the h4_recv_buf helper. I send around examples for using it even with vendor packets like what Nokia used in their platforms. > + if (count >= 3) > + BT_DBG("unexpected pkt type of %x (%02x %02x %02x)?!", > + h4->reassembly[0], data[0], data[1], data[2]); > + else if (count == 2) > + BT_DBG("unexpected pkt type of %x (%02x %02x)?!", > + h4->reassembly[0], data[0], data[1]); > + else if (count == 1) > + BT_DBG("unexpected pkt type of %x (%02x)?!", > + h4->reassembly[0], data[0]); > + else > + BT_DBG("unexpected pkt type of %x?!", > + h4->reassembly[0]); > + h4->rsize = 0; > + return; > + } > + } > +} > > -static int bcm_recv(struct hci_uart *hu, const void *data, int count) > +/* > + * Data indication from the line discipline > + */ > +static int bcm_h4_recv(struct hci_uart *hu, void *data, int count) > { > - struct bcm_data *bcm = hu->priv; > + struct bcm_h4_struct *h4 = hu->priv; > + int ret; > > - if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) > + BT_DBG("bcm_h4_recv hu %p len %d", hu, count); > + > + if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) { > + BT_DBG("h4_recv UART not registered!"); > return -EUNATCH; > + } All these debug additions are cluttering the patch review. Makes it a lot hardware for me to review. It is fine if you keep them in a series as temporary patches, but here it is just causing extra work for me. > > - bcm->rx_skb = h4_recv_buf(hu->hdev, bcm->rx_skb, data, count, > - bcm_recv_pkts, ARRAY_SIZE(bcm_recv_pkts)); > - if (IS_ERR(bcm->rx_skb)) { > - int err = PTR_ERR(bcm->rx_skb); > - BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); > - return err; > + /* Make sure we're resumed */ > + bcm_ensure_wakeup(hu); > + > + /* If we're in the active phase, parse what we get */ > + if (h4->parse_recv) { > + parse_fragment(hu, data, count); > + } else { > + ret = hci_recv_stream_fragment(hu->hdev, data, count); The hci_recv_stream_fragement function is gone from upstream. You can not use it anymore. > + if (ret < 0) { > + BT_ERR("bcm_h4_recv: frame reassembly failed"); > + return ret; > + } > } > > return count; > } > > -static int bcm_enqueue(struct hci_uart *hu, struct sk_buff *skb) > +/* > + * Line discipline is grabbing a packet from the tx queue > + */ > +static struct sk_buff *bcm_h4_dequeue(struct hci_uart *hu) > { This renaming is really not helping to make the patch look simpler. > - struct bcm_data *bcm = hu->priv; > + struct bcm_h4_struct *h4 = hu->priv; > + int is_qempty = skb_queue_empty(&h4->txq); > > - BT_DBG("hu %p skb %p", hu, skb); > + if (!is_qempty) > + BT_DBG("bcm_h4_dequeue with non-empty queue"); > + return skb_dequeue(&h4->txq); > +} > > - /* Prepend skb with frame type */ > - memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); > - skb_queue_tail(&bcm->txq, skb); > +/* > + * Callbacks from the BCMBT_UART device > + */ > > - return 0; > +/* > + * The platform is suspending. Stop UART activity > + */ > +static void suspend_notification(void *context) > +{ > + struct ktermios ktermios; > + struct hci_uart *hu = (struct hci_uart *)context; > + struct bcm_h4_struct *h4 = hu->priv; > + struct tty_struct *tty = hu->tty; > + int status; > + unsigned int set = 0; > + unsigned int clear = 0; > + > + BT_DBG("suspend_notification with is_suspended %d", h4->is_suspended); > + > + if (!h4->pars.configure_sleep) > + return; > + > + if (!h4->is_suspended) { > + if (h4->pars.manual_fc) { > + /* Disable hardware flow control */ > + ktermios = tty->termios; > + ktermios.c_cflag &= ~CRTSCTS; > + status = tty_set_termios(tty, &ktermios); > + if (status) > + BT_DBG("suspend_notification dis fc fail %d", > + status); > + else > + BT_DBG("suspend_notification hw fc disabled"); > + > + /* Clear RTS to prevent the device from sending */ > + /* (most PCs need OUT2 to enable interrupts) */ > + status = tty->driver->ops->tiocmget(tty); > + BT_DBG("suspend_notification cur tiocm 0x%x", status); > + set &= ~(TIOCM_OUT2 | TIOCM_RTS); > + clear = ~set; > + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | > + TIOCM_OUT2 | TIOCM_LOOP; > + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | > + TIOCM_OUT2 | TIOCM_LOOP; > + status = tty->driver->ops->tiocmset(tty, set, clear); > + if (status) > + BT_DBG("suspend_notification clr RTS fail %d", > + status); > + else > + BT_DBG("suspend_notification RTS cleared"); > + status = tty->driver->ops->tiocmget(tty); > + BT_DBG("suspend_notification end tiocm 0x%x", status); > + } I think that hci_ldisc.c should maybe provide common helpers for clearing RTS etc. I would work on making that generic and splitting it out so it can be used by others. Seems like the Atheros UART driver needs that as well. However it looks a lot simpler there. Anyway, it should be general and not duplicated in every sub driver. > + > + /* Once this callback returns, driver suspends BT via GPIO */ > + h4->is_suspended = true; > + } > +} > + > +/* > + * The platform is resuming. Resume UART activity. > + */ > +static void resume_notification(void *context) > +{ > + struct ktermios ktermios; > + struct hci_uart *hu = (struct hci_uart *)context; > + struct bcm_h4_struct *h4 = hu->priv; > + struct tty_struct *tty = hu->tty; > + int status; > + unsigned int set = 0; > + unsigned int clear = 0; > + > + BT_DBG("resume_notification with is_suspended %d", h4->is_suspended); > + > + if (!h4->pars.configure_sleep) > + return; > + > + /* When this callback executes, the device has woken up already */ > + if (h4->is_suspended) { > + h4->is_suspended = false; > + > + if (h4->pars.manual_fc) { > + status = tty->driver->ops->tiocmget(tty); > + BT_DBG("resume_notification cur tiocm 0x%x", status); > + set |= (TIOCM_OUT2 | TIOCM_RTS); > + clear = ~set; > + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | > + TIOCM_OUT2 | TIOCM_LOOP; > + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | > + TIOCM_OUT2 | TIOCM_LOOP; > + status = tty->driver->ops->tiocmset(tty, set, clear); > + if (status) > + BT_DBG("resume_notification set RTS fail %d", > + status); > + else > + BT_DBG("resume_notification RTS set"); > + > + /* Re-enable hardware flow control */ > + ktermios = tty->termios; > + ktermios.c_cflag |= CRTSCTS; > + status = tty_set_termios(tty, &ktermios); > + if (status) > + BT_DBG("resume_notification enable fc fail %d", > + status); > + else > + BT_DBG("resume_notification hw fc re-enabled"); > + } > + } > + > + /* If we're resumed, the idle timer must be running */ > + status = mod_timer(&h4->timer, jiffies + > + msecs_to_jiffies(h4->pars.idle_timeout_in_secs * 1000)); > } > > -static struct sk_buff *bcm_dequeue(struct hci_uart *hu) > +/* > + * The BT device is resuming. Resume UART activity if suspended > + */ > +static void wakeup_notification(void *context) > { > - struct bcm_data *bcm = hu->priv; > + struct ktermios ktermios; > + struct hci_uart *hu = (struct hci_uart *)context; > + struct bcm_h4_struct *h4 = hu->priv; > + struct tty_struct *tty = hu->tty; > + int status; > + unsigned int set = 0; > + unsigned int clear = 0; > + > + if (!h4->pars.configure_sleep) > + return; > + > + status = tty->driver->ops->tiocmget(tty); > + BT_DBG("wakeup_notification hu %p current tiocm 0x%x", hu, status); > + if (h4->is_suspended) { > + if (h4->pars.manual_fc) { > + set |= (TIOCM_OUT2 | TIOCM_RTS); > + clear = ~set; > + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | > + TIOCM_OUT2 | TIOCM_LOOP; > + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | > + TIOCM_OUT2 | TIOCM_LOOP; > + status = tty->driver->ops->tiocmset(tty, set, clear); > + if (status) > + BT_DBG("wakeup_notification set RTS fail %d", > + status); > + else > + BT_DBG("wakeup_notification RTS set"); > + > + /* Re-enable hardware flow control */ > + ktermios = tty->termios; > + ktermios.c_cflag |= CRTSCTS; > + status = tty_set_termios(tty, &ktermios); > + if (status) > + BT_DBG("wakeup_notification fc-en failure %d", > + status); > + else > + BT_DBG("wakeup_notification hw fc re-enabled"); > + } > + > + h4->is_suspended = false; > + } > > - return skb_dequeue(&bcm->txq); > + /* If we're resumed, the idle timer must be running */ > + status = mod_timer(&h4->timer, jiffies + msecs_to_jiffies( > + h4->pars.idle_timeout_in_secs * 1000)); > } > > -static const struct hci_uart_proto bcm_proto = { > +/* > + * Device setup that follows the protocol open > + */ > +static int bcm_h4_setup(struct hci_uart *hu) > +{ > + struct bcm_h4_struct *h4 = hu->priv; > + int status; > + struct sk_buff *skb; > + unsigned char sleep_pars[] = { > + 0x01, /* sleep mode 1=UART */ > + 0x02, /* idle threshold HOST (value * 300ms) */ > + 0x02, /* idle threshold HC (value * 300ms) */ > + 0x01, /* BT_WAKE active mode - 1=active high, 0 = active low */ > + 0x00, /* HOST_WAKE active mode - 1=active high, 0 = active low */ > + 0x01, /* Allow host sleep during SCO - FALSE */ > + 0x01, /* combine sleep mode and LPM - 1 == TRUE */ > + 0x00, /* enable tristate control of UART TX line - FALSE */ > + 0x00, /* USB auto-sleep on USB SUSPEND */ > + 0x00, /* USB USB RESUME timeout (seconds) */ > + 0x00, /* Pulsed Host Wake */ > + 0x00 /* Enable Break To Host */ > + }; > + unsigned char pcm_int_pars[] = { > + 0x00, /* 0=PCM routing, 1=SCO over HCI */ > + 0x02, /* 0=128Kbps,1=256Kbps,2=512Kbps,3=1024Kbps,4=2048Kbps */ > + 0x00, /* short frame sync 0=short, 1=long */ > + 0x00, /* sync mode 0=slave, 1=master */ > + 0x00 /* clock mode 0=slave, 1=master */ > + }; > + unsigned char pcm_format_pars[] = { > + 0x00, /* LSB_First 1=TRUE, 0=FALSE */ > + 0x00, /* Fill_Value (use 0-7 for fill bits value) */ > + 0x02, /* Fill_Method (2=sign extended) */ > + 0x03, /* Fill_Num # of fill bits 0-3) */ > + 0x01 /* Right_Justify 1=TRUE, 0=FALSE */ > + }; This is violating the indentation coding style. > + unsigned char time_slot_number = 0; > + > + BT_DBG("bcm_h4_setup hu %p", hu); > + > + /* Bring the UART into known default state */ > + status = btbcm_init_uart(hu); > + if (status) { > + BT_DBG("bcm_h4_setup failed to init BT device %d", status); > + return status; > + } > + > + /* Basic sanity check */ > + skb = __hci_cmd_sync(hu->hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); > + if (IS_ERR(skb)) { > + status = PTR_ERR(skb); > + BT_ERR("bcm_h4_setup HCI Reset failed (%d)", status); > + return status; > + } > + kfree_skb(skb); > + BT_DBG("bcm_h4_setup HCI Reset succeeded"); > + > + /* Set the new baud rate */ > + status = btbcm_set_baud_rate(hu, > + h4->pars.baud_rate_before_config_download); > + if (status) { > + BT_ERR("bcm_h4_setup set_baud_rate faiilure %d", status); > + return status; > + } > + > + hu->hdev->set_bdaddr = btbcm_set_bdaddr; > + > + /* Download the firmware and reconfigure the UART afterwards */ > + status = btbcm_setup_patchram(hu->hdev); > + if (status) { > + BT_ERR("bcm_h4_setup setup_patchram faiilure %d", status); > + return status; > + } > + > + /* Configure SCO PCM parameters */ > + if (h4->pars.configure_audio) { > + pcm_int_pars[0] = h4->pars.PCMRouting; > + pcm_int_pars[1] = h4->pars.PCMInCallBitclock; > + pcm_int_pars[2] = h4->pars.PCMShortFrameSync; > + pcm_int_pars[3] = h4->pars.PCMSyncMode; > + pcm_int_pars[4] = h4->pars.PCMClockMode; I really get the feeling we want a proper struct for this HCI command. I also wonder if this should be actual some generic function exposed by btbcm.ko. It is really not limited to UART device. It is also possible to build an USB based platform that has SCO routed over PCM. > + skb = __hci_cmd_sync(hu->hdev, 0xfc1c, sizeof(pcm_int_pars), > + pcm_int_pars, HCI_INIT_TIMEOUT); > + if (IS_ERR(skb)) { > + status = PTR_ERR(skb); > + BT_ERR("bcm_h4_setup PCM INT VSC failed (%d)", status); > + return status; > + } > + kfree_skb(skb); > + BT_DBG("bcm_h4_setup PCM INT Parameters VSC succeeded"); > + > + pcm_format_pars[0] = h4->pars.PCMLSBFirst; > + pcm_format_pars[1] = h4->pars.PCMFillValue; > + pcm_format_pars[2] = h4->pars.PCMFillMethod; > + pcm_format_pars[3] = h4->pars.PCMFillNum; > + pcm_format_pars[4] = h4->pars.PCMRightJustify; > + skb = __hci_cmd_sync(hu->hdev, 0xfc1e, sizeof(pcm_format_pars), > + pcm_format_pars, HCI_INIT_TIMEOUT); > + if (IS_ERR(skb)) { > + status = PTR_ERR(skb); > + BT_ERR("bcm_h4_setup PCM Format VSC failed (%d)", > + status); > + return status; > + } > + kfree_skb(skb); > + BT_DBG("bcm_h4_setup PCM Format VSC succeeded"); > + > + skb = __hci_cmd_sync(hu->hdev, 0xfc22, sizeof(time_slot_number), > + &time_slot_number, HCI_INIT_TIMEOUT); > + if (IS_ERR(skb)) { > + status = PTR_ERR(skb); > + BT_ERR("bcm_h4_setup SCO Time Slot VSC failed (%d)", > + status); > + return status; > + } > + kfree_skb(skb); > + BT_DBG("bcm_h4_setup SCO Time Slot VSC succeeded"); > + } > + > + /* Configure device's suspend/resume operation */ > + if (h4->pars.configure_sleep) { > + /* Override the default */ > + sleep_pars[3] = (unsigned char)!h4->pars.bt_wake_active_low; > + sleep_pars[4] = (unsigned char)!h4->pars.dev_wake_active_low; > + skb = __hci_cmd_sync(hu->hdev, 0xfc27, sizeof(sleep_pars), > + sleep_pars, HCI_INIT_TIMEOUT); > + if (IS_ERR(skb)) { > + status = PTR_ERR(skb); > + BT_ERR("bcm_h4_setup Sleep VSC failed (%d)", status); > + return status; > + } > + kfree_skb(skb); > + BT_DBG("bcm_h4_setup Set Sleep Parameters VSC succeeded"); > + } > + > + return 0; > +} > + > +/* > + * Protocol callbacks > + */ > +static struct hci_uart_proto h4p = { Keep this as bcm_proto. > .id = HCI_UART_BCM, > - .name = "BCM", > - .open = bcm_open, > - .close = bcm_close, > - .flush = bcm_flush, > - .setup = bcm_setup, > - .recv = bcm_recv, > - .enqueue = bcm_enqueue, > - .dequeue = bcm_dequeue, > + .name = "UARTBCM”, Please stop renaming things. This is a UART driver and thus no need to repeat that. > + .open = bcm_h4_open, > + .close = bcm_h4_close, > + .flush = bcm_h4_flush, > + .setup = bcm_h4_setup, > + .recv = bcm_h4_recv, > + .enqueue = bcm_h4_enqueue, > + .dequeue = bcm_h4_dequeue, > }; > > +/* > + * Protocol init > + */ > int __init bcm_init(void) > { > - return hci_uart_register_proto(&bcm_proto); > + int status = hci_uart_register_proto(&h4p); > + > + if (!status) > + BT_INFO("Broadcom H4 protocol initialized"); > + else > + BT_ERR("Broadcom H4 protocol registration failed %d", status); > + > + return status; I move this error printing into generic code and so please do not modify this and revert what I did. > } > > +/* > + * Protocol shutdown > + */ > int __exit bcm_deinit(void) > { > - return hci_uart_unregister_proto(&bcm_proto); > + BT_INFO("Broadcom H4 protocol de-initialized"); > + return hci_uart_unregister_proto(&h4p); > } > + No extra empty line at the end of a file. Regards Marcel ^ permalink raw reply [flat|nested] 6+ messages in thread
* RE: [RFC 2/2] Broadcom Bluetooth UART device driver 2015-05-11 19:03 ` Marcel Holtmann @ 2015-05-13 21:50 ` Ilya Faenson 0 siblings, 0 replies; 6+ messages in thread From: Ilya Faenson @ 2015-05-13 21:50 UTC (permalink / raw) To: Marcel Holtmann; +Cc: linux-bluetooth@vger.kernel.org SGkgTWFyY2VsLA0KDQpJIGFtIGFib3V0IHRvIHByb3ZpZGUgdGhlIG5leHQgcmV2IG9mIHRoZXNl IHBhdGNoZXMuIEkgYmVsaWV2ZSBJJ3ZlIGFjY291bnRlZCBmb3IgYWxsIHlvdXIgY29tbWVudHMg ZXhjZXB0IGZvciB0aGUgVUFSVCBhY3Rpb25zIGN1cnJlbnRseSBkb25lIGluIHRoZSBCcm9hZGNv bSBzcGVjaWZpYyBjb2RlLiBTaW5jZSB5b3UgY2xlYXJseSBwcmVmZXIgSW50ZWwncyBhcHByb2Fj aCBhbmQgaGF2ZSByZWZlcnJlZCBtZSB0byB0aGUgSW50ZWwgY29kZSB0byB0aGF0IGV4dGVudCwg Y291bGQgeW91IHBsZWFzZSBhY2NlcHQgcmVsZXZhbnQgSW50ZWwncyBwYXRjaGVzIHNvIEkgY2Fu IHVzZSB0aGUgZW5oYW5jZWQgbGluZSBkaXNjaXBsaW5lIHdpdGggdGhlIGJhdWQgcmF0ZSBzdXBw b3J0IGFzIG9wcG9zZWQgdG8gY29kaW5nIHRoYXQgZnJvbSBzY3JhdGNoIGFnYWluLiBJIHdpbGwg dGhlbiBpbnRlZ3JhdGUgZXZlcnl0aGluZyBhbmQgaXNzdWUgYW5vdGhlciBzZXJpZXMgb2YgQnJv YWRjb20gQlQgVUFSVCBwYXRjaGVzLg0KDQpQbGVhc2Ugc2VlIG15IHJlc3BvbnNlcyBpbmxpbmUg bWFya2VkIGJ5IHRoZSAiSUY6IiBwcmVmaXguDQoNClRoYW5rcywNCiAtSWx5YQ0KDQotLS0tLU9y aWdpbmFsIE1lc3NhZ2UtLS0tLQ0KRnJvbTogTWFyY2VsIEhvbHRtYW5uIFttYWlsdG86bWFyY2Vs QGhvbHRtYW5uLm9yZ10gDQpTZW50OiBNb25kYXksIE1heSAxMSwgMjAxNSAzOjA0IFBNDQpUbzog SWx5YSBGYWVuc29uDQpDYzogbGludXgtYmx1ZXRvb3RoQHZnZXIua2VybmVsLm9yZw0KU3ViamVj dDogUmU6IFtSRkMgMi8yXSBCcm9hZGNvbSBCbHVldG9vdGggVUFSVCBkZXZpY2UgZHJpdmVyDQoN CkhpIElseWEsDQoNCj4gVGhpcyBjb2RlIGltcGxlbWVudHMgdGhlIEJyb2FkY29tIEJsdWV0b290 aCBkZXZpY2UgZHJpdmVyLg0KPiBJdCBtYW5hZ2VzIGRldmljZSBjb25maWd1cmF0aW9uLCBmaXJt d2FyZSBkb3dubG9hZCBhbmQNCj4gcG93ZXIgbWFuYWdlbWVudC4NCj4gDQo+IFNpZ25lZC1vZmYt Ynk6IElseWEgRmFlbnNvbiA8aWZhZW5zb25AYnJvYWRjb20uY29tPg0KPiAtLS0NCj4gZHJpdmVy cy9ibHVldG9vdGgvS2NvbmZpZyAgICAgIHwgIDM1ICstDQo+IGRyaXZlcnMvYmx1ZXRvb3RoL01h a2VmaWxlICAgICB8ICAgMSArDQo+IGRyaXZlcnMvYmx1ZXRvb3RoL2J0YmNtLmMgICAgICB8IDE3 MyArKysrKysrKy0NCj4gZHJpdmVycy9ibHVldG9vdGgvYnRiY20uaCAgICAgIHwgIDE5ICstDQo+ IGRyaXZlcnMvYmx1ZXRvb3RoL2J0YmNtX3VhcnQuYyB8IDY3OSArKysrKysrKysrKysrKysrKysr KysrKysrKysrKysrKysNCj4gZHJpdmVycy9ibHVldG9vdGgvYnRiY21fdWFydC5oIHwgIDkwICsr KysrDQo+IGRyaXZlcnMvYmx1ZXRvb3RoL2hjaV9iY20uYyAgICB8IDgzOCArKysrKysrKysrKysr KysrKysrKysrKysrKysrKysrKysrKysrLS0tLQ0KPiA3IGZpbGVzIGNoYW5nZWQsIDE3NDUgaW5z ZXJ0aW9ucygrKSwgOTAgZGVsZXRpb25zKC0pDQo+IGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJz L2JsdWV0b290aC9idGJjbV91YXJ0LmMNCj4gY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvYmx1 ZXRvb3RoL2J0YmNtX3VhcnQuaA0KPiANCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvYmx1ZXRvb3Ro L0tjb25maWcgYi9kcml2ZXJzL2JsdWV0b290aC9LY29uZmlnDQo+IGluZGV4IGVkNWMyNzMuLjFi ZmUzNmIgMTAwNjQ0DQo+IC0tLSBhL2RyaXZlcnMvYmx1ZXRvb3RoL0tjb25maWcNCj4gKysrIGIv ZHJpdmVycy9ibHVldG9vdGgvS2NvbmZpZw0KPiBAQCAtOCw2ICs4LDEyIEBAIGNvbmZpZyBCVF9J TlRFTA0KPiBjb25maWcgQlRfQkNNDQo+IAl0cmlzdGF0ZQ0KPiAJc2VsZWN0IEZXX0xPQURFUg0K PiArCWhlbHANCj4gKwkgIFRoaXMgZmVhdHVyZSBpcyByZXF1aXJlZCBpZiB5b3Ugd2FudCB0byB1 c2UgQnJvYWRjb20gQmx1ZXRvb3RoDQo+ICsJICBvdmVyIGJvdGggVVNCIGFuZCBVQVJULg0KDQpJ IHRoaW5rIHRoaXMgc2hvdWxkIHNheSDigJxvdmVyIGVpdGhlciBVU0Igb3IgVUFSVOKAnS4NCg0K SUY6IENoYW5nZWQuDQoNCj4gKw0KPiArCSAgU2F5IFkgaGVyZSB0byBjb21waWxlIHN1cHBvcnQg Zm9yIEJyb2FkY29tIEJsdWV0b290aA0KPiArCSAga2VybmVsIG9yIHNheSBNIHRvIGNvbXBpbGUg aXQgYXMgbW9kdWxlIChidHVzYikuDQoNClRoZSByZWFzb24gd2h5IEkgbmV2ZXIgYm90aGVyZWQg YWRkaW5nIGEgaGVscCB0ZXh0IGRlc2NyaXB0aW9uIHRvIHRoaXMgZW50cnkgaXMgYmVjYXVzZSBp dCBpcyBhIGhpZGRlbiBlbnRyeS4gU2VsZWN0aW5nIGVpdGhlciB0aGUgQnJvYWRjb20gVVNCIG9y IGl0cyBVQVJUIHZlcnNpb24gY2F1c2VzIHRoaXMgbW9kdWxlIHRvIGJlIGJ1aWx0LiBZb3Ugd2ls bCBuZXZlciBzZWUgdGhpcyBlbnRyeSBpbiB0aGUga2VybmVsIGNvbmZpZ3VyYXRpb24gdXNlciBp bnRlcmZhY2UuDQoNClRoYXQgbWVhbnMgeW91IGNhbiBub3QgYWN0dWFsbHkgc2VsZWN0IFkgb3Ig TSBvciBOIGhlcmUuIEl0IGlzIHNlbGVjdGVkIGZvciB5b3UgYmFzZWQgb24gb3RoZXIgY2hvaWNl cyBtYWRlIGJ5IGFjdHVhbCBleHBvc2VkIG9wdGlvbnMuIFNvIGl0IGlzIHVwIHRvIHlvdSBpZiB5 b3Ugd2FudCB0byBrZWVwIHRoaXMgb3Igbm90LiBJZiB5b3UgZG8sIHRoZW4gdGhpcyBzaG91bGQg YmUgYSBzZXBhcmF0ZSBwYXRjaCBzaW5jZSBpdCBpcyBmaXhpbmcgc29tZSBleGlzdGluZyBwaWVj ZS4gQW5kIHlvdSBtaWdodCBhbHNvIHdhbnQgdG8gZml4IHVwIHRoZSBCVF9JTlRFTCBvbmUgc2lu Y2UgdGhhdCBoYXMgdGhlIHNhbWUg4oCccHJvYmxlbeKAnS4gSWYgd2UgZml4IHNvbWV0aGluZywg dGhlbiB3ZSBmaXggaXQgZm9yIGFsbCBjdXJyZW50IGV4aXN0ZW5jZXMuDQoNCkFuZCBzL2J0dXNi L2J0YmNtLyBpbiBjYXNlIHlvdSBvdmVybG9va2VkIHRoYXQgc21hbGwgY29weSZwYXN0ZSBidWcu DQoNCklGOiBSZW1vdmVkLiBJIGFkZGVkIHRoYXQgaGVscCBiZWNhdXNlIHRoZSBjaGVja3BhdGNo IHNjcmlwdCB3YXMgY29tcGxhaW5pbmcgYWJvdXQgdGhlIGxhY2sgb2YgaXQuDQoNCj4gDQo+IGNv bmZpZyBCVF9IQ0lCVFVTQg0KPiAJdHJpc3RhdGUgIkhDSSBVU0IgZHJpdmVyIg0KPiBAQCAtMjIs MTUgKzI4LDE2IEBAIGNvbmZpZyBCVF9IQ0lCVFVTQg0KPiAJICBrZXJuZWwgb3Igc2F5IE0gdG8g Y29tcGlsZSBpdCBhcyBtb2R1bGUgKGJ0dXNiKS4NCj4gDQo+IGNvbmZpZyBCVF9IQ0lCVFVTQl9C Q00NCj4gLQlib29sICJCcm9hZGNvbSBwcm90b2NvbCBzdXBwb3J0Ig0KPiArCWJvb2wgIkJyb2Fk Y29tIFVTQiBzdXBwb3J04oCdDQoNCkkgcHJlZmVycmVkIOKAnHByb3RvY29s4oCdIG92ZXIg4oCc VVNC4oCdIGhlcmUgd2hlbiBJIGFkZGVkIGl0IGZvciB0aGUgc2ltcGxlIHJlYXNvbiBzaW5jZSB0 aGlzIGlzIHRoZSBHZW5lcmljIFVTQiBkcml2ZXIuIE5vIG5lZWQgdG8gcmVwZWF0IHRoZSBVU0Ig cGFydCBvZiBpdC4gVGhhdCBpcyBwcmV0dHkgb2J2aW91cy4NCg0KSUY6IFJlc3RvcmVkIHRoZSBv cmlnaW5hbCB3b3JkaW5nLg0KDQo+IAlkZXBlbmRzIG9uIEJUX0hDSUJUVVNCDQo+IAlzZWxlY3Qg QlRfQkNNDQo+IAlkZWZhdWx0IHkNCj4gCWhlbHANCj4gLQkgIFRoZSBCcm9hZGNvbSBwcm90b2Nv bCBzdXBwb3J0IGVuYWJsZXMgZmlybXdhcmUgYW5kIHBhdGNocmFtDQo+IC0JICBkb3dubG9hZCBz dXBwb3J0IGZvciBCcm9hZGNvbSBCbHVldG9vdGggY29udHJvbGxlcnMuDQo+ICsJICBCcm9hZGNv bSBCbHVldG9vdGggVVNCIGRyaXZlciBzdXBwb3J0Lg0KPiArCSAgVGhlIEJyb2FkY29tIFVTQiBz dXBwb3J0IGVuYWJsZXMgZmlybXdhcmUgYW5kIHBhdGNocmFtDQo+ICsJICBkb3dubG9hZCBmb3Ig QnJvYWRjb20gQmx1ZXRvb3RoIFVTQiBjb250cm9sbGVycy4NCj4gDQo+IC0JICBTYXkgWSBoZXJl IHRvIGNvbXBpbGUgc3VwcG9ydCBmb3IgQnJvYWRjb20gcHJvdG9jb2wuDQo+ICsJICBTYXkgWSBo ZXJlIHRvIGNvbXBpbGUgc3VwcG9ydCBmb3IgQnJvYWRjb20gVVNCLg0KDQpJIGFtIG5vdCBjb252 aW5jZWQgdGhhdCB0aGlzIG1ha2VzIGl0IGNsZWFyZXIuIEl0IGlzIGFuIG9wdGlvbiBvZiB0aGUg VVNCIGRyaXZlci4gSXQgaXMgbm90IGEgZGlmZmVyZW50IGRyaXZlci4gSXQgaXMgc3RpbGwgdGhl IHNhbWUgZHJpdmVyLiBJdCBpcyBqdXN0IGVuYWJsaW5nIHRoZSBzdXBwb3J0IGZvciBCcm9hZGNv bSBiYXNlZCBkZXZpY2VzLg0KDQpJRjogUmVzdG9yZWQgdGhlIG9yaWdpbmFsIHdvcmRpbmcuDQoN Cj4gDQo+IGNvbmZpZyBCVF9IQ0lCVFNESU8NCj4gCXRyaXN0YXRlICJIQ0kgU0RJTyBkcml2ZXIi DQo+IEBAIC0xMjUsMTUgKzEzMiwyNSBAQCBjb25maWcgQlRfSENJVUFSVF9JTlRFTA0KPiAJICBT YXkgWSBoZXJlIHRvIGNvbXBpbGUgc3VwcG9ydCBmb3IgSW50ZWwgcHJvdG9jb2wuDQo+IA0KPiBj b25maWcgQlRfSENJVUFSVF9CQ00NCj4gLQlib29sICJCcm9hZGNvbSBwcm90b2NvbCBzdXBwb3J0 Ig0KPiAtCWRlcGVuZHMgb24gQlRfSENJVUFSVA0KPiArCWJvb2wgIkJyb2FkY29tIEJUIFVBUlQg c2VyaWFsIHN1cHBvcnTigJ0NCg0KU2FtZSBleHBsYW5hdGlvbiBhcyBhYm92ZS4gSXQgaXMgYW4g b3B0aW9uIG9mIHRoZSBVQVJUIGRyaXZlci4gTm8gbmVlZCB0byByZXBlYXQgdGhhdCBpbmZvcm1h dGlvbi4gVGhhdCBpcyB3aHkgSSBjaG9vc2UgdG8gdXNlIHRoZSB3b3JkIOKAnHByb3RvY29s4oCd IGluIHRoZSBmaXJzdCBwbGFjZS4NCg0KSUY6IFJlc3RvcmVkIHRoZSBvcmlnaW5hbCB3b3JkaW5n Lg0KDQo+IAlzZWxlY3QgQlRfSENJVUFSVF9INA0KPiArCXNlbGVjdCBCVF9VQVJUX0JDTQ0KPiAJ c2VsZWN0IEJUX0JDTQ0KPiAJaGVscA0KPiAtCSAgVGhlIEJyb2FkY29tIHByb3RvY29sIHN1cHBv cnQgZW5hYmxlcyBCbHVldG9vdGggSENJIG92ZXIgc2VyaWFsDQo+IC0JICBwb3J0IGludGVyZmFj ZSBmb3IgQnJvYWRjb20gQmx1ZXRvb3RoIGNvbnRyb2xsZXJzLg0KPiArCSAgSENJX1VBUlRfQkNN IGlzIGEgcHJvdG9jb2wgZm9yIGluaXRpYWxpemluZywgbWFuYWdpbmcgYW5kDQo+ICsJICBjb21t dW5pY2F0aW5nIHdpdGggQnJvYWRjb20gVUFSVCBCbHVldG9vdGggZGV2aWNlcy4NCj4gKwkgIFRo aXMgcHJvdG9jb2wgaW5pdGlhbGl6ZXMgY2hpcHMgYW5kIHBvd2VyLW1hbmFnZXMgdGhlbS4NCj4g KwkgIEVuYWJsZSB0aGlzIGlmIHlvdSBoYXZlIHNlcmlhbCBCcm9hZGNvbSBCbHVldG9vdGggZGV2 aWNlLg0KPiArDQo+ICsJICBTYXkgWSBoZXJlIHRvIGNvbXBpbGUgc3VwcG9ydCBmb3IgQnJvYWRj b20gVUFSVCBwcm90b2NvbC4NCj4gKw0KPiArY29uZmlnIEJUX1VBUlRfQkNNDQo+ICsJdHJpc3Rh dGUgIkJyb2FkY29tIEJUIFVBUlQgZHJpdmVyIg0KPiArCWRlcGVuZHMgb24gQlRfSENJVUFSVF9I NCAmJiBUVFkNCj4gKwloZWxwDQo+ICsJICBUaGlzIGRyaXZlciBzdXBwb3J0cyB0aGUgSENJX1VB UlRfQlQgcHJvdG9jb2wuDQo+IA0KPiAtCSAgU2F5IFkgaGVyZSB0byBjb21waWxlIHN1cHBvcnQg Zm9yIEJyb2FkY29tIHByb3RvY29sLg0KPiArCSAgSXQgbWFuYWdlcyBCbHVldG9vdGggVUFSVCBk ZXZpY2UgcHJvcGVydGllcyBhbmQgR1BJT3MuDQoNCk15IGlkZWEgd2FzIGFjdHVhbGx5IG5vdCBw dXR0aW5nIHRoaXMgaW50byBhIHNlcGFyYXRlIGtlcm5lbCBtb2R1bGUuIFNvIEkgaGF2ZSB0byBy ZWFkIHRocm91Z2ggdGhpcyB3aG9sZSBwYXRjaCBzZXQgdG8gc2VlIGlmIHRoYXQgbWFrZXMgc2Vu c2Ugb3Igbm90LiBNeSBpbml0aWFsIHRob3VnaHQgaGFzIGJlZW4gdGhhdCB0aGlzIGlzIGluIHRo ZSBkcml2ZXJzL2JsdWV0b290aC9oY2lfYmNtLmMuDQoNCkp1c3QgYXMgYSBub3RlLCBpbiBjYXNl IG9mIGEgc2VwYXJhdGUgZHJpdmVyLCB0aGF0IGRyaXZlciBzaG91bGQgaGF2ZSBiZWVuIGluIGl0 cyBvd24gcGF0Y2ggYW5kIG5vdCBpbnRlcm1peGVkIHdpdGggdGhpcyBvbmUuIE1peGluZyB0aGVt IHRvZ2V0aGVyIG1ha2VzIGl0IHJlYWxseSBoYXJkIHRvIHJldmlldyBpdC4NCg0KSUY6IFRoaXMg ZHJpdmVyIGlzIGluc3RhbnRpYXRlZCBieSB0aGUgRGV2aWNlIFRyZWUgb3IgaXQgY2FuJ3QgZWFz aWx5IHNoYXJlIGEgbW9kdWxlIHdpdGggdGhlIEJsdWVaIHByb3RvY29sLiBXaWxsIHN1Ym1pdCBp dCBub3cgYXMgYSBzZXBhcmF0ZSBwYXRjaC4NCg0KPiANCj4gY29uZmlnIEJUX0hDSUJDTTIwM1gN Cj4gCXRyaXN0YXRlICJIQ0kgQkNNMjAzeCBVU0IgZHJpdmVyIg0KPiBkaWZmIC0tZ2l0IGEvZHJp dmVycy9ibHVldG9vdGgvTWFrZWZpbGUgYi9kcml2ZXJzL2JsdWV0b290aC9NYWtlZmlsZQ0KPiBp bmRleCBkZDBkOWM0Li4wZTVmZDY2IDEwMDY0NA0KPiAtLS0gYS9kcml2ZXJzL2JsdWV0b290aC9N YWtlZmlsZQ0KPiArKysgYi9kcml2ZXJzL2JsdWV0b290aC9NYWtlZmlsZQ0KPiBAQCAtMjEsNiAr MjEsNyBAQCBvYmotJChDT05GSUdfQlRfTVJWTCkJCSs9IGJ0bXJ2bC5vDQo+IG9iai0kKENPTkZJ R19CVF9NUlZMX1NESU8pCSs9IGJ0bXJ2bF9zZGlvLm8NCj4gb2JqLSQoQ09ORklHX0JUX1dJTElO SykJCSs9IGJ0d2lsaW5rLm8NCj4gb2JqLSQoQ09ORklHX0JUX0JDTSkJCSs9IGJ0YmNtLm8NCj4g K29iai0kKENPTkZJR19CVF9VQVJUX0JDTSkJKz0gYnRiY21fdWFydC5vDQo+IA0KPiBidG1ydmwt eQkJCTo9IGJ0bXJ2bF9tYWluLm8NCj4gYnRtcnZsLSQoQ09ORklHX0RFQlVHX0ZTKQkrPSBidG1y dmxfZGVidWdmcy5vDQo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2JsdWV0b290aC9idGJjbS5jIGIv ZHJpdmVycy9ibHVldG9vdGgvYnRiY20uYw0KPiBpbmRleCA0YmJhODY2Li4zZTlhYzMwIDEwMDY0 NA0KPiAtLS0gYS9kcml2ZXJzL2JsdWV0b290aC9idGJjbS5jDQo+ICsrKyBiL2RyaXZlcnMvYmx1 ZXRvb3RoL2J0YmNtLmMNCj4gQEAgLTIsNyArMiw4IEBADQo+ICAqDQo+ICAqICBCbHVldG9vdGgg c3VwcG9ydCBmb3IgQnJvYWRjb20gZGV2aWNlcw0KPiAgKg0KPiAtICogIENvcHlyaWdodCAoQykg MjAxNSAgSW50ZWwgQ29ycG9yYXRpb24NCj4gKyAqICBDb3B5cmlnaHQgKEMpIDIwMTUgSW50ZWwg Q29ycG9yYXRpb24NCj4gKyAqICBDb3B5cmlnaHQgKEMpIDIwMTUgQnJvYWRjb20gQ29ycG9yYXRp b24NCg0KSnVzdCBmb2xsb3cgdGhlIGRvdWJsZSBzcGFjZXMgdGhhdCB3ZSBub3JtYWxseSBkbyBm b3Igc2VwYXJhdGluZyB0aGUgeWVhciBmcm9tIHRoZSBjb21wYW55Lg0KDQpJRjogT2theS4NCg0K PiAgKg0KPiAgKg0KPiAgKiAgVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4g cmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkNCj4gQEAgLTE1LDI0ICsxNiwyMiBAQA0KPiAg KiAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAg U2VlIHRoZQ0KPiAgKiAgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWls cy4NCj4gICoNCj4gLSAqICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBH TlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZQ0KPiAtICogIGFsb25nIHdpdGggdGhpcyBwcm9ncmFt OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlDQo+IC0gKiAgRm91bmRhdGlvbiwg SW5jLiwgNTkgVGVtcGxlIFBsYWNlLCBTdWl0ZSAzMzAsIEJvc3RvbiwgTUEgIDAyMTExLTEzMDcg IFVTQQ0KPiAtICoNCg0KSSBrbm93IHRoYXQgZXZlbnR1YWxseSB3ZSBoYXZlIHRvIHJlbW92ZSB0 aGUgRlNGIGFkZHJlc3MgZnJvbSB0aGUgY29kZSwgYnV0IHRoYXQgaXMgY2xlYXJseSBhbiBpbmRp dmlkdWFsIGNsZWFudXAgcGF0Y2ggdGhhdCBjYW4gY29tZSBsYXRlci4gTWl4aW5nIHRoZXNlIGlu IGVhcmx5IG9uIGp1c3QgYWRkcyBjbHV0dGVyIGZvciB0aGUgcmV2aWV3Lg0KDQpJRjogT2theSwg cmVzdG9yZWQuDQoNCj4gICovDQo+IA0KPiAjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+DQo+ICNp bmNsdWRlIDxsaW51eC9maXJtd2FyZS5oPg0KPiArI2luY2x1ZGUgPGxpbnV4L3R0eS5oPg0KPiAj aW5jbHVkZSA8YXNtL3VuYWxpZ25lZC5oPg0KPiANCj4gI2luY2x1ZGUgPG5ldC9ibHVldG9vdGgv Ymx1ZXRvb3RoLmg+DQo+ICNpbmNsdWRlIDxuZXQvYmx1ZXRvb3RoL2hjaV9jb3JlLmg+DQo+IA0K PiArI2luY2x1ZGUg4oCcaGNpX3VhcnQuaCINCg0KVGhpcyBzY3JlYW1zIGxheWVyIHZpb2xhdGlv bi4NCg0KYnRiY20uW2NoXSBzaG91bGQgYmUgaW5kZXBlbmRlbnQgc28gdGhhdCB0aGUgVVNCIGFu ZCBhbHNvIHRoZSBVQVJUIGRyaXZlciBjYW4gdXRpbGlzZSBpdC4NCg0KSUY6IFlvdSBoYXZlIG5v dCBjb21wbGFpbmVkIHdoZW4gSW50ZWwgaW5jbHVkZWQgdGhlIHNhbWUgaGVhZGVyIGludG8gdGhl IHNhbWUgZmlsZS4gQ291bGQgeW91IHBsZWFzZSBhcHByb3ZlIHRoZSByZWxldmFudCBJbnRlbCBw YXRjaGVzIHNvIHdlIGNhbiB1c2UgdGhlIGxpbmUgZGlzY2lwbGluZSBhbmQgb3RoZXIgcmVsZXZh bnQgY2hhbmdlcyB3aXRob3V0IHJlLWNyZWF0aW5nIHRoZSBzYW1lIHRoaW5ncyBmcm9tIHNjcmF0 Y2ggYW5kIGRvaW5nIHRoZSBzdWJzZXF1ZW50IG1lcmdlcz8NCg0KQWxzbyBjaGFuZ2VzIHRvIGJ0 YmNtLltjaF0gc2hvdWxkIGNvbWUgYXMgc2VwYXJhdGUgcGF0Y2hlcy4gVGhleSBzaG91bGQgY29t ZSBmaXJzdCBhbmQgaW50cm9kdWNlIG5ldyBjb21tb24gdXNlZCBmdW5jdGlvbmFsaXR5Lg0KDQpJ RjogU3RydWN0dXJlZCBhcyBhIHNlcGFyYXRlIHBhdGNoLg0KDQo+ICNpbmNsdWRlICJidGJjbS5o Ig0KPiANCj4gLSNkZWZpbmUgVkVSU0lPTiAiMC4xIg0KPiArI2RlZmluZSBWRVJTSU9OICIwLjIi DQo+IA0KPiAtI2RlZmluZSBCREFERFJfQkNNMjA3MDJBMCAoJihiZGFkZHJfdCkge3sweDAwLCAw eGEwLCAweDAyLCAweDcwLCAweDIwLCAweDAwfX0pDQo+ICsjZGVmaW5lIEJEQUREUl9CQ00yMDcw MkEwICgmKGJkYWRkcl90KSB7ezB4MDAsIDB4YTAsIDB4MDIsIDB4NzAsIDB4MjAsIDB4MDB9IH0p DQoNClJlbW92ZSB0aGlzIG9uZS4gVGhhdCB3aGl0ZXNwYWNlIGZpeCB5b3UgYXJlIGRvaW5nIGhl cmUgaXMgd3JvbmcuDQoNCklGOiBSZW1vdmVkLg0KDQo+IA0KPiBpbnQgYnRiY21fY2hlY2tfYmRh ZGRyKHN0cnVjdCBoY2lfZGV2ICpoZGV2KQ0KPiB7DQo+IEBAIC00Myw2ICs0Miw3IEBAIGludCBi dGJjbV9jaGVja19iZGFkZHIoc3RydWN0IGhjaV9kZXYgKmhkZXYpDQo+IAkJCSAgICAgSENJX0lO SVRfVElNRU9VVCk7DQo+IAlpZiAoSVNfRVJSKHNrYikpIHsNCj4gCQlpbnQgZXJyID0gUFRSX0VS Uihza2IpOw0KPiArDQoNCklmIHlvdSB3YW50IHRvIGZpeCBzb21lIGNvZGluZyBzdHlsZSwgdGhl biBwbGVhc2UgZG8gdGhhdCBpbiBhIHNlcGFyYXRlIHBhdGNoLiBJZiB0aGV5IGFyZSB2YWxpZCBm aXhlcywgdGhlbiB0aGV5IGFyZSBlYXN5IHRvIGFwcGx5LiBJbnRlcm1peGVkIHdpdGggYWRkaW5n IGZlYXR1cmVzIGl0IGlzIGEgYmFkIGlkZWEuDQoNCklGOiBBbGwgdGhlc2Ugd2VyZSBjYXVzZWQg YnkgdGhlIGNoZWNrcGF0Y2ggc2NyaXB0IGZpeGVzLiBUaGUgZmlyc3QgUkZDIGNvbW1lbnQgYXNr ZWQgbWUgdG8gZml4IHRoZW0uIEkndmUgbm93IHJlbW92ZWQgdGhhdCBjYXVzaW5nIHRoZSBjaGVj a3BhdGNoIGlzc3VlcyBhZ2Fpbi4NCg0KPiAJCUJUX0VSUigiJXM6IEJDTTogUmVhZGluZyBkZXZp Y2UgYWRkcmVzcyBmYWlsZWQgKCVkKSIsDQo+IAkJICAgICAgIGhkZXYtPm5hbWUsIGVycik7DQo+ IAkJcmV0dXJuIGVycjsNCj4gQEAgLTE1OSw2ICsxNTksOCBAQCBpbnQgYnRiY21fcGF0Y2hyYW0o c3RydWN0IGhjaV9kZXYgKmhkZXYsIGNvbnN0IGNoYXIgKmZpcm13YXJlKQ0KPiAJfQ0KPiANCj4g CS8qIDI1MCBtc2VjIGRlbGF5IGFmdGVyIExhdW5jaCBSYW0gY29tcGxldGVzICovDQo+ICsJQlRf SU5GTygiJXM6IEJDTTogRGVsYXlpbmcgdXBvbiB0aGUgcGF0Y2ggZG93bmxvYWQgY29tcGxldGlv bi4uLiIsDQo+ICsJCWhkZXYtPm5hbWUpOw0KDQpTYW1lIG9uIHRoaXMgb25lLiBJZiB0aGlzIGFk ZHMgdmFsdWUsIHBsZWFzZSBzcGxpdCB0aGlzIG91dCBhbmQgaGF2ZSBhIHNlcGFyYXRlIHBhdGNo IGZvciBpdC4gSSBrbm93IHRoaXMgbWlnaHQgc291bmQgYSBiaXQgbGlrZSBleHRyYSBvdmVyaGVh ZCwgYnV0IHdoZW4gaGF2aW5nIHRvIGxvb2sgYmFjayBhdCB0aGlzIGluIDIgeWVhcnMgaXQgaGVs cHMgYSBsb29rIHRvIHNlZSB0aGUgcmVhc29uaW5nIGZvciBpdC4gU28gZmFyIHdlIGhhdmUgZ290 dGVuIGF3YXkgd2l0aCBub3QgcHJpbnRpbmcgdGhpcyBpbmZvcm1hdGlvbiBhbmQgbm9ib2R5IGNv bXBsYWluZWQuIElmIHRoaXMgaXMganVzdCBmb3IgZGVidWdnaW5nIHB1cnBvc2VzLCB0aGVuIGtl ZXBpbmcgaXQgYXMgYSBzZXBhcmF0ZSBwYXRjaCBpcyBiZXR0ZXIuIFlvdSBjYW4ganVzdCBkcm9w IGl0IGF0IHRoZSBlbmQuDQoNCklGOiBFYXNpZXIgdG8gcmVtb3ZlIHRoYW4gZGlzY3Vzcy4NCg0K PiAJbXNsZWVwKDI1MCk7DQo+IA0KPiBkb25lOg0KPiBAQCAtMTc0LDYgKzE3Niw3IEBAIHN0YXRp YyBpbnQgYnRiY21fcmVzZXQoc3RydWN0IGhjaV9kZXYgKmhkZXYpDQo+IAlza2IgPSBfX2hjaV9j bWRfc3luYyhoZGV2LCBIQ0lfT1BfUkVTRVQsIDAsIE5VTEwsIEhDSV9JTklUX1RJTUVPVVQpOw0K PiAJaWYgKElTX0VSUihza2IpKSB7DQo+IAkJaW50IGVyciA9IFBUUl9FUlIoc2tiKTsNCj4gKw0K PiAJCUJUX0VSUigiJXM6IEJDTTogUmVzZXQgZmFpbGVkICglZCkiLCBoZGV2LT5uYW1lLCBlcnIp Ow0KPiAJCXJldHVybiBlcnI7DQo+IAl9DQo+IEBAIC0yNDYsOCArMjQ5LDEwIEBAIHN0YXRpYyBz dHJ1Y3Qgc2tfYnVmZiAqYnRiY21fcmVhZF91c2JfcHJvZHVjdChzdHJ1Y3QgaGNpX2RldiAqaGRl dikNCj4gc3RhdGljIGNvbnN0IHN0cnVjdCB7DQo+IAl1MTYgc3VidmVyOw0KPiAJY29uc3QgY2hh ciAqbmFtZTsNCj4gKwl1MzIgYmF1ZF9yYXRlOwkvKiBvcGVyYXRpb25hbCBiYXVkIHJhdGUgKi8N Cj4gfSBiY21fdWFydF9zdWJ2ZXJfdGFibGVbXSA9IHsNCj4gLQl7IDB4NDEwZSwgIkJDTTQzMzQx QjAiCX0sCS8qIDAwMi4wMDEuMDE0ICovDQo+ICsJeyAweDQxMGUsICJCQ000MzM0MUIwIiwgMzAw MDAwMH0sICAgICAgICAgICAgICAgICAgICAvKiAwMDIuMDAxLjAxNCAqLw0KPiArCXsgMHg2MTBj LCAiQkNNNDM1NF8wMDMuMDAxLjAxMi4wMzA2LjA2NTkiLCAzMDAwMDAwfSwgLyogMDAzLjAwMS4w MTIgKi8NCg0KVGhlc2UgYXJlIG5vdCBmaXJtd2FyZSBuYW1lcy4gSXQgaXMganVzdCBzdXBwb3Nl IHRvIHRoZSB0aGUgZmlyc3QgcGFydCBvZiB0aGUgc3RyaW5nLiBTbyBqdXN0IGFkZGluZyBmaXJt d2FyZSBmaWxlbmFtZXMgaGVyZSBpcyB0aGUgd3JvbmcgYXBwcm9hY2guDQoNCkFuZCBhcyB3ZSB0 YWxrZWQsIHNvb24sIHRoaXMgbmVlZHMgdG8gYmUgcmVwbGFjZWQgYnkgYSDigJxtYW5pZmVzdOKA nSBmaWxlIHRoYXQgd2lsbCBiZSBsb2FkZWQgdmlhIHJlcXVlc3RfZmlybXdhcmUoKSBmcm9tIHRo ZSBmaXJtd2FyZSBkaXJlY3RvcnkgdGhhdCBhbGxvd3MgdG8gbWFrZSB0aGUgcmlnaHQgc2VsZWN0 aW9uIG9mIGZpcm13YXJlIGZpbGUuIFdlIGFyZSBqdXN0IG5vdCB0aGVyZSB5ZXQuIFNvIGl0IHdp bGwgYmUgZWFzeSB0byBqdXN0IGFkZCB0aGUgbmV3IHN1YnZlciBlbnRyeSBoZXJlIGFzIGl0IGlz Lg0KDQpBbHNvIHRoaXMgdGFibGUgaXMgbm90IGFwcHJvcHJpYXRlIGZvciB0aGUgdGhlIG9wZXJh dGlvbmFsIGJhdWQgcmF0ZS4gSSBwcmVmZXIgd2UgZG8gdGhhdCBleGFjdGx5IGFzIEZyZWQgZGlk IGluIGhpcyBwYXRjaGVzIGFuZCB0aGVuIG1heWJlIGxhdGVyIGFkZCBhIGZlYXR1cmUgdG8gb3Zl cndyaXRlIHRoaXMgdmlhIEFDUEkgb3IgRFRTIGVudHJpZXMuDQoNCklGOiBQbGVhc2UgYXBwcm92 ZSBGcmVkJ3MgcGF0Y2hlcyB0aGVuLg0KDQo+IAl7IH0NCj4gfTsNCj4gDQo+IEBAIC0yNjgsNiAr MjczLDEzMyBAQCBzdGF0aWMgY29uc3Qgc3RydWN0IHsNCj4gCXsgfQ0KPiB9Ow0KPiANCj4gKy8q DQo+ICsgKiBTZXQgdGhlIFVBUlQgaW50byB0aGUgZGVmYXVsdHMNCj4gKyAqLw0KPiAraW50IGJ0 YmNtX2luaXRfdWFydChzdHJ1Y3QgaGNpX3VhcnQgKmh1KQ0KPiArew0KPiArCXN0cnVjdCBrdGVy bWlvcyBrdGVybWlvczsNCj4gKwlzdHJ1Y3QgdHR5X3N0cnVjdCAqdHR5ID0gaHUtPnR0eTsNCg0K QXMgYSBnZW5lcmFsIHJ1bGUgdGhlIHZhcmlhYmxlcyB0aGF0IGNhcnJ5IGFuIGFzc2lnbm1lbnQg ZnJvbSBzb21lIG90aGVyIHN0cnVjdCBjb21lIGZpcnN0Lg0KDQpJRjogQ2hhbmdlZC4NCg0KPiAr CWludCBzdGF0dXMsIHNwZWVkOw0KPiArDQo+ICsJLyogQnJpbmcgVUFSVCBpbnRvIGRlZmF1bHQg c2V0dGluZyBhdCAxMTUyMDAgKi8NCg0KSSBkb27igJl0IHRoaW5rIHRoaXMgY29tbWVudCBiZWxv bmcgaGVyZSBiZWZvcmUgZmx1c2hpbmcgdGhlIGJ1ZmZlci4gSSB0aGluayBoZXJlIHlvdSB3YW50 IGEgY29tbWVudCB0aGF0IGV4cGxhaW4gdGhhdCB3ZSBhcmUgZmx1c2hpbmcgdGhlIGxpbmUgZGlz Y2lwbGluZSBidWZmZXJzIGFuZCB0aGUgVFRZIGJ1ZmZlcnMuDQoNCklGOiBDaGFuZ2VkLg0KDQo+ ICsJaWYgKHR0eS0+bGRpc2MtPm9wcy0+Zmx1c2hfYnVmZmVyKQ0KPiArCQl0dHktPmxkaXNjLT5v cHMtPmZsdXNoX2J1ZmZlcih0dHkpOw0KPiArCXR0eV9kcml2ZXJfZmx1c2hfYnVmZmVyKHR0eSk7 DQoNCkFuZCB0aGlzIHNob3VsZCBoYXZlIGFuIGV4dHJhIHNwYWNlIGluIGJldHdlZW4gaGVyZSBh bmQgdGhlbiBhZGQgdGhlIGNvbW1lbnQgdG8gcHV0IHRoZSBVQVJUIGJhY2sgaW50byBkZWZhdWx0 IG1vZGUuIEkgd291bGQgYWN0dWFsbHkgbGlzdCBhbGwgZGVmYXVsdCBvcHRpb25zIHdlIGFyZSBy ZXF1aXJpbmcgYW5kIG5vdCBqdXN0IHRoZSBzcGVlZC4NCg0KSUY6IERvbmUuDQoNCj4gKwlrdGVy bWlvcyA9IHR0eS0+dGVybWlvczsNCj4gKwlCVF9EQkcoImluaXRfdWFydCBkZWYgZmxhZ3MgY19v ICV4IGNfbCAleCBjX2MgJXggc3BkICVkLyVkIiwNCj4gKwkgICAgICAga3Rlcm1pb3MuY19vZmxh Zywga3Rlcm1pb3MuY19sZmxhZywga3Rlcm1pb3MuY19jZmxhZywNCj4gKwkgICAgICAga3Rlcm1p b3MuY19pc3BlZWQsIGt0ZXJtaW9zLmNfb3NwZWVkKTsNCj4gKwkgICAgICAga3Rlcm1pb3MuY19p ZmxhZyAmPSB+KElHTkJSSyB8IEJSS0lOVCB8IFBBUk1SSyB8IElTVFJJUA0KPiArCQl8IElOTENS IHwgSUdOQ1IgfCBJQ1JOTCB8IElYT04pOw0KPiArCWt0ZXJtaW9zLmNfb2ZsYWcgJj0gfk9QT1NU Ow0KPiArCWt0ZXJtaW9zLmNfbGZsYWcgJj0gfihFQ0hPIHwgRUNIT05MIHwgSUNBTk9OIHwgSVNJ RyB8IElFWFRFTik7DQo+ICsJa3Rlcm1pb3MuY19jZmxhZyAmPSB+KENTSVpFIHwgUEFSRU5CIHwg Q0JBVUQpOw0KPiArCWt0ZXJtaW9zLmNfY2ZsYWcgfD0gQ1M4Ow0KPiArCWt0ZXJtaW9zLmNfY2Zs YWcgfD0gQ1JUU0NUUzsNCj4gKwlrdGVybWlvcy5jX2NmbGFnIHw9IEIxMTUyMDA7DQo+ICsJa3Rl cm1pb3MuY19pc3BlZWQgPSAxMTUyMDA7DQo+ICsJa3Rlcm1pb3MuY19vc3BlZWQgPSAxMTUyMDA7 DQo+ICsJc3RhdHVzID0gdHR5X3NldF90ZXJtaW9zKHR0eSwgJmt0ZXJtaW9zKTsNCg0KSW4gZ2Vu ZXJhbCB0aGUgdmFyaWFibGUgbmFtZSBlcnIgaXMgbW9zdGx5IHVzZWQgZm9yIHRoaXMgYW5kIG5v dCBzdGF0dXMuDQoNCklGOiBDaGFuZ2VkLg0KDQo+ICsJaWYgKHN0YXR1cykgew0KPiArCQlCVF9E QkcoImluaXRfdWFydCBzZXRfdGVybWlvcyBmYWlsdXJlICVkIiwgc3RhdHVzKTsNCj4gKwkJcmV0 dXJuIHN0YXR1czsNCj4gKwl9DQo+ICsNCj4gKwlzcGVlZCA9IHR0eV9nZXRfYmF1ZF9yYXRlKHR0 eSk7DQo+ICsJQlRfREJHKCJpbml0X3VhcnQgc2V0X3Rlcm1pb3MgY29tcGxldGVkLCBzcGQgJWQi LCBzcGVlZCk7DQoNClRoaXMgd2FycmFudHMgYW4gZXh0cmEgZW1wdHkgbGluZSBmb3IgZWFzaWVy IHJlYWRhYmlsaXR5Lg0KDQpJRjogQWRkZWQuDQoNCj4gKwlrdGVybWlvcyA9IHR0eS0+dGVybWlv czsNCj4gKwlCVF9EQkcoImluaXRfdWFydCBuZXcgZmxhZ3MgY19vICV4IGNfbCAleCBjX2MgJXgg c3BkICVkLyVkIiwNCj4gKwkgICAgICAga3Rlcm1pb3MuY19vZmxhZywga3Rlcm1pb3MuY19sZmxh Zywga3Rlcm1pb3MuY19jZmxhZywNCj4gKwkgICAgICAga3Rlcm1pb3MuY19pc3BlZWQsIGt0ZXJt aW9zLmNfb3NwZWVkKTsNCg0KSG93ZXZlciBhIGxvdCBvZiB0aGlzIHB1cmUgZGVidWcgY29kZSBk dXJpbmcgZGV2ZWxvcG1lbnQuIERvIHlvdSB3YW50IHRvIGtlZXAgaXQgYXJvdW5kPw0KDQpJRjog UmVtb3ZlZCBtb3N0IG9mIGl0Lg0KDQo+ICsNCj4gKwlyZXR1cm4gMDsNCj4gK30NCj4gK0VYUE9S VF9TWU1CT0xfR1BMKGJ0YmNtX2luaXRfdWFydCk7DQoNCkkgd29uZGVyIGlmIHRoaXMgY29kZSBh Y3R1YWxseSBiZWxvbmdzIGludG8gYnRiY20gbW9kdWxlLiBJdCBzb3VuZHMgbGlrZSBwcmV0dHkg Z2VuZXJpYyBjb2RlIHRoYXQgY291bGQgYmUganVzdCBkb25lIGluIGhjaV9sZGlzYy5jIGFuZCBj b3VsZCBiZSBkb25lIGJlZm9yZWhhbmQuIE1haW5seSBzaW5jZSBhbGwgdmVuZG9ycyBoYXZlIHNv bWUgc29ydCBvZiBkZWZhdWx0IGJhdWQgcmF0ZSBhbmQgb3BlcmF0aW9uYWwgYmF1ZCByYXRlLiBX ZSB3YW50IHRvIGxpbWl0IG1lc3Npbmcgd2l0aCB0aGUgVFRZIGNvZGUgdG8gYSBjZW50cmFsIGxv Y2F0aW9uLiBJIGRvIG5vdCB3YW50IHRvIGR1cGxpY2F0ZSB0aGlzIGNvZGUgZm9yIEludGVsLCBS ZWFsdGVrIG9yIGFueSBvdGhlciBoYXJkd2FyZSBtYW51ZmFjdHVyZXIuDQoNCkkgdGhpbmsgdGhh dCBGcmVkIHdhcyBkb2luZyB0aGF0IGluIGEgY2VudHJhbCBsb2NhdGlvbiBpbiBoY2lfbGRpc2Mu YyB0byBoYXZlIHRoZSBIQ0kgVUFSVCBjb3JlIGhhbmRsaW5nIHByZXBhcmUgdGhpcy4NCg0KSUY6 IEFnYWluLCBwbGVhc2UgYXBwcm92ZSBGcmVkJ3MgcGF0Y2hlcyBhbmQgSSB3aWxsIGdsYWRseSB1 c2UgdGhlbS4NCg0KPiArDQo+ICsvKg0KPiArICogU2V0IHRoZSBiYXVkIHJhdGUgb24gdGhlIFVB UlQgYW5kIHRoZSBkZXZpY2UNCj4gKyAqLw0KPiAraW50IGJ0YmNtX3NldF9iYXVkX3JhdGUoc3Ry dWN0IGhjaV91YXJ0ICpodSwgaW50IGJhdWRfcmF0ZSkNCj4gK3sNCg0KQXMgSSBzYWlkIGFib3Zl LiBUaGlzIGlzIGEgbGF5ZXIgdmlvbGF0aW9uLiBzdHJ1Y3QgaGNpX3VhcnQgaXMgaW50ZXJuYWwg dG8gdGhlIGhjaV91YXJ0LmtvIGRyaXZlci4gWW91IGNhbiBub3QgZXhwb3NlIHRoaXMgZnJvbSB0 aGUgYnRiY20ua28gZHJpdmVyLg0KDQpJRjogQWdhaW4sIHBsZWFzZSBhcHByb3ZlIEZyZWQncyBw YXRjaGVzIGFuZCBJIHdpbGwgZ2xhZGx5IHVzZSB0aGVtLg0KDQo+ICsJc3RydWN0IGt0ZXJtaW9z IGt0ZXJtaW9zOw0KPiArCXN0cnVjdCB0dHlfc3RydWN0ICp0dHkgPSBodS0+dHR5Ow0KPiArCWlu dCBzdGF0dXMsIHNwZWVkLCBjZmxhZzsNCj4gKwlzdHJ1Y3Qgc2tfYnVmZiAqc2tiOw0KPiArCXVu c2lnbmVkIGNoYXIgZW5hYmxlID0gMTsNCj4gKwl1bnNpZ25lZCBjaGFyIGJhdWRfcmF0ZV92c2Nf cGFyc1tdID0gezAsIDAsIDAsIDB4MTAsIDB4MGUsIDB9Ow0KDQpNaWdodCB3YW50IHRvIHVzZSB1 OCBoZXJlIGluc3RlYWQuIEFuZCAweDAxIGluc3RlYWQgb2YgMSBmb3IgdGhlc2UgYXNzaWdubWVu dHMuDQoNCklGOiBDaGFuZ2VkLg0KDQo+ICsNCj4gKwkvKiBJZiB0aGUgYmF1ZCByYXRlIGlzIGhp Z2hlciB0aGFuIDMwMDAwMDAsIGNoYW5nZSB0aGUgY2xvY2sgKi8NCj4gKwlpZiAoYmF1ZF9yYXRl ID4gMzAwMDAwMCkgew0KPiArCQlza2IgPSBfX2hjaV9jbWRfc3luYyhodS0+aGRldiwgMHhmYzQ1 LCAxLCAmZW5hYmxlLA0KPiArCQkJCSAgICAgSENJX0lOSVRfVElNRU9VVCk7DQo+ICsJCWlmIChJ U19FUlIoc2tiKSkgew0KPiArCQkJc3RhdHVzID0gUFRSX0VSUihza2IpOw0KPiArCQkJcmV0dXJu IHN0YXR1czsNCj4gKwkJfQ0KPiArDQo+ICsJCWtmcmVlX3NrYihza2IpOw0KPiArCQlCVF9EQkco InNldF9iYXVkX3JhdGUgd3JpdGUgVUFSVCA0OCBNSHogVlNDIHN1Y2NlZWRlZCIpOw0KPiArCX0N Cg0KSSB3b25kZXIgaWYgY2FuIGFsd2F5cyBhc3N1bWUgdGhhdCB0aGUgY2xvY2sgaXMgc2V0IGNv cnJlY3RseSBhbmQgbm90IGJldHRlciBzd2l0Y2ggdGhlIGNsb2NrIGJhY2sgaW4gY2FzZSB0aGUg dmFsdWUgaXMgbG93ZXIuDQoNCkFsc28gaXMgdGhpcyBub3cgcmVhbGx5IGVuYWJsZSBvciBqdXN0 IGEgY2xvY2sgbW9kZSBzZWxlY3Rpb24/DQoNCklGOiBUaGlzIGlzIGNsb2NrIG1vZGUgc2VsZWN0 aW9uIGZvciBoaWdoZXIgYmF1ZCByYXRlcy4gVGhlIGRlZmF1bHQgY2xvY2sgaXMgZ29vZCBmb3Ig bG93ZXIgcmF0ZXMuDQoNCj4gKw0KPiArCS8qIE5vdyBsZXQgdGhlIGRldmljZSBrbm93IGFib3V0 IHRoZSByYXRlIGNoYW5nZSAqLw0KPiArCWJhdWRfcmF0ZV92c2NfcGFyc1syXSA9ICh1bnNpZ25l ZCBjaGFyKShiYXVkX3JhdGUgJiAweGZmKTsNCj4gKwliYXVkX3JhdGVfdnNjX3BhcnNbM10gPSAo dW5zaWduZWQgY2hhcikoKGJhdWRfcmF0ZSA+PiA4KSAmIDB4ZmYpOw0KPiArCWJhdWRfcmF0ZV92 c2NfcGFyc1s0XSA9ICh1bnNpZ25lZCBjaGFyKSgoYmF1ZF9yYXRlID4+IDE2KSAmIDB4ZmYpOw0K PiArCWJhdWRfcmF0ZV92c2NfcGFyc1s1XSA9ICh1bnNpZ25lZCBjaGFyKSgoYmF1ZF9yYXRlID4+ IDI0KSAmIDB4ZmYpOw0KDQpXZSBoYXZlIGZ1bmN0aW9uIGxpa2UgcHV0X3VuYWxpZ25lZF9sZTMy IGZvciB0aGlzLiBPciBqdXN0IGRlZmluZSB0aGUgdmVuZG9yIGNvbW1hbmQgc3RydWN0IGZvciB0 aGlzLg0KDQpJRjogQ2hhbmdlZC4NCg0KPiArCXNrYiA9IF9faGNpX2NtZF9zeW5jKGh1LT5oZGV2 LCAweGZjMTgsIHNpemVvZihiYXVkX3JhdGVfdnNjX3BhcnMpLA0KPiArCQkJICAgICBiYXVkX3Jh dGVfdnNjX3BhcnMsIEhDSV9JTklUX1RJTUVPVVQpOw0KPiArCWlmIChJU19FUlIoc2tiKSkgew0K PiArCQlzdGF0dXMgPSBQVFJfRVJSKHNrYik7DQo+ICsJCUJUX0VSUigic2V0X2JhdWRfcmF0ZSBW U0MgZmFpbGVkICglZCkiLCBzdGF0dXMpOw0KPiArCQlyZXR1cm4gc3RhdHVzOw0KPiArCQl9DQoN ClRoZSB9IGlzIGF0IHRoZSB3cm9uZyBpbmRlbnRhdGlvbi4NCg0KSUY6IEZpeGVkLg0KDQo+ICsN Cj4gKwlrZnJlZV9za2Ioc2tiKTsNCj4gKwlCVF9EQkcoInNldF9iYXVkX3JhdGUgVlNDIHN1Y2Nl ZWRlZCIpOw0KPiArDQo+ICsJLyogU2V0IFVBUlQgaW50byB0aGlzIHJhdGUgYXMgd2VsbCAqLw0K PiArCWt0ZXJtaW9zID0gdHR5LT50ZXJtaW9zOw0KPiArCUJUX0RCRygic2V0X2JhdWRfcmF0ZSBz dGFydCBmbGFncyBjX28gJXggY19sICV4IGNfYyAleCBzcGQgJWQvJWQiLA0KPiArCSAgICAgICBr dGVybWlvcy5jX29mbGFnLCBrdGVybWlvcy5jX2xmbGFnLCBrdGVybWlvcy5jX2NmbGFnLA0KPiAr CSAgICAgICBrdGVybWlvcy5jX2lzcGVlZCwga3Rlcm1pb3MuY19vc3BlZWQpOw0KPiArCXN3aXRj aCAoYmF1ZF9yYXRlKSB7DQo+ICsJY2FzZSAxMTUyMDA6DQo+ICsJCWNmbGFnIHw9IEIxMTUyMDA7 IGJyZWFrOw0KPiArCWNhc2UgOTIxNjAwOg0KPiArCQljZmxhZyB8PSBCOTIxNjAwOyBicmVhazsN Cj4gKwljYXNlIDMwMDAwMDA6DQo+ICsJCWNmbGFnIHw9IEIzMDAwMDAwOyBicmVhazsNCj4gKwlj YXNlIDM1MDAwMDA6DQo+ICsJCWNmbGFnIHw9IEIzNTAwMDAwOyBicmVhazsNCj4gKwljYXNlIDQw MDAwMDA6DQo+ICsJCWNmbGFnIHw9IEI0MDAwMDAwOyBicmVhazsNCj4gKwlkZWZhdWx0Og0KPiAr CQlCVF9EQkcoInNldF9iYXVkX3JhdGUgdW5rbm93biByYXRlICVkIiwgYmF1ZF9yYXRlKTsNCj4g KwkJcmV0dXJuIC1FSU5WQUw7DQo+ICsJfQ0KPiArDQo+ICsJa3Rlcm1pb3MuY19jZmxhZyAmPSB+ Q0JBVUQ7DQo+ICsJa3Rlcm1pb3MuY19jZmxhZyB8PSBjZmxhZzsNCj4gKwlrdGVybWlvcy5jX2lz cGVlZCA9IGJhdWRfcmF0ZTsNCj4gKwlrdGVybWlvcy5jX29zcGVlZCA9IGJhdWRfcmF0ZTsNCj4g KwlzdGF0dXMgPSB0dHlfc2V0X3Rlcm1pb3ModHR5LCAma3Rlcm1pb3MpOw0KPiArCWlmIChzdGF0 dXMpIHsNCj4gKwkJQlRfREJHKCJzZXRfYmF1ZF9yYXRlIHNldF90ZXJtaW9zIGZhaWx1cmUgJWQi LCBzdGF0dXMpOw0KPiArCQlyZXR1cm4gc3RhdHVzOw0KPiArCX0NCj4gKw0KPiArCXNwZWVkID0g dHR5X2dldF9iYXVkX3JhdGUodHR5KTsNCj4gKwlCVF9EQkcoInNldF9iYXVkX3JhdGUgc2V0X3Rl cm1pb3MgY29tcGxldGVkLCBzcGQgJWQiLCBzcGVlZCk7DQo+ICsJa3Rlcm1pb3MgPSB0dHktPnRl cm1pb3M7DQo+ICsJQlRfREJHKCJzZXRfYmF1ZF9yYXRlIGZsYWdzIGNfbyAleCBjX2wgJXggY19j ICV4IHNwZCAlZC8lZCIsDQo+ICsJICAgICAgIGt0ZXJtaW9zLmNfb2ZsYWcsIGt0ZXJtaW9zLmNf bGZsYWcsIGt0ZXJtaW9zLmNfY2ZsYWcsDQo+ICsJICAgICAgIGt0ZXJtaW9zLmNfaXNwZWVkLCBr dGVybWlvcy5jX29zcGVlZCk7DQoNCkR1cGxpY2F0aW5nIHRoZSBhY3R1YWwgVFRZIGJhdWQgcmF0 ZSBjaGFuZ2UgY29kZSBoZXJlIG1ha2VzIGl0IGNsZWFyIHRoYXQgd2Ugd2FudCB0aGF0IGNlbnRy YWxpc2VkIGluIGhjaV9sZGlzYy4NCg0KSUY6IExvb2tpbmcgZm9yd2FyZCB0byB1c2luZyBGcmVk J3MgY2hhbmdlcy4NCg0KPiArDQo+ICsJcmV0dXJuIDA7DQo+ICt9DQo+ICtFWFBPUlRfU1lNQk9M X0dQTChidGJjbV9zZXRfYmF1ZF9yYXRlKTsNCj4gKw0KPiBpbnQgYnRiY21fc2V0dXBfcGF0Y2hy YW0oc3RydWN0IGhjaV9kZXYgKmhkZXYpDQo+IHsNCj4gCWNoYXIgZndfbmFtZVs2NF07DQo+IEBA IC0yNzUsNyArNDA3LDggQEAgaW50IGJ0YmNtX3NldHVwX3BhdGNocmFtKHN0cnVjdCBoY2lfZGV2 ICpoZGV2KQ0KPiAJY29uc3QgY2hhciAqaHdfbmFtZSA9IE5VTEw7DQo+IAlzdHJ1Y3Qgc2tfYnVm ZiAqc2tiOw0KPiAJc3RydWN0IGhjaV9ycF9yZWFkX2xvY2FsX3ZlcnNpb24gKnZlcjsNCj4gLQlp bnQgaSwgZXJyOw0KPiArCWludCBpLCBlcnIsIGlzX3VhcnQgPSBmYWxzZTsNCj4gKwlzdHJ1Y3Qg aGNpX3VhcnQgKmh1ID0gaGNpX2dldF9kcnZkYXRhKGhkZXYpOw0KPiANCj4gCS8qIFJlc2V0ICov DQo+IAllcnIgPSBidGJjbV9yZXNldChoZGV2KTsNCj4gQEAgLTI5NywxNCArNDMwLDE4IEBAIGlu dCBidGJjbV9zZXR1cF9wYXRjaHJhbShzdHJ1Y3QgaGNpX2RldiAqaGRldikNCj4gCWlmIChJU19F UlIoc2tiKSkNCj4gCQlyZXR1cm4gUFRSX0VSUihza2IpOw0KPiANCj4gLQlCVF9JTkZPKCIlczog QkNNOiBjaGlwIGlkICV1IiwgaGRldi0+bmFtZSwgc2tiLT5kYXRhWzFdKTsNCj4gKwlCVF9JTkZP KCIlczogQkNNOiBjaGlwIGlkICV1LCByZXYgMHgleCBzdWJ2ZXIgMHgleCIsDQo+ICsJCWhkZXYt Pm5hbWUsIHNrYi0+ZGF0YVsxXSwgcmV2LCBzdWJ2ZXIpOw0KPiAJa2ZyZWVfc2tiKHNrYik7DQo+ IA0KPiAJc3dpdGNoICgocmV2ICYgMHhmMDAwKSA+PiAxMikgew0KPiAJY2FzZSAwOg0KPiArCWNh c2UgMToNCj4gCQlmb3IgKGkgPSAwOyBiY21fdWFydF9zdWJ2ZXJfdGFibGVbaV0ubmFtZTsgaSsr KSB7DQo+IAkJCWlmIChzdWJ2ZXIgPT0gYmNtX3VhcnRfc3VidmVyX3RhYmxlW2ldLnN1YnZlcikg ew0KPiAJCQkJaHdfbmFtZSA9IGJjbV91YXJ0X3N1YnZlcl90YWJsZVtpXS5uYW1lOw0KPiArCQkJ CUJUX0lORk8oIlVBUlQgZmlybXdhcmUgZm91bmQ6ICVzIiwgaHdfbmFtZSk7DQo+ICsJCQkJaXNf dWFydCA9IHRydWU7DQo+IAkJCQlicmVhazsNCj4gCQkJfQ0KPiAJCX0NCj4gQEAgLTMxMiw3ICs0 NDksNyBAQCBpbnQgYnRiY21fc2V0dXBfcGF0Y2hyYW0oc3RydWN0IGhjaV9kZXYgKmhkZXYpDQo+ IAkJc25wcmludGYoZndfbmFtZSwgc2l6ZW9mKGZ3X25hbWUpLCAiYnJjbS8lcy5oY2QiLA0KPiAJ CQkgaHdfbmFtZSA/IDogIkJDTSIpOw0KPiAJCWJyZWFrOw0KPiAtCWNhc2UgMToNCj4gKw0KPiAJ Y2FzZSAyOg0KPiAJCS8qIFJlYWQgVVNCIFByb2R1Y3QgSW5mbyAqLw0KPiAJCXNrYiA9IGJ0YmNt X3JlYWRfdXNiX3Byb2R1Y3QoaGRldik7DQo+IEBAIC0zNDUsMTEgKzQ4MiwyNSBAQCBpbnQgYnRi Y21fc2V0dXBfcGF0Y2hyYW0oc3RydWN0IGhjaV9kZXYgKmhkZXYpDQo+IAlpZiAoZXJyID09IC1F Tk9FTlQpDQo+IAkJcmV0dXJuIDA7DQo+IA0KPiArCS8qIE9uY2UgdGhlIHBhdGNoIGlzIGRvd25s b2FkZWQsIHRoZSBkZXZpY2UgaXMgYmFjayBhdCBkZWZhdWx0IHJhdGUgKi8NCj4gKwlpZiAoaXNf dWFydCkgew0KPiArCQllcnIgPSBidGJjbV9pbml0X3VhcnQoaHUpOw0KPiArCQlpZiAoZXJyKQ0K PiArCQkJcmV0dXJuIDA7DQo+ICsJfQ0KPiArDQo+IAkvKiBSZXNldCAqLw0KPiAJZXJyID0gYnRi Y21fcmVzZXQoaGRldik7DQo+IAlpZiAoZXJyKQ0KPiAJCXJldHVybiBlcnI7DQo+IA0KPiArCWlm IChpc191YXJ0KSB7DQo+ICsJCWVyciA9IGJ0YmNtX3NldF9iYXVkX3JhdGUoaHUsDQo+ICsJCQkJ CSAgYmNtX3VhcnRfc3VidmVyX3RhYmxlW2ldLmJhdWRfcmF0ZSk7DQo+ICsJCWlmIChlcnIpDQo+ ICsJCQlyZXR1cm4gMDsNCj4gKwl9DQo+ICsNCg0KVGhlIGlzX3VhcnQgZGVjaXNpb24gaXMgc29t ZXRoaW5nIHRoYXQgdGhlIGRyaXZlciBzaG91bGQgbWFrZS4gU28gd2hpbGUgcmlnaHQgbm93IGl0 IGlzIGVhc3kgdG8ganVzdCByZWZlcmVuY2UgdGhlIHNldHVwIGZ1bmN0aW9uIGZyb20gdGhlIGNv bW1vbiBjb2RlLCBJIHRoaW5rIHRoZSByZWFsaXR5IGlzIHRoYXQgZWFjaCBkcml2ZXIgKFVTQiBh bmQgVUFSVCkgaGFzIHRvIHByb3ZpZGUgaXRzIG93biAtPnNldHVwIGZ1bmN0aW9uIGZvciBCcm9h ZGNvbSBkZXZpY2VzIGFuZCB0aGVuIHN0aWNrIHRoZSBuZWVkZWQgcGllY2VzIHRvZ2V0aGVyLiBT byBsZXRzIHRyeSB0byBmaWd1cmUgb3V0IHdoYXQgbmVlZHMgdG8gYmUgZG9uZSB3aGVuIGFuZCB3 aGF0IGNhbiBiZSBnZW5lcmljIGluIGhjaV9sZGlzYy5jIGFuZCB0aGVuIHdlIG1vdmUgcGllY2Vz IGludG8gdGhlIHJpZ2h0IGxvY2F0aW9uLg0KDQpJRjogQWdyZWUuIEludGVsIGlzIGV4dGVuc2l2 ZWx5IGNoYW5naW5nIHRoaXMgY29kZS4gTGV0J3MgYXBwcm92ZSB3aGF0IEludGVsIGhhcyBkb25l IHRvIHRoaXMgZXh0ZW50IGFuZCBnbyBmcm9tIHRoZXJlLg0KDQo+IAkvKiBSZWFkIExvY2FsIFZl cnNpb24gSW5mbyAqLw0KPiAJc2tiID0gYnRiY21fcmVhZF9sb2NhbF92ZXJzaW9uKGhkZXYpOw0K PiAJaWYgKElTX0VSUihza2IpKQ0KPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9ibHVldG9vdGgvYnRi Y20uaCBiL2RyaXZlcnMvYmx1ZXRvb3RoL2J0YmNtLmgNCj4gaW5kZXggZWI2YWI1Zi4uZjdkMzBj NiAxMDA2NDQNCj4gLS0tIGEvZHJpdmVycy9ibHVldG9vdGgvYnRiY20uaA0KPiArKysgYi9kcml2 ZXJzL2JsdWV0b290aC9idGJjbS5oDQo+IEBAIC0yLDcgKzIsOCBAQA0KPiAgKg0KPiAgKiAgQmx1 ZXRvb3RoIHN1cHBvcnQgZm9yIEJyb2FkY29tIGRldmljZXMNCj4gICoNCj4gLSAqICBDb3B5cmln aHQgKEMpIDIwMTUgIEludGVsIENvcnBvcmF0aW9uDQo+ICsgKiAgQ29weXJpZ2h0IChDKSAyMDE1 IEludGVsIENvcnBvcmF0aW9uDQo+ICsgKiAgQ29weXJpZ2h0IChDKSAyMDE1IEJyb2FkY29tIENv cnBvcmF0aW9uDQo+ICAqDQo+ICAqDQo+ICAqICBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2Fy ZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeQ0KPiBAQCAtMTUsMTAgKzE2 LDYgQEANCj4gICogIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIg UFVSUE9TRS4gIFNlZSB0aGUNCj4gICogIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBt b3JlIGRldGFpbHMuDQo+ICAqDQo+IC0gKiAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29w eSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UNCj4gLSAqICBhbG9uZyB3aXRoIHRo aXMgcHJvZ3JhbTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZQ0KPiAtICogIEZv dW5kYXRpb24sIEluYy4sIDU5IFRlbXBsZSBQbGFjZSwgU3VpdGUgMzMwLCBCb3N0b24sIE1BICAw MjExMS0xMzA3ICBVU0ENCj4gLSAqDQo+ICAqLw0KPiANCj4gI2lmIElTX0VOQUJMRUQoQ09ORklH X0JUX0JDTSkNCj4gQEAgLTMwLDYgKzI3LDggQEAgaW50IGJ0YmNtX3BhdGNocmFtKHN0cnVjdCBo Y2lfZGV2ICpoZGV2LCBjb25zdCBjaGFyICpmaXJtd2FyZSk7DQo+IGludCBidGJjbV9zZXR1cF9w YXRjaHJhbShzdHJ1Y3QgaGNpX2RldiAqaGRldik7DQo+IGludCBidGJjbV9zZXR1cF9hcHBsZShz dHJ1Y3QgaGNpX2RldiAqaGRldik7DQo+IA0KPiAraW50IGJ0YmNtX2luaXRfdWFydChzdHJ1Y3Qg aGNpX3VhcnQgKmh1KTsNCj4gK2ludCBidGJjbV9zZXRfYmF1ZF9yYXRlKHN0cnVjdCBoY2lfdWFy dCAqaHUsIGludCBiYXVkX3JhdGUpOw0KPiAjZWxzZQ0KPiANCj4gc3RhdGljIGlubGluZSBpbnQg YnRiY21fY2hlY2tfYmRhZGRyKHN0cnVjdCBoY2lfZGV2ICpoZGV2KQ0KPiBAQCAtNTcsNCArNTYs MTQgQEAgc3RhdGljIGlubGluZSBpbnQgYnRiY21fc2V0dXBfYXBwbGUoc3RydWN0IGhjaV9kZXYg KmhkZXYpDQo+IAlyZXR1cm4gMDsNCj4gfQ0KPiANCj4gK3N0YXRpYyBpbnQgYnRiY21faW5pdF91 YXJ0KHZvaWQgKmh1KQ0KDQpUaGVzZSBzaG91bGQgYmUgc3RhdGljIGlubGluZS4gTm90IHRoYXQg d2UgY2FuIGtlZXAgdGhlbSB0aGlzIHdheSwgYnV0IGp1c3QgZm9yIGZ1dHVyZSByZWZlcmVuY2Uu DQoNCklGOiBDaGFuZ2VkLg0KDQo+ICt7DQo+ICsJcmV0dXJuIDA7DQo+ICt9DQo+ICsNCj4gK3N0 YXRpYyBpbnQgYnRiY21fc2V0X2JhdWRfcmF0ZSh2b2lkICpodSwgaW50IGJhdWRfcmF0ZSk7DQo+ ICt7DQo+ICsJcmV0dXJuIDA7DQo+ICt9DQo+ICsNCj4gI2VuZGlmDQo+IGRpZmYgLS1naXQgYS9k cml2ZXJzL2JsdWV0b290aC9idGJjbV91YXJ0LmMgYi9kcml2ZXJzL2JsdWV0b290aC9idGJjbV91 YXJ0LmMNCj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQNCj4gaW5kZXggMDAwMDAwMC4uMzMwOGJkYg0K PiAtLS0gL2Rldi9udWxsDQo+ICsrKyBiL2RyaXZlcnMvYmx1ZXRvb3RoL2J0YmNtX3VhcnQuYw0K PiBAQCAtMCwwICsxLDY3OSBAQA0KPiArLyoNCj4gKyAqDQo+ICsgKiAgQmx1ZXRvb3RoIEJDTSBV QVJUIERyaXZlcg0KPiArICoNCj4gKyAqICBDb3B5cmlnaHQgKGMpIDIwMTUgQnJvYWRjb20gQ29y cG9yYXRpb24NCj4gKyAqDQo+ICsgKiAgVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlv dSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkNCj4gKyAqICBpdCB1bmRlciB0aGUg dGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieQ0K PiArICogIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9uIDIgb2Yg dGhlIExpY2Vuc2UsIG9yDQo+ICsgKiAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lv bi4NCj4gKyAqDQo+ICsgKiAgVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3Bl IHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsDQo+ICsgKiAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZ OyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YNCj4gKyAqICBNRVJDSEFOVEFC SUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlDQo+ICsg KiAgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4NCj4gKyAqDQo+ ICsgKi8NCj4gKw0KPiArI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPg0KPiArDQo+ICsjaW5jbHVk ZSA8bGludXgva2VybmVsLmg+DQo+ICsjaW5jbHVkZSA8bGludXgvaW5pdC5oPg0KPiArI2luY2x1 ZGUgPGxpbnV4L3R5cGVzLmg+DQo+ICsjaW5jbHVkZSA8bGludXgvZmNudGwuaD4NCj4gKyNpbmNs dWRlIDxsaW51eC9pbnRlcnJ1cHQuaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9wdHJhY2UuaD4NCj4g KyNpbmNsdWRlIDxsaW51eC9wb2xsLmg+DQo+ICsNCj4gKyNpbmNsdWRlIDxsaW51eC9zbGFiLmg+ DQo+ICsjaW5jbHVkZSA8bGludXgvdHR5Lmg+DQo+ICsjaW5jbHVkZSA8bGludXgvZXJybm8uaD4N Cj4gKyNpbmNsdWRlIDxsaW51eC9zdHJpbmcuaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9zaWduYWwu aD4NCj4gKyNpbmNsdWRlIDxsaW51eC9pb2N0bC5oPg0KPiArI2luY2x1ZGUgPGxpbnV4L3NrYnVm Zi5oPg0KPiArI2luY2x1ZGUgPGxpbnV4L2xpc3QuaD4NCj4gKw0KPiArI2luY2x1ZGUgPG5ldC9i bHVldG9vdGgvYmx1ZXRvb3RoLmg+DQo+ICsjaW5jbHVkZSA8bmV0L2JsdWV0b290aC9oY2lfY29y ZS5oPg0KPiArDQo+ICsjaW5jbHVkZSA8bGludXgvZ3Bpby9jb25zdW1lci5oPg0KPiArI2luY2x1 ZGUgPGxpbnV4L29mLmg+DQo+ICsjaW5jbHVkZSA8bGludXgvb2ZfZ3Bpby5oPg0KPiArI2luY2x1 ZGUgPGxpbnV4L29mX3BsYXRmb3JtLmg+DQo+ICsNCj4gKyNpbmNsdWRlICJidGJjbV91YXJ0Lmgi DQo+ICsNCj4gK3N0YXRpYyBpbnQgaWRsZVRpbWVvdXQgPSA1Ow0KDQpXZSBkbyBub3QgbmFtZSB2 YXJpYWJsZXMgaW4gY2FtZWwgY2FzZS4gVGhpcyB3b3VsZCBiZSBpZGxlX3RpbWVvdXQuDQoNCklG OiBDaGFuZ2VkLg0KDQo+ICttb2R1bGVfcGFyYW0oaWRsZVRpbWVvdXQsIGludCwgMCk7DQo+ICtN T0RVTEVfUEFSTV9ERVNDKGlkbGVUaW1lb3V0LCAiQmx1ZXRvb3RoIGlkbGUgdGltZW91dCBpbiBz ZWNvbmRzIik7DQo+ICsNCj4gKy8qIERldmljZSBjb250ZXh0ICovDQo+ICtzdHJ1Y3QgYmNtX2Rl dmljZSB7DQo+ICsJc3RydWN0IGxpc3RfaGVhZCBsaXN0Ow0KPiArDQo+ICsJc3RydWN0IHBsYXRm b3JtX2RldmljZSAqcGRldjsNCj4gKwlzdHJ1Y3QgZ3Bpb19kZXNjICpidF93YWtlX2dwaW87DQo+ ICsJc3RydWN0IGdwaW9fZGVzYyAqZGV2X3dha2VfZ3BpbzsNCj4gKwlzdHJ1Y3QgZ3Bpb19kZXNj ICpyZWdfb25fZ3BpbzsNCj4gKwlpbnQgYnRfd2FrZV9pcnE7DQo+ICsJaW50IGRldl93YWtlX2Fj dGl2ZV9sb3c7DQo+ICsJaW50IHJlZ19vbl9hY3RpdmVfbG93Ow0KPiArCWludCBidF93YWtlX2Fj dGl2ZV9sb3c7DQo+ICsJdTMyIGNvbmZpZ3VyZV9zbGVlcDsNCj4gKwl1MzIgbWFudWFsX2ZjOw0K PiArCXUzMiBiYXVkX3JhdGVfYmVmb3JlX2NvbmZpZ19kb3dubG9hZDsNCj4gKwl1MzIgY29uZmln dXJlX2F1ZGlvOw0KPiArCXUzMiBQQ01DbG9ja01vZGU7DQo+ICsJdTMyIFBDTUZpbGxNZXRob2Q7 DQo+ICsJdTMyIFBDTUZpbGxOdW07DQo+ICsJdTMyIFBDTUZpbGxWYWx1ZTsNCj4gKwl1MzIgUENN SW5DYWxsQml0Y2xvY2s7DQo+ICsJdTMyIFBDTUxTQkZpcnN0Ow0KPiArCXUzMiBQQ01SaWdodEp1 c3RpZnk7DQo+ICsJdTMyIFBDTVJvdXRpbmc7DQo+ICsJdTMyIFBDTVNob3J0RnJhbWVTeW5jOw0K PiArCXUzMiBQQ01TeW5jTW9kZTsNCj4gKw0KPiArCWNoYXIgdHR5X25hbWVbNjRdOw0KPiArDQo+ ICsJc3RydWN0IGJ0YmNtX3VhcnRfY2FsbGJhY2tzIHByb3RvY29sX2NhbGxiYWNrczsNCj4gKwlz dHJ1Y3Qgd29ya19zdHJ1Y3Qgd2FrZXVwX3dvcms7DQo+ICt9Ow0KPiArDQo+ICsvKiBMaXN0IG9m IEJDTSBCVCBVQVJUIGRldmljZXMgKi8NCj4gK3N0YXRpYyBERUZJTkVfU1BJTkxPQ0soZGV2aWNl X2xpc3RfbG9jayk7DQo+ICtzdGF0aWMgTElTVF9IRUFEKGRldmljZV9saXN0KTsNCj4gKw0KPiAr LyoNCj4gKyAqIENhbGxpbmcgdGhlIEJDTSBwcm90b2NvbCBhdCBsb3dlciBleGVjdXRpb24gcHJp b3JpdHkNCj4gKyAqLw0KPiArc3RhdGljIHZvaWQgYmNtX2J0X3dha2V1cF90YXNrKHN0cnVjdCB3 b3JrX3N0cnVjdCAqd3MpDQo+ICt7DQo+ICsJaW50IHJlc3VtZV9mbGFnOw0KPiArCXN0cnVjdCBi Y21fZGV2aWNlICpwX2JjbV9kZXZpY2UgPQ0KPiArCQljb250YWluZXJfb2Yod3MsIHN0cnVjdCBi Y21fZGV2aWNlLCB3YWtldXBfd29yayk7DQo+ICsNCj4gKwlpZiAoIXBfYmNtX2RldmljZSkgew0K PiArCQlCVF9EQkcoImJjbV9idF93YWtldXBfdGFzayAtIGZhaWxpbmcsIG5vIGRldmljZSIpOw0K PiArCQlyZXR1cm47DQo+ICsJfQ0KPiArDQo+ICsJLyogTWFrZSBzdXJlIHRoZSBkZXZpY2UgaXMg cmVzdW1lZCAqLw0KPiArCXJlc3VtZV9mbGFnID0gIXBfYmNtX2RldmljZS0+ZGV2X3dha2VfYWN0 aXZlX2xvdzsNCj4gKwlpZiAocF9iY21fZGV2aWNlLT5kZXZfd2FrZV9ncGlvKSB7DQo+ICsJCWdw aW9kX3NldF92YWx1ZShwX2JjbV9kZXZpY2UtPmRldl93YWtlX2dwaW8sIHJlc3VtZV9mbGFnKTsN Cj4gKwkJQlRfREJHKCJiY21fYnRfd2FrZXVwX3Rhc2sgLSByZXN1bWUgJWQgd3JpdHRlbiwgZGVs YXlpbmcgMTUgbXMiLA0KPiArCQkgICAgICAgcmVzdW1lX2ZsYWcpOw0KPiArCQltZGVsYXkoMTUp Ow0KPiArCX0NCj4gKw0KPiArCS8qIExldCB0aGUgcHJvdG9jb2wga25vdyBpdCdzIHRpbWUgdG8g d2FrZSB1cCAqLw0KPiArCWlmIChwX2JjbV9kZXZpY2UtPnByb3RvY29sX2NhbGxiYWNrcy5wX3dh a2V1cCkNCj4gKwkJcF9iY21fZGV2aWNlLT5wcm90b2NvbF9jYWxsYmFja3MucF93YWtldXAoDQo+ ICsJCQlwX2JjbV9kZXZpY2UtPnByb3RvY29sX2NhbGxiYWNrcy5jb250ZXh0KTsNCj4gK30NCj4g Kw0KPiArLyoNCj4gKyAqIEludGVycnVwdCByb3V0aW5lIGZvciB0aGUgd2FrZSBmcm9tIHRoZSBk ZXZpY2UNCj4gKyAqLw0KPiArc3RhdGljIGlycXJldHVybl90IGJjbV9idF91YXJ0X2lzcihpbnQg aXJxLCB2b2lkICpjb250ZXh0KQ0KPiArew0KPiArCXVuc2lnbmVkIGludCBidF93YWtlOw0KPiAr CXN0cnVjdCBiY21fZGV2aWNlICpwID0gKHN0cnVjdCBiY21fZGV2aWNlICopY29udGV4dDsNCj4g Kw0KPiArCWJ0X3dha2UgPSBncGlvZF9nZXRfdmFsdWUocC0+YnRfd2FrZV9ncGlvKTsNCj4gKwlC VF9EQkcoImJjbV9idF91YXJ0X2lzciB3aXRoIGJ0X3dha2Ugb2YgJWQgKGFjdGl2ZV9sb3cgJWQp LCByZXEgYmgiLA0KPiArCSAgICAgICBidF93YWtlLCBwLT5idF93YWtlX2FjdGl2ZV9sb3cpOw0K PiArDQo+ICsJLyogRGVmZXIgdGhlIGFjdHVhbCBwcm9jZXNzaW5nIHRvIHRoZSBwbGF0Zm9ybSB3 b3JrIHF1ZXVlICovDQo+ICsJc2NoZWR1bGVfd29yaygmcC0+d2FrZXVwX3dvcmspOw0KPiArCXJl dHVybiBJUlFfSEFORExFRDsNCj4gK30NCj4gKw0KPiArLyoNCj4gKyAqIERldmljZSBpbnN0YW5j ZSBzdGFydHVwDQo+ICsgKi8NCj4gK3N0YXRpYyBpbnQgYmNtX2J0X3VhcnRfcHJvYmUoc3RydWN0 IHBsYXRmb3JtX2RldmljZSAqcGRldikNCj4gK3sNCj4gKwlpbnQgcmV0ID0gMDsNCj4gKwlzdHJ1 Y3QgZGV2aWNlX25vZGUgKm5wID0gcGRldi0+ZGV2Lm9mX25vZGU7DQo+ICsJY29uc3QgY2hhciAq dHR5X25hbWU7DQo+ICsJc3RydWN0IGJjbV9kZXZpY2UgKnBfYmNtX2RldmljZSA9IE5VTEw7DQo+ ICsNCj4gKwlwX2JjbV9kZXZpY2UgPSBkZXZtX2t6YWxsb2MoJnBkZXYtPmRldiwgc2l6ZW9mKCpw X2JjbV9kZXZpY2UpLA0KPiArCQlHRlBfS0VSTkVMKTsNCj4gKwlpZiAoIXBfYmNtX2RldmljZSkg ew0KPiArCQlCVF9EQkcoImJjbV9idF91YXJ0X3Byb2JlIC0gZmFpbGluZyBkdWUgdG8gbm8gbWVt b3J5Iik7DQo+ICsJCXJldHVybiAtRU5PTUVNOw0KPiArCX0NCj4gKwlwX2JjbV9kZXZpY2UtPnBk ZXYgPSBwZGV2Ow0KPiArCUJUX0RCRygiYmNtX2J0X3VhcnRfcHJvYmUgJXAgY29udGV4dCIsIHBf YmNtX2RldmljZSk7DQo+ICsNCj4gKwkvKiBHZXQgZGV2IHdha2UgR1BJTyAqLw0KPiArCXBfYmNt X2RldmljZS0+ZGV2X3dha2VfZ3BpbyA9IGdwaW9kX2dldCgmcGRldi0+ZGV2LCAiYnQtd2FrZSIp Ow0KPiArCUJUX0RCRygiYmNtX2J0X3VhcnRfcHJvYmUgLSBncGlvZF9nZXQgZm9yIGJ0LXdha2Ug cmV0dXJuZWQgJXAiLA0KPiArCSAgICAgICBwX2JjbV9kZXZpY2UtPmRldl93YWtlX2dwaW8pOw0K PiArCWlmIChJU19FUlIocF9iY21fZGV2aWNlLT5kZXZfd2FrZV9ncGlvKSkgew0KPiArCQlyZXQg PSBQVFJfRVJSKHBfYmNtX2RldmljZS0+ZGV2X3dha2VfZ3Bpbyk7DQo+ICsJCWlmIChyZXQgIT0g LUVOT0VOVCkgew0KPiArCQkJZGV2X2VycigmcGRldi0+ZGV2LA0KPiArCQkJCSJiY21fYnRfdWFy dF9wcm9iZSAtIGRldl93YWtlIEdQSU86ICVkXG4iLCByZXQpOw0KPiArCQl9DQo+ICsJCXBfYmNt X2RldmljZS0+ZGV2X3dha2VfZ3BpbyA9IE5VTEw7DQo+ICsJfSBlbHNlIHsNCj4gKwkJaW50IHJl c3VtZV9mbGFnOw0KPiArDQo+ICsJCXBfYmNtX2RldmljZS0+ZGV2X3dha2VfYWN0aXZlX2xvdyA9 IGdwaW9kX2lzX2FjdGl2ZV9sb3cNCj4gKwkJCShwX2JjbV9kZXZpY2UtPmRldl93YWtlX2dwaW8p Ow0KPiArCQlCVF9EQkcoImJjbV9idF91YXJ0X3Byb2JlIC0gZGV2X3dha2UgYS1sb3cgaXMgJWQg KGNhbnMgJWQpIiwNCj4gKwkJICAgICAgIHBfYmNtX2RldmljZS0+ZGV2X3dha2VfYWN0aXZlX2xv dywNCj4gKwkJICAgICAgIGdwaW9kX2NhbnNsZWVwKHBfYmNtX2RldmljZS0+ZGV2X3dha2VfZ3Bp bykpOw0KPiArDQo+ICsJCS8qIGNvbmZpZ3VyZSBkZXZfd2FrZSBhcyBvdXRwdXQgd2l0aCBpbml0 IHJlc3VtZWQgc3RhdGUgKi8NCj4gKwkJcmVzdW1lX2ZsYWcgPSAhcF9iY21fZGV2aWNlLT5kZXZf d2FrZV9hY3RpdmVfbG93Ow0KPiArCQlyZXQgPSBncGlvZF9kaXJlY3Rpb25fb3V0cHV0KHBfYmNt X2RldmljZS0+ZGV2X3dha2VfZ3BpbywNCj4gKwkJCQkJICAgICByZXN1bWVfZmxhZyk7DQo+ICsJ CWlmIChyZXQgPCAwKSB7DQo+ICsJCQlkZXZfZXJyKCZwZGV2LT5kZXYsDQo+ICsJCQkJImJjbV9i dF91YXJ0X3Byb2JlIHMgZGV2X3dha2UgR1BJTzogJWRcbiIsIHJldCk7DQo+ICsJCQlncGlvZF9w dXQocF9iY21fZGV2aWNlLT5kZXZfd2FrZV9ncGlvKTsNCj4gKwkJCXBfYmNtX2RldmljZS0+ZGV2 X3dha2VfZ3BpbyA9IE5VTEw7DQo+ICsJCQlnb3RvIGVuZDsNCj4gKwkJfSBlbHNlIHsNCj4gKwkJ CUJUX0RCRygiYmNtX2J0X3VhcnRfcHJvYmUgLSBkZXZfd2FrZSBzZXQgdG8gJWQiLA0KPiArCQkJ ICAgICAgIHJlc3VtZV9mbGFnKTsNCj4gKwkJfQ0KPiArCX0NCj4gKw0KPiArCS8qIEdldCBwb3dl ciBvbi9vZmYgR1BJTyAqLw0KPiArCXBfYmNtX2RldmljZS0+cmVnX29uX2dwaW8gPSBncGlvZF9n ZXQoJnBkZXYtPmRldiwgInJlZy1vbiIpOw0KPiArCUJUX0RCRygiYmNtX2J0X3VhcnRfcHJvYmUg LSBncGlvZF9nZXQgZm9yIHJlZy1vbiByZXR1cm5lZCAlcCIsDQo+ICsJICAgICAgIHBfYmNtX2Rl dmljZS0+cmVnX29uX2dwaW8pOw0KPiArCWlmIChJU19FUlIocF9iY21fZGV2aWNlLT5yZWdfb25f Z3BpbykpIHsNCj4gKwkJcmV0ID0gUFRSX0VSUihwX2JjbV9kZXZpY2UtPnJlZ19vbl9ncGlvKTsN Cj4gKwkJaWYgKHJldCAhPSAtRU5PRU5UKSB7DQo+ICsJCQlkZXZfZXJyKCZwZGV2LT5kZXYsDQo+ ICsJCQkJImJjbV9idF91YXJ0X3Byb2JlIC0gcmVnX29uIEdQSU86ICVkXG4iLCByZXQpOw0KPiAr CQl9DQo+ICsJCXBfYmNtX2RldmljZS0+cmVnX29uX2dwaW8gPSBOVUxMOw0KPiArCX0gZWxzZSB7 DQo+ICsJCWludCBwb3dlcm9uX2ZsYWc7DQo+ICsNCj4gKwkJcF9iY21fZGV2aWNlLT5yZWdfb25f YWN0aXZlX2xvdyA9IGdwaW9kX2lzX2FjdGl2ZV9sb3cNCj4gKwkJCShwX2JjbV9kZXZpY2UtPnJl Z19vbl9ncGlvKTsNCj4gKwkJQlRfREJHKCJiY21fYnRfdWFydF9wcm9iZSAtIHJlZ19vbiBhLWxv dyBpcyAlZCAoY2FucyAlZCkiLA0KPiArCQkgICAgICAgcF9iY21fZGV2aWNlLT5yZWdfb25fYWN0 aXZlX2xvdywNCj4gKwkJICAgICAgIGdwaW9kX2NhbnNsZWVwKHBfYmNtX2RldmljZS0+cmVnX29u X2dwaW8pKTsNCj4gKw0KPiArCQkvKiBjb25maWd1cmUgcmVnX29uIGFzIG91dHB1dCB3aXRoIGlu aXQgb24gc3RhdGUgKi8NCj4gKwkJcG93ZXJvbl9mbGFnID0gIXBfYmNtX2RldmljZS0+cmVnX29u X2FjdGl2ZV9sb3c7DQo+ICsJCXJldCA9IGdwaW9kX2RpcmVjdGlvbl9vdXRwdXQocF9iY21fZGV2 aWNlLT5yZWdfb25fZ3BpbywNCj4gKwkJCQkJICAgICBwb3dlcm9uX2ZsYWcpOw0KPiArCQlpZiAo cmV0IDwgMCkgew0KPiArCQkJZGV2X2VycigmcGRldi0+ZGV2LA0KPiArCQkJCSJiY21fYnRfdWFy dF9wcm9iZSBzIHJlZ19vbiBHUElPOiAlZFxuIiwgcmV0KTsNCj4gKwkJCWdwaW9kX3B1dChwX2Jj bV9kZXZpY2UtPnJlZ19vbl9ncGlvKTsNCj4gKwkJCXBfYmNtX2RldmljZS0+cmVnX29uX2dwaW8g PSBOVUxMOw0KPiArCQl9IGVsc2Ugew0KPiArCQkJQlRfREJHKCJiY21fYnRfdWFydF9wcm9iZSAt IHJlZ19vbiBpbml0aWFsbHkgc2V0IHRvICVkIiwNCj4gKwkJCSAgICAgICBwb3dlcm9uX2ZsYWcp Ow0KPiArCQl9DQo+ICsJfQ0KPiArDQo+ICsJcGxhdGZvcm1fc2V0X2RydmRhdGEocGRldiwgcF9i Y21fZGV2aWNlKTsNCj4gKwkvKiBNdXN0IGJlIGRvbmUgYmVmb3JlIGludGVycnVwdCBpcyByZXF1 ZXN0ZWQgKi8NCj4gKwlJTklUX1dPUksoJnBfYmNtX2RldmljZS0+d2FrZXVwX3dvcmssIGJjbV9i dF93YWtldXBfdGFzayk7DQo+ICsNCj4gKwkvKiBHZXQgYnQgaG9zdCB3YWtlIEdQSU8gKi8NCj4g KwlwX2JjbV9kZXZpY2UtPmJ0X3dha2VfZ3BpbyA9IGdwaW9kX2dldCgmcGRldi0+ZGV2LCAiYnQt aG9zdC13YWtlIik7DQo+ICsJQlRfREJHKCJiY21fYnRfdWFydF9wcm9iZSAtIGdwaW9kX2dldCBm b3IgYnQtaG9zdC13YWtlIHJldHVybmVkICVwIiwNCj4gKwkgICAgICAgcF9iY21fZGV2aWNlLT5i dF93YWtlX2dwaW8pOw0KPiArCWlmIChJU19FUlIocF9iY21fZGV2aWNlLT5idF93YWtlX2dwaW8p KSB7DQo+ICsJCXJldCA9IFBUUl9FUlIocF9iY21fZGV2aWNlLT5idF93YWtlX2dwaW8pOw0KPiAr CQlpZiAocmV0ICE9IC1FTk9FTlQpIHsNCj4gKwkJCWRldl9lcnIoJnBkZXYtPmRldiwNCj4gKwkJ CQkiYmNtX2J0X3VhcnRfcHJvYmUgLSBidF93YWtlIEdQSU86ICVkXG4iLCByZXQpOw0KPiArCQl9 DQo+ICsJCXBfYmNtX2RldmljZS0+YnRfd2FrZV9ncGlvID0gTlVMTDsNCj4gKwl9IGVsc2Ugew0K PiArCQkvKiBjb25maWd1cmUgYnRfd2FrZSBhcyBpbnB1dCAqLw0KPiArCQlyZXQgPSBncGlvZF9k aXJlY3Rpb25faW5wdXQocF9iY21fZGV2aWNlLT5idF93YWtlX2dwaW8pOw0KPiArCQlpZiAocmV0 IDwgMCkgew0KPiArCQkJZGV2X2VycigmcGRldi0+ZGV2LA0KPiArCQkJCSJiY21fYnRfdWFydF9w cm9iZSBzIGJ0X3dha2UgR1BJTzogJWRcbiIsIHJldCk7DQo+ICsJCQlncGlvZF9wdXQocF9iY21f ZGV2aWNlLT5idF93YWtlX2dwaW8pOw0KPiArCQkJcF9iY21fZGV2aWNlLT5idF93YWtlX2dwaW8g PSBOVUxMOw0KPiArCQl9IGVsc2Ugew0KPiArCQkJcF9iY21fZGV2aWNlLT5idF93YWtlX2FjdGl2 ZV9sb3cgPSBncGlvZF9pc19hY3RpdmVfbG93DQo+ICsJCQkJKHBfYmNtX2RldmljZS0+YnRfd2Fr ZV9ncGlvKTsNCj4gKwkJCUJUX0RCRygiYmNtX2J0X3VhcnRfcHJvYmUgLWJ0X3dha2UgYS1sb3cg aXMgJWQoY2FucyVkKSIsDQo+ICsJCQkgICAgICAgcF9iY21fZGV2aWNlLT5idF93YWtlX2FjdGl2 ZV9sb3csDQo+ICsJCQkgICAgICAgZ3Bpb2RfY2Fuc2xlZXAocF9iY21fZGV2aWNlLT5idF93YWtl X2dwaW8pKTsNCj4gKwkJCXBfYmNtX2RldmljZS0+YnRfd2FrZV9pcnEgPSBncGlvZF90b19pcnEN Cj4gKwkJCQkocF9iY21fZGV2aWNlLT5idF93YWtlX2dwaW8pOw0KPiArCQkJaWYgKHBfYmNtX2Rl dmljZS0+YnRfd2FrZV9pcnEgPCAwKSB7DQo+ICsJCQkJZGV2X2VycigmcGRldi0+ZGV2LA0KPiAr CQkJCSJiY21fYnRfdWFydF9wcm9iZSAtIEhPU1RfV0FLRSBJUlE6ICVkXG4iLCByZXQpOw0KPiAr CQkJfSBlbHNlIHsNCj4gKwkJCQl1bnNpZ25lZCBsb25nIGludGZsYWdzID0gSVJRRl9UUklHR0VS X1JJU0lORzsNCj4gKw0KPiArCQkJCWlmIChwX2JjbV9kZXZpY2UtPmJ0X3dha2VfYWN0aXZlX2xv dykNCj4gKwkJCQkJaW50ZmxhZ3MgPSBJUlFGX1RSSUdHRVJfRkFMTElORzsNCj4gKw0KPiArCQkJ CXJldCA9IHJlcXVlc3RfaXJxKHBfYmNtX2RldmljZS0+YnRfd2FrZV9pcnEsDQo+ICsJCQkJCQkg IGJjbV9idF91YXJ0X2lzciwNCj4gKwkJCQkJCSAgaW50ZmxhZ3MsICJidF9ob3N0X3dha2UiLA0K PiArCQkJCQkJICBwX2JjbV9kZXZpY2UpOw0KPiArCQkJCWlmIChyZXQgPCAwKSB7DQo+ICsJCQkJ CWRldl9lcnIoJnBkZXYtPmRldiwgImJjbV9idF91YXJ0X3Byb2JlIC0gZmFpbGVkIHRvIGNvbmYg SVJRICVkOiAlZCIsDQo+ICsJCQkJCQlwX2JjbV9kZXZpY2UtPmJ0X3dha2VfaXJxLCByZXQpOw0K PiArCQkJCX0gZWxzZSB7DQo+ICsJCQkJCUJUX0RCRygiYmNtX2J0X3VhcnRfcHJvYmUgLSBJUlEg JWQiLA0KPiArCQkJCQkgICAgICAgcF9iY21fZGV2aWNlLT5idF93YWtlX2lycSk7DQo+ICsJCQkJ fQ0KPiArCQkJfQ0KPiArCQl9DQo+ICsJfQ0KPiArDQo+ICsJcF9iY21fZGV2aWNlLT5jb25maWd1 cmVfc2xlZXAgPSAwOw0KPiArCWlmICghb2ZfcHJvcGVydHlfcmVhZF91MzIobnAsICJjb25maWd1 cmUtc2xlZXAiLA0KPiArCQkJCSAgJnBfYmNtX2RldmljZS0+Y29uZmlndXJlX3NsZWVwKSkgew0K PiArCQlCVF9EQkcoImNvbmZpZ3VyZS1zbGVlcCByZWFkIGFzICVkIiwNCj4gKwkJCXBfYmNtX2Rl dmljZS0+Y29uZmlndXJlX3NsZWVwKTsNCj4gKwl9DQo+ICsJcF9iY21fZGV2aWNlLT5tYW51YWxf ZmMgPSAwOw0KPiArCWlmICghb2ZfcHJvcGVydHlfcmVhZF91MzIobnAsICJtYW51YWwtZmMiLA0K PiArCQkJCSAgJnBfYmNtX2RldmljZS0+bWFudWFsX2ZjKSkgew0KPiArCQlCVF9EQkcoIm1hbnVh bC1mYyByZWFkIGFzICVkIiwNCj4gKwkJCXBfYmNtX2RldmljZS0+bWFudWFsX2ZjKTsNCj4gKwl9 DQo+ICsJcF9iY21fZGV2aWNlLT5iYXVkX3JhdGVfYmVmb3JlX2NvbmZpZ19kb3dubG9hZCA9IDMw MDAwMDA7DQo+ICsJaWYgKCFvZl9wcm9wZXJ0eV9yZWFkX3UzMigNCj4gKwkJbnAsICJiYXVkLXJh dGUtYmVmb3JlLWNvbmZpZy1kb3dubG9hZCIsDQo+ICsJCSZwX2JjbV9kZXZpY2UtPmJhdWRfcmF0 ZV9iZWZvcmVfY29uZmlnX2Rvd25sb2FkKSkgew0KPiArCQlCVF9EQkcoImJhdWQtcmF0ZS1iZWZv cmUtY29uZmlnLWRvd25sb2FkIHJlYWQgYXMgJWQiLA0KPiArCQkJcF9iY21fZGV2aWNlLT5iYXVk X3JhdGVfYmVmb3JlX2NvbmZpZ19kb3dubG9hZCk7DQo+ICsJfQ0KPiArCXBfYmNtX2RldmljZS0+ Y29uZmlndXJlX2F1ZGlvID0gMDsNCj4gKwlpZiAoIW9mX3Byb3BlcnR5X3JlYWRfdTMyKG5wLCAi Y29uZmlndXJlLWF1ZGlvIiwNCj4gKwkJCQkgICZwX2JjbV9kZXZpY2UtPmNvbmZpZ3VyZV9hdWRp bykpIHsNCj4gKwkJQlRfREJHKCJjb25maWd1cmUtYXVkaW8gcmVhZCBhcyAlZCIsDQo+ICsJCQlw X2JjbV9kZXZpY2UtPmNvbmZpZ3VyZV9hdWRpbyk7DQo+ICsJfQ0KPiArCWlmIChwX2JjbV9kZXZp Y2UtPmNvbmZpZ3VyZV9hdWRpbykgew0KPiArCQkvKiBEZWZhdWx0cyBmb3IgYXVkaW8gKi8NCj4g KwkJcF9iY21fZGV2aWNlLT5QQ01DbG9ja01vZGUgPSAwOw0KPiArCQlwX2JjbV9kZXZpY2UtPlBD TUZpbGxNZXRob2QgPSAyOw0KPiArCQlwX2JjbV9kZXZpY2UtPlBDTUZpbGxOdW0gPSAwOw0KPiAr CQlwX2JjbV9kZXZpY2UtPlBDTUZpbGxWYWx1ZSA9IDM7DQo+ICsJCXBfYmNtX2RldmljZS0+UENN SW5DYWxsQml0Y2xvY2sgPSAwOw0KPiArCQlwX2JjbV9kZXZpY2UtPlBDTUxTQkZpcnN0ID0gMDsN Cj4gKwkJcF9iY21fZGV2aWNlLT5QQ01SaWdodEp1c3RpZnkgPSAwOw0KPiArCQlwX2JjbV9kZXZp Y2UtPlBDTVJvdXRpbmcgPSAwOw0KPiArCQlwX2JjbV9kZXZpY2UtPlBDTVNob3J0RnJhbWVTeW5j ID0gMDsNCj4gKwkJcF9iY21fZGV2aWNlLT5QQ01TeW5jTW9kZSA9IDA7DQo+ICsNCj4gKwkJaWYg KCFvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgIlBDTUNsb2NrTW9kZSIsDQo+ICsJCQkJCSAgJnBf YmNtX2RldmljZS0+UENNQ2xvY2tNb2RlKSkNCj4gKwkJCUJUX0RCRygiUENNQ2xvY2tNb2RlIHJl YWQgYXMgJWQiLA0KPiArCQkJCXBfYmNtX2RldmljZS0+UENNQ2xvY2tNb2RlKTsNCj4gKwkJaWYg KCFvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgIlBDTUZpbGxNZXRob2QiLA0KPiArCQkJCQkgICZw X2JjbV9kZXZpY2UtPlBDTUZpbGxNZXRob2QpKQ0KPiArCQkJQlRfREJHKCJQQ01GaWxsTWV0aG9k IHJlYWRhcyAlZCIsDQo+ICsJCQkJcF9iY21fZGV2aWNlLT5QQ01GaWxsTWV0aG9kKTsNCj4gKwkJ aWYgKCFvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgIlBDTUZpbGxOdW0iLA0KPiArCQkJCQkgICZw X2JjbV9kZXZpY2UtPlBDTUZpbGxOdW0pKQ0KPiArCQkJQlRfREJHKCJQQ01GaWxsTnVtIHJlYWQg YXMgJWQiLA0KPiArCQkJCXBfYmNtX2RldmljZS0+UENNRmlsbE51bSk7DQo+ICsJCWlmICghb2Zf cHJvcGVydHlfcmVhZF91MzIobnAsICJQQ01GaWxsVmFsdWUiLA0KPiArCQkJCQkgICZwX2JjbV9k ZXZpY2UtPlBDTUZpbGxWYWx1ZSkpDQo+ICsJCQlCVF9EQkcoIlBDTUZpbGxWYWx1ZSByZWFkIGFz ICVkIiwNCj4gKwkJCQlwX2JjbV9kZXZpY2UtPlBDTUZpbGxWYWx1ZSk7DQo+ICsJCWlmICghb2Zf cHJvcGVydHlfcmVhZF91MzIobnAsICJQQ01JbkNhbGxCaXRjbG9jayIsDQo+ICsJCQkJCSAgJnBf YmNtX2RldmljZS0+UENNSW5DYWxsQml0Y2xvY2spKQ0KPiArCQkJQlRfREJHKCJQQ01JbkNhbGxC aXRjbG9jayByZWFkIGFzICVkIiwNCj4gKwkJCQlwX2JjbV9kZXZpY2UtPlBDTUluQ2FsbEJpdGNs b2NrKTsNCj4gKwkJaWYgKCFvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgIlBDTUxTQkZpcnN0IiwN Cj4gKwkJCQkJICAmcF9iY21fZGV2aWNlLT5QQ01MU0JGaXJzdCkpDQo+ICsJCQlCVF9EQkcoIlBD TUxTQkZpcnN0IHJlYWQgYXMgJWQiLA0KPiArCQkJCXBfYmNtX2RldmljZS0+UENNTFNCRmlyc3Qp Ow0KPiArCQlpZiAoIW9mX3Byb3BlcnR5X3JlYWRfdTMyKG5wLCAiUENNUmlnaHRKdXN0aWZ5IiwN Cj4gKwkJCQkJICAmcF9iY21fZGV2aWNlLT5QQ01SaWdodEp1c3RpZnkpKQ0KPiArCQkJQlRfREJH KCJQQ01SaWdodEp1c3RpZnkgcmVhZCBhcyAlZCIsDQo+ICsJCQkJcF9iY21fZGV2aWNlLT5QQ01S aWdodEp1c3RpZnkpOw0KPiArCQlpZiAoIW9mX3Byb3BlcnR5X3JlYWRfdTMyKG5wLCAiUENNUm91 dGluZyIsDQo+ICsJCQkJCSAgJnBfYmNtX2RldmljZS0+UENNUm91dGluZykpDQo+ICsJCQlCVF9E QkcoIlBDTVJvdXRpbmcgcmVhZCBhcyAlZCIsDQo+ICsJCQkJcF9iY21fZGV2aWNlLT5QQ01Sb3V0 aW5nKTsNCj4gKwkJaWYgKCFvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgIlBDTVNob3J0RnJhbWVT eW5jIiwNCj4gKwkJCQkJICAmcF9iY21fZGV2aWNlLT5QQ01TaG9ydEZyYW1lU3luYykpDQo+ICsJ CQlCVF9EQkcoIlBDTVNob3J0RnJhbWVTeW5jIHJlYWQgYXMgJWQiLA0KPiArCQkJCXBfYmNtX2Rl dmljZS0+UENNU2hvcnRGcmFtZVN5bmMpOw0KPiArCQlpZiAoIW9mX3Byb3BlcnR5X3JlYWRfdTMy KG5wLCAiUENNU3luY01vZGUiLA0KPiArCQkJCQkgICZwX2JjbV9kZXZpY2UtPlBDTVN5bmNNb2Rl KSkNCj4gKwkJCUJUX0RCRygiUENNU3luY01vZGUgcmVhZCBhcyAlZCIsDQo+ICsJCQkJcF9iY21f ZGV2aWNlLT5QQ01TeW5jTW9kZSk7DQo+ICsJfQ0KPiArDQo+ICsJaWYgKCFvZl9wcm9wZXJ0eV9y ZWFkX3N0cmluZyhucCwgInR0eSIsICZ0dHlfbmFtZSkpIHsNCj4gKwkJc3RyY3B5KHBfYmNtX2Rl dmljZS0+dHR5X25hbWUsIHR0eV9uYW1lKTsNCj4gKwkJQlRfREJHKCJ0dHkgbmFtZSByZWFkIGFz ICVzIiwgcF9iY21fZGV2aWNlLT50dHlfbmFtZSk7DQo+ICsJfQ0KPiArDQo+ICsJQlRfREJHKCJp ZGxlVGltZW91dCBzZXQgYXMgJWQiLCBpZGxlVGltZW91dCk7DQo+ICsNCj4gKwlyZXQgPSAwOyAg LyogSWYgd2UgbWFkZSBpdCBoZXJlLCB3ZSdyZSBmaW5lICovDQo+ICsNCj4gKwkvKiBQbGFjZSB0 aGlzIGluc3RhbmNlIG9uIHRoZSBkZXZpY2UgbGlzdCAqLw0KPiArCXNwaW5fbG9jaygmZGV2aWNl X2xpc3RfbG9jayk7DQo+ICsJbGlzdF9hZGRfdGFpbCgmcF9iY21fZGV2aWNlLT5saXN0LCAmZGV2 aWNlX2xpc3QpOw0KPiArCXNwaW5fdW5sb2NrKCZkZXZpY2VfbGlzdF9sb2NrKTsNCj4gKw0KPiAr ZW5kOg0KPiArCWlmIChyZXQpIHsNCj4gKwkJaWYgKHBfYmNtX2RldmljZS0+cmVnX29uX2dwaW8p IHsNCj4gKwkJCWdwaW9kX3B1dChwX2JjbV9kZXZpY2UtPnJlZ19vbl9ncGlvKTsNCj4gKwkJCXBf YmNtX2RldmljZS0+cmVnX29uX2dwaW8gPSBOVUxMOw0KPiArCQl9DQo+ICsJCWlmIChwX2JjbV9k ZXZpY2UtPmJ0X3dha2VfZ3Bpbykgew0KPiArCQkJZ3Bpb2RfcHV0KHBfYmNtX2RldmljZS0+YnRf d2FrZV9ncGlvKTsNCj4gKwkJCXBfYmNtX2RldmljZS0+YnRfd2FrZV9ncGlvID0gTlVMTDsNCj4g KwkJfQ0KPiArCQlpZiAocF9iY21fZGV2aWNlLT5kZXZfd2FrZV9ncGlvKSB7DQo+ICsJCQlncGlv ZF9wdXQocF9iY21fZGV2aWNlLT5kZXZfd2FrZV9ncGlvKTsNCj4gKwkJCXBfYmNtX2RldmljZS0+ ZGV2X3dha2VfZ3BpbyA9IE5VTEw7DQo+ICsJCX0NCj4gKwl9DQo+ICsNCj4gKwlCVF9EQkcoImJj bV9idF91YXJ0X3Byb2JlIHdpdGggdGhlIHJlc3VsdCAlZCIsIHJldCk7DQo+ICsJcmV0dXJuIHJl dDsNCj4gK30NCj4gKw0KPiArLyoNCj4gKyAqIERldmljZSBpbnN0YW5jZSByZW1vdmFsDQo+ICsg Ki8NCj4gK3N0YXRpYyBpbnQgYmNtX2J0X3VhcnRfcmVtb3ZlKHN0cnVjdCBwbGF0Zm9ybV9kZXZp Y2UgKnBkZXYpDQo+ICt7DQo+ICsJc3RydWN0IGJjbV9kZXZpY2UgKnBfYmNtX2RldmljZSA9IHBs YXRmb3JtX2dldF9kcnZkYXRhKHBkZXYpOw0KPiArDQo+ICsJaWYgKHBfYmNtX2RldmljZSA9PSBO VUxMKSB7DQo+ICsJCUJUX0RCRygiYmNtX2J0X3VhcnRfcmVtb3ZlIC0gbG9naWMgZXJyb3IsIG5v IHByb2JlPyEiKTsNCj4gKwkJcmV0dXJuIDA7DQo+ICsJfQ0KPiArDQo+ICsJQlRfREJHKCJiY21f YnRfdWFydF9yZW1vdmUgJXAgY29udGV4dCIsIHBfYmNtX2RldmljZSk7DQo+ICsNCj4gKwlzcGlu X2xvY2soJmRldmljZV9saXN0X2xvY2spOw0KPiArCWxpc3RfZGVsKCZwX2JjbV9kZXZpY2UtPmxp c3QpOw0KPiArCXNwaW5fdW5sb2NrKCZkZXZpY2VfbGlzdF9sb2NrKTsNCj4gKw0KPiArCUJUX0RC RygiYmNtX2J0X3VhcnRfcmVtb3ZlIC0gZnJlZWluZyBpbnRlcnJ1cHQgJWQiLA0KPiArCQlwX2Jj bV9kZXZpY2UtPmJ0X3dha2VfaXJxKTsNCj4gKwlmcmVlX2lycShwX2JjbV9kZXZpY2UtPmJ0X3dh a2VfaXJxLCBwX2JjbV9kZXZpY2UpOw0KPiArDQo+ICsJaWYgKHBfYmNtX2RldmljZS0+cmVnX29u X2dwaW8pIHsNCj4gKwkJQlRfREJHKCJiY21fYnRfdWFydF9yZW1vdmUgLSByZWxlYXNpbmcgcmVn X29uX2dwaW8iKTsNCj4gKwkJZ3Bpb2RfcHV0KHBfYmNtX2RldmljZS0+cmVnX29uX2dwaW8pOw0K PiArCQlwX2JjbV9kZXZpY2UtPnJlZ19vbl9ncGlvID0gTlVMTDsNCj4gKwl9DQo+ICsNCj4gKwlp ZiAocF9iY21fZGV2aWNlLT5kZXZfd2FrZV9ncGlvKSB7DQo+ICsJCUJUX0RCRygiYmNtX2J0X3Vh cnRfcmVtb3ZlIC0gcmVsZWFzaW5nIGRldl93YWtlX2dwaW8iKTsNCj4gKwkJZ3Bpb2RfcHV0KHBf YmNtX2RldmljZS0+ZGV2X3dha2VfZ3Bpbyk7DQo+ICsJCXBfYmNtX2RldmljZS0+ZGV2X3dha2Vf Z3BpbyA9IE5VTEw7DQo+ICsJfQ0KPiArDQo+ICsJaWYgKHBfYmNtX2RldmljZS0+YnRfd2FrZV9n cGlvKSB7DQo+ICsJCUJUX0RCRygiYmNtX2J0X3VhcnRfcmVtb3ZlIC0gcmVsZWFzaW5nIGJ0X3dh a2VfZ3BpbyIpOw0KPiArCQlncGlvZF9wdXQocF9iY21fZGV2aWNlLT5idF93YWtlX2dwaW8pOw0K PiArCQlwX2JjbV9kZXZpY2UtPmJ0X3dha2VfZ3BpbyA9IE5VTEw7DQo+ICsJfQ0KPiArDQo+ICsJ QlRfREJHKCJiY21fYnRfdWFydF9yZW1vdmUgJXAgZG9uZSIsIHBfYmNtX2RldmljZSk7DQo+ICsJ cmV0dXJuIDA7DQo+ICt9DQo+ICsNCj4gKy8qDQo+ICsgKiBQbGF0Zm9ybSByZXN1bWUgY2FsbGJh Y2sNCj4gKyAqLw0KPiArc3RhdGljIGludCBiY21fYnRfdWFydF9yZXN1bWUoc3RydWN0IGRldmlj ZSAqcGRldikNCj4gK3sNCj4gKwlpbnQgcmVzdW1lX2ZsYWc7DQo+ICsJc3RydWN0IGJjbV9kZXZp Y2UgKnBfYmNtX2RldmljZSA9IHBsYXRmb3JtX2dldF9kcnZkYXRhKA0KPiArCQl0b19wbGF0Zm9y bV9kZXZpY2UocGRldikpOw0KPiArDQo+ICsJaWYgKHBfYmNtX2RldmljZSA9PSBOVUxMKSB7DQo+ ICsJCUJUX0RCRygiYmNtX2J0X3VhcnRfcmVzdW1lIC0gbG9naWMgZXJyb3IsIG5vIGRldmljZT8h Iik7DQo+ICsJCXJldHVybiAwOw0KPiArCX0NCj4gKw0KPiArCUJUX0RCRygiYmNtX2J0X3VhcnRf cmVzdW1lICVwIiwgcF9iY21fZGV2aWNlKTsNCj4gKw0KPiArCXJlc3VtZV9mbGFnID0gIXBfYmNt X2RldmljZS0+ZGV2X3dha2VfYWN0aXZlX2xvdzsNCj4gKwlpZiAocF9iY21fZGV2aWNlLT5kZXZf d2FrZV9ncGlvKSB7DQo+ICsJCWdwaW9kX3NldF92YWx1ZShwX2JjbV9kZXZpY2UtPmRldl93YWtl X2dwaW8sIHJlc3VtZV9mbGFnKTsNCj4gKwkJQlRfREJHKCJiY21fYnRfdWFydF9yZXN1bWU6ICVk IHdyaXR0ZW4sIGRlbGF5aW5nIDE1IG1zIiwNCj4gKwkJICAgICAgIHJlc3VtZV9mbGFnKTsNCj4g KwkJbWRlbGF5KDE1KTsNCj4gKwl9DQo+ICsNCj4gKwkvKiBMZXQgdGhlIHByb3RvY29sIGtub3cg dGhlIHBsYXRmb3JtIGlzIHJlc3VtaW5nICovDQo+ICsJaWYgKHBfYmNtX2RldmljZS0+cHJvdG9j b2xfY2FsbGJhY2tzLnBfcmVzdW1lKQ0KPiArCQlwX2JjbV9kZXZpY2UtPnByb3RvY29sX2NhbGxi YWNrcy5wX3Jlc3VtZSgNCj4gKwkJCXBfYmNtX2RldmljZS0+cHJvdG9jb2xfY2FsbGJhY2tzLmNv bnRleHQpOw0KPiArDQo+ICsJcmV0dXJuIDA7DQo+ICt9DQo+ICsNCj4gKy8qDQo+ICsgKiBQbGF0 Zm9ybSBzdXNwZW5kIGNhbGxiYWNrDQo+ICsgKi8NCj4gK3N0YXRpYyBpbnQgYmNtX2J0X3VhcnRf c3VzcGVuZChzdHJ1Y3QgZGV2aWNlICpwZGV2KQ0KPiArew0KPiArCWludCByZXN1bWVfZmxhZzsN Cj4gKwlzdHJ1Y3QgYmNtX2RldmljZSAqcF9iY21fZGV2aWNlID0gcGxhdGZvcm1fZ2V0X2RydmRh dGEoDQo+ICsJCXRvX3BsYXRmb3JtX2RldmljZShwZGV2KSk7DQo+ICsNCj4gKwlpZiAocF9iY21f ZGV2aWNlID09IE5VTEwpIHsNCj4gKwkJQlRfREJHKCJiY21fYnRfdWFydF9zdXNwZW5kIC0gbG9n aWMgZXJyb3IsIG5vIGRldmljZT8hIik7DQo+ICsJCXJldHVybiAwOw0KPiArCX0NCj4gKw0KPiAr CUJUX0RCRygiYmNtX2J0X3VhcnRfc3VzcGVuZCAlcCIsIHBfYmNtX2RldmljZSk7DQo+ICsNCj4g KwkvKiBMZXQgdGhlIHByb3RvY29sIGtub3cgdGhlIHBsYXRmb3JtIGlzIHN1c3BlbmRpbmcgKi8N Cj4gKwlpZiAocF9iY21fZGV2aWNlLT5wcm90b2NvbF9jYWxsYmFja3MucF9zdXNwZW5kKQ0KPiAr CQlwX2JjbV9kZXZpY2UtPnByb3RvY29sX2NhbGxiYWNrcy5wX3N1c3BlbmQoDQo+ICsJCQlwX2Jj bV9kZXZpY2UtPnByb3RvY29sX2NhbGxiYWNrcy5jb250ZXh0KTsNCj4gKw0KPiArCS8qIFN1c3Bl bmQgdGhlIGRldmljZSAqLw0KPiArCWlmIChwX2JjbV9kZXZpY2UtPmRldl93YWtlX2dwaW8pIHsN Cj4gKwkJcmVzdW1lX2ZsYWcgPSAhcF9iY21fZGV2aWNlLT5kZXZfd2FrZV9hY3RpdmVfbG93Ow0K PiArCQlncGlvZF9zZXRfdmFsdWUocF9iY21fZGV2aWNlLT5kZXZfd2FrZV9ncGlvLCAhcmVzdW1l X2ZsYWcpOw0KPiArCQlCVF9EQkcoImJjbV9idF91YXJ0X3N1c3BlbmQ6ICVkIHdyaXR0ZW4sIGRl bGF5aW5nIDE1IG1zIiwNCj4gKwkJCSFyZXN1bWVfZmxhZyk7DQo+ICsJCW1kZWxheSgxNSk7DQo+ ICsJfQ0KPiArDQo+ICsJcmV0dXJuIDA7DQo+ICt9DQo+ICsNCj4gKy8qDQo+ICsgKiBFbnRyeSBw b2ludCBmb3IgY2FsbHMgZnJvbSB0aGUgcHJvdG9jb2wNCj4gKyAqLw0KPiAraW50IGJ0YmNtX3Vh cnRfY29udHJvbChpbnQgYWN0aW9uLCB2b2lkICpkZXZpY2VfY29udGV4dCwNCj4gKwl2b2lkICpw X2RhdGEsIHVuc2lnbmVkIGxvbmcgKnBfc2l6ZSkNCj4gK3sNCj4gKwlzdHJ1Y3QgYnRiY21fdWFy dF9jYWxsYmFja3MgKnBjOw0KPiArCXN0cnVjdCBidGJjbV91YXJ0X3BhcmFtZXRlcnMgKnBwID0g cF9kYXRhOyAvKiBmb3IgcGFycyBhY3Rpb24gb25seSAqLw0KPiArCWludCByZXQgPSAwOw0KPiAr CWludCByZXN1bWVfZmxhZywgcG93ZXJvbl9mbGFnOw0KDQpGb3IgdHJ1ZSBib29sZWFuIHZhcmlh YmxlLCBwbGVhc2UgdXNlIGJvb2wgaW5zdGVhZCBvZiBpbnQuDQoNCklGOiBUaGVzZSBhcmUgYWN0 dWFsbHkgcGFyYW1ldGVycyBmb3IgdGhlIEdQSU8gY2FsbHMgc28gdGhleSBzaG91bGQgYmUgImlu dCIuDQoNCj4gKwlzdHJ1Y3QgYmNtX2RldmljZSAqcF9iY21fZGV2aWNlID0gZGV2aWNlX2NvbnRl eHQ7DQo+ICsJc3RydWN0IGxpc3RfaGVhZCAqcHRyOw0KPiArCWJvb2wgaXNfZm91bmQgPSBmYWxz ZTsNCj4gKw0KPiArCS8qIFNwZWNpYWwgcHJvY2Vzc2luZyBmb3IgdGhlIGNhbGxiYWNrIGNvbmZp Z3VyYXRpb24gKi8NCj4gKwlpZiAoYWN0aW9uID09IEJUQkNNX1VBUlRfQUNUSU9OX0NPTkZJR1VS RV9DQUxMQkFDS1MpIHsNCj4gKwkJcGMgPSBwX2RhdGE7DQo+ICsNCj4gKwkJQlRfREJHKCJidGJj bV91YXJ0X2NvbnRyb2wgLSBjb25maWd1cmUgY2FsbGJhY2tzIik7DQo+ICsJCWlmICgocF9kYXRh ID09IE5VTEwpIHx8ICpwX3NpemUgIT0gc2l6ZW9mKHN0cnVjdA0KDQpFeHRyYSAoKSBhcm91bmQg eCA9PSB5IGFyZSBub3QgbmVlZGVkLiBEbyBib3RoZXIgd2l0aCB0aGVtLg0KIA0KSUY6IENoYW5n ZWQuDQoNCj4gKwkJCWJ0YmNtX3VhcnRfY2FsbGJhY2tzKSB8fCAocGMtPmludGVyZmFjZV92ZXJz aW9uICE9DQo+ICsJCQlCVEJDTV9VQVJUX0lOVEVSRkFDRV9WRVJTSU9OKSkgew0KDQpXcm9uZyBp bmRlbnRhdGlvbi4NCg0KSUY6IENoYW5nZWQuDQoNCj4gKwkJCUJUX0RCRygiYnRiY21fdWFydF9j b250cm9sIC0gY2FsbGJhY2tzIG1pc21hdGNoISIpOw0KPiArCQkJcmV0dXJuIC1FMkJJRzsNCj4g KwkJfQ0KPiArDQo+ICsJCUJUX0RCRygiYnRiY21fdWFydF9jb250cm9sIC0gY29uZmlndXJlIGNh bGxiYWNrcyBmb3IgJXMoJXApIiwNCj4gKwkJICAgICAgIHBjLT5uYW1lLCBwYy0+Y29udGV4dCk7 DQo+ICsJCWlmIChwX2JjbV9kZXZpY2UgPT0gTlVMTCkgew0KPiArCQkJc3Bpbl9sb2NrKCZkZXZp Y2VfbGlzdF9sb2NrKTsNCj4gKwkJCWxpc3RfZm9yX2VhY2gocHRyLCAmZGV2aWNlX2xpc3QpIHsN Cj4gKwkJCQlwX2JjbV9kZXZpY2UgPSBsaXN0X2VudHJ5KHB0ciwgc3RydWN0DQo+ICsJCQkJCQkJ ICBiY21fZGV2aWNlLCBsaXN0KTsNCj4gKwkJCQlpZiAoIXN0cmNtcChwX2JjbV9kZXZpY2UtPnR0 eV9uYW1lLCBwYy0+bmFtZSkpIHsNCj4gKwkJCQkJaXNfZm91bmQgPSB0cnVlOw0KPiArCQkJCQli cmVhazsNCj4gKwkJCQl9DQo+ICsJCQl9DQo+ICsNCj4gKwkJCXNwaW5fdW5sb2NrKCZkZXZpY2Vf bGlzdF9sb2NrKTsNCj4gKwkJCWlmICghaXNfZm91bmQpIHsNCj4gKwkJCQlCVF9EQkcoImJ0YmNt X3VhcnRfY29udHJvbCAtIG5vIGRldmljZSEiKTsNCj4gKwkJCQlyZXR1cm4gLUVOT0VOVDsNCj4g KwkJCX0NCj4gKwkJfQ0KPiArDQo+ICsJCXBfYmNtX2RldmljZS0+cHJvdG9jb2xfY2FsbGJhY2tz ID0gKnBjOw0KPiArCQltZW1jcHkocF9kYXRhLCAmcF9iY21fZGV2aWNlLCBzaXplb2YocF9iY21f ZGV2aWNlKSk7DQo+ICsJCSpwX3NpemUgPSBzaXplb2YocF9iY21fZGV2aWNlKTsNCj4gKwkJcmV0 dXJuIHJldDsNCj4gKwl9DQo+ICsNCj4gKwkvKiBBbGwgb3RoZXIgcmVxdWVzdHMgbXVzdCBoYXZl IHRoZSByaWdodCBjb250ZXh0ICovDQo+ICsJaWYgKHBfYmNtX2RldmljZSA9PSBOVUxMKSB7DQo+ ICsJCUJUX0RCRygiYnRiY21fdWFydF9jb250cm9sIC0gZmFpbGluZywgbm8gZGV2aWNlIik7DQo+ ICsJCXJldHVybiAtRU5PRU5UOw0KPiArCX0NCj4gKw0KPiArCXN3aXRjaCAoYWN0aW9uKSB7DQo+ ICsJY2FzZSBCVEJDTV9VQVJUX0FDVElPTl9QT1dFUl9PTjoNCj4gKwkJQlRfREJHKCJidGJjbV91 YXJ0X2NvbnRyb2wgJXAgLSBwb3dlciBvbiIsIGRldmljZV9jb250ZXh0KTsNCj4gKwkJaWYgKHBf YmNtX2RldmljZS0+cmVnX29uX2dwaW8pIHsNCj4gKwkJCXBvd2Vyb25fZmxhZyA9ICFwX2JjbV9k ZXZpY2UtPnJlZ19vbl9hY3RpdmVfbG93Ow0KPiArCQkJZ3Bpb2Rfc2V0X3ZhbHVlKHBfYmNtX2Rl dmljZS0+cmVnX29uX2dwaW8sDQo+ICsJCQkJCXBvd2Vyb25fZmxhZyk7DQo+ICsJCQlCVF9EQkco ImJ0YmNtX3VhcnRfY29udHJvbCAtIHB3cm9uICVkLCBkZWxheSAxNSBtcyIsDQo+ICsJCQkgICAg ICAgcG93ZXJvbl9mbGFnKTsNCj4gKwkJCW1kZWxheSgxNSk7DQo+ICsJCX0NCj4gKwkJYnJlYWs7 DQo+ICsNCj4gKwljYXNlIEJUQkNNX1VBUlRfQUNUSU9OX1BPV0VSX09GRjoNCj4gKwkJQlRfREJH KCJidGJjbV91YXJ0X2NvbnRyb2wgJXAgLSBwb3dlciBvZmYiLCBkZXZpY2VfY29udGV4dCk7DQo+ ICsJCWlmIChwX2JjbV9kZXZpY2UtPnJlZ19vbl9ncGlvKSB7DQo+ICsJCQlwb3dlcm9uX2ZsYWcg PSBwX2JjbV9kZXZpY2UtPnJlZ19vbl9hY3RpdmVfbG93Ow0KPiArCQkJZ3Bpb2Rfc2V0X3ZhbHVl KHBfYmNtX2RldmljZS0+cmVnX29uX2dwaW8sDQo+ICsJCQkJCXBvd2Vyb25fZmxhZyk7DQo+ICsJ CQlCVF9EQkcoImJ0YmNtX3VhcnRfY29udHJvbCAtIHB3cm9mZiAlZCwgZGVsYXkgMTUgbXMiLA0K PiArCQkJICAgICAgIHBvd2Vyb25fZmxhZyk7DQo+ICsJCQltZGVsYXkoMTUpOw0KPiArCQl9DQo+ ICsJCWJyZWFrOw0KPiArDQo+ICsJY2FzZSBCVEJDTV9VQVJUX0FDVElPTl9SRVNVTUU6DQo+ICsJ CUJUX0RCRygiYnRiY21fdWFydF9jb250cm9sICVwIC0gcmVzdW1lIiwgZGV2aWNlX2NvbnRleHQp Ow0KPiArCQlpZiAocF9iY21fZGV2aWNlLT5kZXZfd2FrZV9ncGlvKSB7DQo+ICsJCQlyZXN1bWVf ZmxhZyA9ICFwX2JjbV9kZXZpY2UtPmRldl93YWtlX2FjdGl2ZV9sb3c7DQo+ICsJCQlncGlvZF9z ZXRfdmFsdWUocF9iY21fZGV2aWNlLT5kZXZfd2FrZV9ncGlvLA0KPiArCQkJCQlyZXN1bWVfZmxh Zyk7DQo+ICsJCQlCVF9EQkcoImJ0YmNtX3VhcnRfY29udHJvbCAtIHJlc3VtZSAlZCwgZGVsYXkg MTUgbXMiLA0KPiArCQkJICAgICAgIHJlc3VtZV9mbGFnKTsNCj4gKwkJCW1kZWxheSgxNSk7DQo+ ICsJCX0NCj4gKwkJYnJlYWs7DQo+ICsNCj4gKwljYXNlIEJUQkNNX1VBUlRfQUNUSU9OX1NVU1BF TkQ6DQo+ICsJCUJUX0RCRygiYnRiY21fdWFydF9jb250cm9sICVwIC0gc3VzcGVuZCIsIGRldmlj ZV9jb250ZXh0KTsNCj4gKwkJaWYgKHBfYmNtX2RldmljZS0+ZGV2X3dha2VfZ3Bpbykgew0KPiAr CQkJcmVzdW1lX2ZsYWcgPSAhcF9iY21fZGV2aWNlLT5kZXZfd2FrZV9hY3RpdmVfbG93Ow0KPiAr CQkJZ3Bpb2Rfc2V0X3ZhbHVlKHBfYmNtX2RldmljZS0+ZGV2X3dha2VfZ3BpbywNCj4gKwkJCQkJ IXJlc3VtZV9mbGFnKTsNCj4gKwkJCUJUX0RCRygiYnRiY21fdWFydF9jb250cm9sIC0gc3VzcGVu ZCAlZCwgZGVsYXkgMTVtcyIsDQo+ICsJCQkgICAgICAgIXJlc3VtZV9mbGFnKTsNCj4gKwkJCW1k ZWxheSgxNSk7DQo+ICsJCX0NCj4gKwkJYnJlYWs7DQo+ICsNCj4gKwljYXNlIEJUQkNNX1VBUlRf QUNUSU9OX0dFVF9QQVJBTUVURVJTOg0KPiArCQlCVF9EQkcoImJ0YmNtX3VhcnRfY29udHJvbCAl cCAtIGdldCBwYXJzIiwgZGV2aWNlX2NvbnRleHQpOw0KPiArCQlpZiAoKHBfZGF0YSA9PSBOVUxM KSB8fA0KPiArCQkJKCpwX3NpemUgPCBzaXplb2Yoc3RydWN0IGJ0YmNtX3VhcnRfcGFyYW1ldGVy cykpKSB7DQo+ICsJCQlCVF9EQkcoImJ0YmNtX3VhcnRfY29udHJvbCAtIGZhaWxpbmcsIHdyb25n IHBhciBzaXplIik7DQo+ICsJCQlyZXR1cm4gLUUyQklHOw0KPiArCQl9DQo+ICsNCj4gKwkJbWVt c2V0KHBwLCAwLCBzaXplb2Yoc3RydWN0IGJ0YmNtX3VhcnRfcGFyYW1ldGVycykpOw0KPiArCQlw cC0+aW50ZXJmYWNlX3ZlcnNpb24gPSBCVEJDTV9VQVJUX0lOVEVSRkFDRV9WRVJTSU9OOw0KPiAr CQlwcC0+Y29uZmlndXJlX3NsZWVwID0gcF9iY21fZGV2aWNlLT5jb25maWd1cmVfc2xlZXA7DQo+ ICsJCXBwLT5tYW51YWxfZmMgPSBwX2JjbV9kZXZpY2UtPm1hbnVhbF9mYzsNCj4gKwkJcHAtPmRl dl93YWtlX2FjdGl2ZV9sb3cgPSBwX2JjbV9kZXZpY2UtPmRldl93YWtlX2FjdGl2ZV9sb3c7DQo+ ICsJCXBwLT5idF93YWtlX2FjdGl2ZV9sb3cgPSBwX2JjbV9kZXZpY2UtPmJ0X3dha2VfYWN0aXZl X2xvdzsNCj4gKwkJcHAtPmlkbGVfdGltZW91dF9pbl9zZWNzID0gaWRsZVRpbWVvdXQ7DQo+ICsJ CXBwLT5iYXVkX3JhdGVfYmVmb3JlX2NvbmZpZ19kb3dubG9hZCA9DQo+ICsJCQlwX2JjbV9kZXZp Y2UtPmJhdWRfcmF0ZV9iZWZvcmVfY29uZmlnX2Rvd25sb2FkOw0KPiArCQlwcC0+Y29uZmlndXJl X2F1ZGlvID0gcF9iY21fZGV2aWNlLT5jb25maWd1cmVfYXVkaW87DQo+ICsJCXBwLT5QQ01DbG9j a01vZGUgPSBwX2JjbV9kZXZpY2UtPlBDTUNsb2NrTW9kZTsNCj4gKwkJcHAtPlBDTUZpbGxNZXRo b2QgPSBwX2JjbV9kZXZpY2UtPlBDTUZpbGxNZXRob2Q7DQo+ICsJCXBwLT5QQ01GaWxsTnVtID0g cF9iY21fZGV2aWNlLT5QQ01GaWxsTnVtOw0KPiArCQlwcC0+UENNRmlsbFZhbHVlID0gcF9iY21f ZGV2aWNlLT5QQ01GaWxsVmFsdWU7DQo+ICsJCXBwLT5QQ01JbkNhbGxCaXRjbG9jayA9IHBfYmNt X2RldmljZS0+UENNSW5DYWxsQml0Y2xvY2s7DQo+ICsJCXBwLT5QQ01MU0JGaXJzdCA9IHBfYmNt X2RldmljZS0+UENNTFNCRmlyc3Q7DQo+ICsJCXBwLT5QQ01SaWdodEp1c3RpZnkgPSBwX2JjbV9k ZXZpY2UtPlBDTVJpZ2h0SnVzdGlmeTsNCj4gKwkJcHAtPlBDTVJvdXRpbmcgPSBwX2JjbV9kZXZp Y2UtPlBDTVJvdXRpbmc7DQo+ICsJCXBwLT5QQ01TaG9ydEZyYW1lU3luYyA9IHBfYmNtX2Rldmlj ZS0+UENNU2hvcnRGcmFtZVN5bmM7DQo+ICsJCXBwLT5QQ01TeW5jTW9kZSA9IHBfYmNtX2Rldmlj ZS0+UENNU3luY01vZGU7DQo+ICsJCSpwX3NpemUgPSBzaXplb2Yoc3RydWN0IGJ0YmNtX3VhcnRf cGFyYW1ldGVycyk7DQo+ICsJCWJyZWFrOw0KPiArDQo+ICsJZGVmYXVsdDoNCj4gKwkJQlRfREJH KCJidGJjbV91YXJ0X2NvbnRyb2wgJXAgdW5rbm93biBhY3QgJWQiLA0KPiArCQkgICAgICAgZGV2 aWNlX2NvbnRleHQsIGFjdGlvbik7DQo+ICsJCXJldCA9IC1FSU5WQUw7DQo+ICsJCWJyZWFrOw0K PiArCX0NCj4gKw0KPiArCXJldHVybiByZXQ7DQo+ICt9DQo+ICtFWFBPUlRfU1lNQk9MKGJ0YmNt X3VhcnRfY29udHJvbCk7DQo+ICsNCj4gKy8qIFBsYXRmb3JtIHN1c3AgYW5kIHJlc3VtZSBjYWxs YmFja3MgKi8NCj4gK3N0YXRpYyBTSU1QTEVfREVWX1BNX09QUyhiY21fYnRfdWFydF9wbV9vcHMs DQo+ICsJYmNtX2J0X3VhcnRfc3VzcGVuZCwgYmNtX2J0X3VhcnRfcmVzdW1lKTsNCj4gKw0KPiAr LyogRHJpdmVyIG1hdGNoIHRhYmxlICovDQo+ICtzdGF0aWMgY29uc3Qgc3RydWN0IG9mX2Rldmlj ZV9pZCBiY21fYnRfdWFydF9tYXRjaF90YWJsZVtdID0gew0KDQpObyBuZWVkIHRvIGNhbGwgaXQg bWF0Y2hfdGFibGUuIEp1c3QgdGFibGUgYXMgc3VmZmljZSBpcyBmaW5lLg0KDQpJRjogQ2hhbmdl ZC4NCg0KPiArCXsgLmNvbXBhdGlibGUgPSAiYnJjbSxicmNtLWJ0LXVhcnQiIH0sDQo+ICsJe30N Cj4gK307DQo+ICsNCj4gKy8qIERyaXZlciBjb25maWd1cmF0aW9uICovDQo+ICtzdGF0aWMgc3Ry dWN0IHBsYXRmb3JtX2RyaXZlciBiY21fYnRfdWFydF9wbGF0Zm9ybV9kcml2ZXIgPSB7DQoNCk5v IG5lZWQgdG8gY2FsbCBpdCBwbGF0Zm9ybV9kcml2ZXIuIEp1c3QgZHJpdmVyIGFzIHN1ZmZpeCBp cyBmaW5lLg0KDQpJRjogQ2hhbmdlZC4NCg0KPiArCS5wcm9iZSA9IGJjbV9idF91YXJ0X3Byb2Jl LA0KPiArCS5yZW1vdmUgPSBiY21fYnRfdWFydF9yZW1vdmUsDQo+ICsJLmRyaXZlciA9IHsNCj4g KwkJLm5hbWUgPSAiYnJjbV9idF91YXJ0IiwNCj4gKwkJLm9mX21hdGNoX3RhYmxlID0gb2ZfbWF0 Y2hfcHRyKGJjbV9idF91YXJ0X21hdGNoX3RhYmxlKSwNCj4gKwkJLm93bmVyID0gVEhJU19NT0RV TEUsDQo+ICsJCS5wbSA9ICZiY21fYnRfdWFydF9wbV9vcHMsDQo+ICsJfSwNCj4gK307DQo+ICsN Cj4gK21vZHVsZV9wbGF0Zm9ybV9kcml2ZXIoYmNtX2J0X3VhcnRfcGxhdGZvcm1fZHJpdmVyKTsN Cj4gKw0KPiArTU9EVUxFX0FVVEhPUigiSWx5YSBGYWVuc29uIik7DQo+ICtNT0RVTEVfREVTQ1JJ UFRJT04oIkJyb2FkY29tIEJsdWV0b290aCBVQVJUIERyaXZlciIpOw0KPiArTU9EVUxFX0xJQ0VO U0UoIkR1YWwgQlNEL0dQTOKAnSk7DQoNCkNvcHlyaWdodCBoZWFkZXIgc2F5cyBHUEx2Mi4gU28g bGV0cyByZWZsZWN0IHRoZSBjb3JyZWN0IGxpY2Vuc2UgaGVyZS4NCg0KSUY6IFRoZSBjb3B5cmln aHQgaGVhZGVyIHVwZGF0ZWQgdG8gbWF0Y2ggdGhlIGR1YWwgQlNEL0dQTCBsaWNlbnNlLg0KDQo+ ICsNCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvYmx1ZXRvb3RoL2J0YmNtX3VhcnQuaCBiL2RyaXZl cnMvYmx1ZXRvb3RoL2J0YmNtX3VhcnQuaA0KPiBuZXcgZmlsZSBtb2RlIDEwMDY0NA0KPiBpbmRl eCAwMDAwMDAwLi41ODAxNzUzDQo+IC0tLSAvZGV2L251bGwNCj4gKysrIGIvZHJpdmVycy9ibHVl dG9vdGgvYnRiY21fdWFydC5oDQo+IEBAIC0wLDAgKzEsOTAgQEANCj4gKy8qDQo+ICsgKg0KPiAr ICogIEJsdWV0b290aCBCQ00gVUFSVCBEcml2ZXIgSGVhZGVyDQo+ICsgKg0KPiArICogIENvcHly aWdodCAoYykgMjAxNSBCcm9hZGNvbSBDb3Jwb3JhdGlvbg0KPiArICoNCj4gKyAqICBUaGlzIHBy b2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1v ZGlmeQ0KPiArICogIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGlj IExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5DQo+ICsgKiAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRh dGlvbjsgZWl0aGVyIHZlcnNpb24gMiBvZiB0aGUgTGljZW5zZSwgb3INCj4gKyAqICAoYXQgeW91 ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLg0KPiArICoNCj4gKyAqICBUaGlzIHByb2dyYW0g aXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwNCj4gKyAq ICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJy YW50eSBvZg0KPiArICogIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VM QVIgUFVSUE9TRS4gIFNlZSB0aGUNCj4gKyAqICBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBm b3IgbW9yZSBkZXRhaWxzLg0KPiArICoNCj4gKyAqLw0KPiArI2lmbmRlZiBCVEJDTV9VQVJUX0gN Cj4gKyNkZWZpbmUgQlRCQ01fVUFSVF9IDQo+ICsNCj4gKy8qIENoYW5nZSB0aGUgdmVyc2lvbiBp ZiB5b3UgY2hhbmdlIGFueXRoaW5nIGluIHRoaXMgaGVhZGVyICovDQo+ICsjZGVmaW5lIEJUQkNN X1VBUlRfSU5URVJGQUNFX1ZFUlNJT04gMQ0KDQpJIGRvIG5vdCBzZWUgdGhlIG5lZWQgZm9yIHRo aXMuIFdoeSB3b3VsZCB3ZSBkbyB0aGF0Pw0KDQpJRjogU2luY2UgdGhpcyBpcyB0aGUgaW50ZXIt bW9kdWxlIGludGVyZmFjZSwgbWlzbWF0Y2hlZCBiaW5hcmllcyBtYXkNCnJ1biBvbiBhIHBsYXRm b3JtIHdoZW4gb25lIHNpZGUncyBpbnRlcmZhY2UgaXMgbmV3ZXIgdGhhbiB0aGUgb3RoZXIuDQpU aGUgZHJpdmVyIGNoZWNrcyB0aGF0IHRoZSBjYWxsZXIgcnVucyB0aGUgcmlnaHQgaW50ZXJmYWNl IHZlcnNpb24gYmVmb3JlDQphbGxvd2luZyB0aGUgY2FsbGVyJ3MgcmVxdWVzdHMuDQoNCj4gKw0K PiArLyogQ2FsbGJhY2tzIGZyb20gdGhlIGRyaXZlciBpbnRvIHRoZSBwcm90b2NvbCAqLw0KPiAr dHlwZWRlZiB2b2lkICgqcF9zdXNwZW5kX2NhbGxiYWNrKSh2b2lkICpjb250ZXh0KTsNCj4gK3R5 cGVkZWYgdm9pZCAoKnBfcmVzdW1lX2NhbGxiYWNrKSh2b2lkICpjb250ZXh0KTsNCj4gK3R5cGVk ZWYgdm9pZCAoKnBfd2FrZXVwX2NhbGxiYWNrKSh2b2lkICpjb250ZXh0KTsNCg0KRXh0cmEgZW1w dHkgbGluZSBoZXJlLg0KDQpJRjogIEV4dHJhIGxpbmUgcmVtb3ZlZC4NCg0KPiArc3RydWN0IGJ0 YmNtX3VhcnRfY2FsbGJhY2tzIHsNCj4gKwlpbnQgaW50ZXJmYWNlX3ZlcnNpb247IC8qIGludGVy ZmFjZSAjIGNvbXBpbGVkIGFnYWluc3QgKi8NCj4gKwl2b2lkICpjb250ZXh0OyAgICAgICAgIC8q IHByb3RvY29sIGluc3RhbmNlIGNvbnRleHQgKi8NCj4gKwljaGFyIG5hbWVbNjRdOyAgICAgICAg IC8qIHByb3RvY29sIHR0eSBkZXZpY2UsIGZvciBleGFtcGxlLCB0dHlTMCAqLw0KDQpXaHkgd291 bGQgd2UgcmVjb3JkIHRoZSBUVFkgbmFtZS4gSXQgbWlnaHQgYWN0dWFsbHkgY2hhbmdlLg0KDQpJ RjogWW91J3ZlIHByZXZpb3VzbHkgYXNrZWQgdG8gc3VwcG9ydCBtdWx0aXBsZSBCVCBVQVJUIGRl dmljZSBpbnN0YW5jZXMuDQpCb3RoIEJsdWVaIHByb3RvY29sIGFuZCB0aGUgZGV2aWNlIHVzZSB0 aGUgdHR5IG5hbWUgdG8gYmluZCB0aGUgcmlnaHQNCnByb3RvY29sIGluc3RhbmNlIGludG8gdGhl IHJpZ2h0IGRldmljZSBpbnN0YW5jZS4gSSdsbCBnbGFkbHkgcmVtb3ZlIHRoZQ0KdHR5IG5hbWUg aWYgbXVsdGlwbGUgQlQgVUFSVCBzdXBwb3J0IGlzIG5vdCBuZWVkZWQuDQoNCj4gKw0KPiArCS8q IENhbGxiYWNrcyBwcm9wZXIgKi8NCj4gKwlwX3N1c3BlbmRfY2FsbGJhY2sgcF9zdXNwZW5kOw0K PiArCXBfcmVzdW1lX2NhbGxiYWNrIHBfcmVzdW1lOw0KPiArCXBfd2FrZXVwX2NhbGxiYWNrIHBf d2FrZXVwOw0KDQpJIGRvIG5vdCBnZXQgdGhpcyBwXyBwcmVmaXggbmFtaW5nLiBXaGF0IGlzIHRo YXQgZm9yPw0KDQpJRjogVGhlc2UgYXJlIHBvaW50ZXJzIHRvIHRoZSBwcm90b2NvbCBmdW5jdGlv bnMgY2FsbGVkIGJ5IHRoZSBkcml2ZXIgdXBvbg0KcGxhdGZvcm0gc3VzcGVuZC9yZXN1bWUgYW5k IGRldmljZSB3YWtldXAgaW50ZXJydXB0Lg0KDQo+ICt9Ow0KPiArDQo+ICsvKiBEcml2ZXIgcGFy YW1ldGVycyByZXRyaWV2ZWQgZnJvbSB0aGUgRFQgb3IgQUNQSSAqLw0KPiArc3RydWN0IGJ0YmNt X3VhcnRfcGFyYW1ldGVycyB7DQo+ICsJaW50IGludGVyZmFjZV92ZXJzaW9uOyAvKiBpbnRlcmZh Y2UgIyBjb21waWxlZCBhZ2FpbnN0ICovDQo+ICsNCj4gKwkvKiBQYXJhbWV0ZXJzIHByb3BlciAq Lw0KDQpXaGF0IGlzIGEg4oCccHJvcGVy4oCdPw0KDQpJRjogQ2hhbmdlZCB0aGUgY29tbWVudCB0 byByZWFkICJQYXJhbWV0ZXJzIHRoZW1zZWx2ZXMiLiBUaGF0IHdhcw0KSW4gcmVmZXJlbmNlIHRv IHRoZSBmaXJzdCBtZW1iZXIgb2YgdGhhdCBzdHJ1Y3R1cmUgd2hpY2ggd2FzIG5vdCBhDQpQYXJh bWV0ZXIuDQoNCj4gKwlpbnQgY29uZmlndXJlX3NsZWVwOw0KPiArCWludCBtYW51YWxfZmM7DQo+ ICsJaW50IGRldl93YWtlX2FjdGl2ZV9sb3c7DQo+ICsJaW50IGJ0X3dha2VfYWN0aXZlX2xvdzsN Cj4gKwlpbnQgaWRsZV90aW1lb3V0X2luX3NlY3M7DQo+ICsJaW50IGJhdWRfcmF0ZV9iZWZvcmVf Y29uZmlnX2Rvd25sb2FkOw0KPiArCWludCBjb25maWd1cmVfYXVkaW87DQo+ICsJaW50IFBDTUNs b2NrTW9kZTsNCj4gKwlpbnQgUENNRmlsbE1ldGhvZDsNCj4gKwlpbnQgUENNRmlsbE51bTsNCj4g KwlpbnQgUENNRmlsbFZhbHVlOw0KPiArCWludCBQQ01JbkNhbGxCaXRjbG9jazsNCj4gKwlpbnQg UENNTFNCRmlyc3Q7DQo+ICsJaW50IFBDTVJpZ2h0SnVzdGlmeTsNCj4gKwlpbnQgUENNUm91dGlu ZzsNCj4gKwlpbnQgUENNU2hvcnRGcmFtZVN5bmM7DQo+ICsJaW50IFBDTVN5bmNNb2RlOw0KPiAr fTsNCj4gKw0KPiArLyoNCj4gKyAqIEFjdGlvbnMgb24gdGhlIEJUQkNNX1VBUlQgZHJpdmVyDQo+ ICsgKi8NCj4gKw0KPiArLyogQ29uZmlndXJlIHByb3RvY29sIGNhbGxiYWNrcyAqLw0KPiArI2Rl ZmluZSBCVEJDTV9VQVJUX0FDVElPTl9DT05GSUdVUkVfQ0FMTEJBQ0tTIDANCj4gKw0KPiArLyog UmV0cmlldmUgQlQgZGV2aWNlIHBhcmFtZXRlcnMgKi8NCj4gKyNkZWZpbmUgQlRCQ01fVUFSVF9B Q1RJT05fR0VUX1BBUkFNRVRFUlMgICAgICAxDQo+ICsNCj4gKy8qIFJlc3VtZSB0aGUgQlQgZGV2 aWNlIHZpYSBHUElPICovDQo+ICsjZGVmaW5lIEJUQkNNX1VBUlRfQUNUSU9OX1JFU1VNRSAgICAg ICAgICAgICAgMg0KPiArDQo+ICsvKiBTdXNwZW5kIHRoZSBCVCBkZXZpY2UgdmlhIEdQSU8gKi8N Cj4gKyNkZWZpbmUgQlRCQ01fVUFSVF9BQ1RJT05fU1VTUEVORCAgICAgICAgICAgICAzDQo+ICsN Cj4gKy8qIFBvd2VyIHRoZSBCVCBkZXZpY2Ugb2ZmIHZpYSBHUElPICovDQo+ICsjZGVmaW5lIEJU QkNNX1VBUlRfQUNUSU9OX1BPV0VSX09GRiAgICAgICAgICAgNA0KPiArDQo+ICsvKiBQb3dlciB0 aGUgQlQgZGV2aWNlIG9uIHZpYSBHUElPICovDQo+ICsjZGVmaW5lIEJUQkNNX1VBUlRfQUNUSU9O X1BPV0VSX09OICAgICAgICAgICAgNQ0KPiArDQo+ICsvKiBFeGVjdXRlIGFuIGFjdGlvbiBvbiB0 aGUgQlQgZGV2aWNlICovDQo+ICtleHRlcm4gaW50IGJ0YmNtX3VhcnRfY29udHJvbChpbnQgYWN0 aW9uLCB2b2lkICpkZXZpY2VfY29udGV4dCwNCj4gKwkJCSAgICAgIHZvaWQgKnBfZGF0YSwgdW5z aWduZWQgbG9uZyAqcF9zaXplKTsNCg0KQ2FuIHRoZXNlIGJlIDYgaW5kaXZpZHVhbCBmdW5jdGlv biBpbnN0ZWFkIG9mIHRyeWluZyB0byBmaWRkbGUgdGhpcyB0aHJvdWdoIGEgc2luZ2xlIG9uZT8N Cg0KSUY6IFRoZXkgY291bGQgYmUuIEhvd2V2ZXIsIHRoaXMgaXMgYSBkcml2ZXIgc28gdGhlIGNs ZWFuZXN0IGludGVyZmFjZSB0byBpdCB3b3VsZA0KYXJndWFibHkgYmUgdGhyb3VnaCB0aGUgaW9j dGxzLiBJdCBtYXkgc3RpbGwgYmVjb21lIGFuIGlvY3RsIGF0IHNvbWUgcG9pbnQgYWxsb3dpbmcN CmZvciBib3RoIHVzZXIgYW5kIGtlcm5lbCBtb2RlIGFjY2Vzcy4gVGhpcyBmdW5jdGlvbiB3b3Vs ZCB0aGVuIGJlIGVhc2lseSB1cGRhdGVkDQp0byBzZXJ2ZSBpb2N0bHMuDQoNCj4gKw0KPiArI2Vu ZGlmDQo+ICsNCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvYmx1ZXRvb3RoL2hjaV9iY20uYyBiL2Ry aXZlcnMvYmx1ZXRvb3RoL2hjaV9iY20uYw0KPiBpbmRleCAxZWMwYjRhLi5lNzBmODliIDEwMDY0 NA0KPiAtLS0gYS9kcml2ZXJzL2JsdWV0b290aC9oY2lfYmNtLmMNCj4gKysrIGIvZHJpdmVycy9i bHVldG9vdGgvaGNpX2JjbS5jDQo+IEBAIC0xLDggKzEsMTMgQEANCj4gLyoNCj4gICoNCj4gLSAq ICBCbHVldG9vdGggSENJIFVBUlQgZHJpdmVyIGZvciBCcm9hZGNvbSBkZXZpY2VzDQo+ICsgKiAg Qmx1ZXRvb3RoIFVBUlQgSDQgcHJvdG9jb2wgZm9yIEJyb2FkY29tIGRldmljZXMNCj4gICoNCj4g LSAqICBDb3B5cmlnaHQgKEMpIDIwMTUgIEludGVsIENvcnBvcmF0aW9uDQo+ICsgKiAgQ29weXJp Z2h0IChjKSAyMDE1IEludGVsIENvcnBvcmF0aW9uDQo+ICsgKiAgQ29weXJpZ2h0IChjKSAyMDE1 IEJyb2FkY29tIENvcnBvcmF0aW9uDQo+ICsgKg0KPiArICogIEFja25vd2xlZGdlbWVudHM6DQo+ ICsgKiAgVGhpcyBmaWxlIGhhcyBiZWVuIGJhc2VkIG9uIGhjaV9oNC5jIG9yaWdpbmFsbHkgZGV2 ZWxvcGVkDQo+ICsgKiAgYnkgTWF4aW0gS3Jhc255YW5za3kgYW5kIE1hcmNlbCBIb2x0bWFubi4N Cj4gICoNCj4gICoNCj4gICogIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2Fu IHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5DQo+IEBAIC0xNSwxMzkgKzIwLDg0MiBAQA0K PiAgKiAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NF LiAgU2VlIHRoZQ0KPiAgKiAgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0 YWlscy4NCj4gICoNCj4gLSAqICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRo ZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZQ0KPiAtICogIGFsb25nIHdpdGggdGhpcyBwcm9n cmFtOyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlDQo+IC0gKiAgRm91bmRhdGlv biwgSW5jLiwgNTkgVGVtcGxlIFBsYWNlLCBTdWl0ZSAzMzAsIEJvc3RvbiwgTUEgIDAyMTExLTEz MDcgIFVTQQ0KPiAtICoNCj4gICovDQo+IA0KPiArI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPg0K PiArDQo+ICNpbmNsdWRlIDxsaW51eC9rZXJuZWwuaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9pbml0 Lmg+DQo+ICsjaW5jbHVkZSA8bGludXgvdHlwZXMuaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9mY250 bC5oPg0KPiArI2luY2x1ZGUgPGxpbnV4L2ludGVycnVwdC5oPg0KPiArI2luY2x1ZGUgPGxpbnV4 L3B0cmFjZS5oPg0KPiArI2luY2x1ZGUgPGxpbnV4L3BvbGwuaD4NCj4gKw0KPiArI2luY2x1ZGUg PGxpbnV4L3NsYWIuaD4NCj4gKyNpbmNsdWRlIDxsaW51eC90dHkuaD4NCj4gI2luY2x1ZGUgPGxp bnV4L2Vycm5vLmg+DQo+ICsjaW5jbHVkZSA8bGludXgvc3RyaW5nLmg+DQo+ICsjaW5jbHVkZSA8 bGludXgvc2lnbmFsLmg+DQo+ICsjaW5jbHVkZSA8bGludXgvaW9jdGwuaD4NCj4gI2luY2x1ZGUg PGxpbnV4L3NrYnVmZi5oPg0KPiANCj4gI2luY2x1ZGUgPG5ldC9ibHVldG9vdGgvYmx1ZXRvb3Ro Lmg+DQo+ICNpbmNsdWRlIDxuZXQvYmx1ZXRvb3RoL2hjaV9jb3JlLmg+DQo+IA0KPiAtI2luY2x1 ZGUgImJ0YmNtLmgiDQo+ICsjaW5jbHVkZSA8bGludXgvZ3Bpby9jb25zdW1lci5oPg0KPiArI2lu Y2x1ZGUgPGxpbnV4L29mX2dwaW8uaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9vZl9wbGF0Zm9ybS5o Pg0KPiArDQo+ICNpbmNsdWRlICJoY2lfdWFydC5oIg0KPiArI2luY2x1ZGUgImJ0YmNtLmgiDQo+ ICsjaW5jbHVkZSAiYnRiY21fdWFydC5oIg0KPiANCj4gLXN0cnVjdCBiY21fZGF0YSB7DQo+IC0J c3RydWN0IHNrX2J1ZmYgKnJ4X3NrYjsNCj4gKy8qIFByb3RvY29sIGNvbnRleHQgKi8NCj4gK3N0 cnVjdCBiY21faDRfc3RydWN0IHsNCg0KDQpJIGFtIG1pc3NpbmcgdGhlIHJlYXNvbiBmb3IgdGhp cyByZW5hbWluZy4NCg0KSUY6IEkndmUgYWN0dWFsbHkgc3RhcnRlZCB0aGlzIGRldmVsb3BtZW50 IGJlZm9yZSB5b3UndmUgY3JlYXRlZCB0aGlzIGZpbGUuIEhhdmUgbm93IHJlc3RvcmVkIHlvdXIg bmFtZS4NCg0KPiAJc3RydWN0IHNrX2J1ZmZfaGVhZCB0eHE7DQo+ICsJc3RydWN0IGhjaV91YXJ0 ICpodTsNCj4gKw0KPiArCWJvb2wgaXNfc3VzcGVuZGVkOyAvKiBzdXNwZW5kL3Jlc3VtZSBmbGFn ICovDQo+ICsNCj4gKwkvKiBSZWN2IGRhdGEgcGFyc2luZyBpcyBub3QgdXNlZCBpbiBub3JtYWwg b3BlcmF0aW9uICovDQo+ICsJYm9vbCBwYXJzZV9yZWN2Ow0KPiArCS8qIGJ1ZmZlciBpbmNsdWRl cyB0aGUgdHlwZSAqLw0KPiArCXVuc2lnbmVkIGNoYXIgcmVhc3NlbWJseVsxICsgSENJX01BWF9G UkFNRV9TSVpFXTsNCj4gKwl1bnNpZ25lZCBpbnQgcnNpemU7DQo+ICsJdTE2IHJleHBlY3RlZDsN Cg0KU28gdGhlIG5pY2UgSDo0IFJYIGhlbHBlciBmdW5jdGlvbiB0aGF0IEkgYnVpbGQgaXMgbm90 IGdvb2QgZW5vdWdoPyBSZWFsbHk/IFlvdSBuZWVkIHRvIHJlYWxseSBtYWtlIGEgZ29vZCBjYXNl IGZvciBub3QgdXNpbmcgaXQuDQoNCklGOiBSZW1vdmVkIGl0Lg0KDQo+ICsNCj4gKwlzdHJ1Y3Qg dGltZXJfbGlzdCB0aW1lcjsgLyogaWRsZSB0aW1lciAqLw0KPiArDQo+ICsJc3RydWN0IGJ0YmNt X3VhcnRfcGFyYW1ldGVycyBwYXJzOyAvKiBkZXZpY2UgcGFyYW1ldGVycyAqLw0KPiArCXZvaWQg KmRldmljZV9jb250ZXh0OyAvKiBBQ1BJL0RUIGRldmljZSBjb250ZXh0ICovDQo+IH07DQo+IA0K PiAtc3RhdGljIGludCBiY21fb3BlbihzdHJ1Y3QgaGNpX3VhcnQgKmh1KQ0KPiArLyogU3RhdGlj IGZ1bmN0aW9uIHByb3RvdHlwZXMgZm9yIGZvcndhcmQgcmVmZXJlbmNlcyAqLw0KPiArc3RhdGlj IHZvaWQgc3VzcGVuZF9ub3RpZmljYXRpb24odm9pZCAqY29udGV4dCk7DQo+ICtzdGF0aWMgdm9p ZCByZXN1bWVfbm90aWZpY2F0aW9uKHZvaWQgKmNvbnRleHQpOw0KPiArc3RhdGljIHZvaWQgd2Fr ZXVwX25vdGlmaWNhdGlvbih2b2lkICpjb250ZXh0KTsNCj4gK3N0YXRpYyB2b2lkIGJjbV9lbnN1 cmVfd2FrZXVwKHN0cnVjdCBoY2lfdWFydCAqaHUpOw0KDQpJIGRpc2xpa2UgZm9yd2FyZCBkZWNs YXJhdGlvbi4gSWYgdGhleSBjYW4gYmUgYXZvaWQsIGxldHMgYXZvaWQgdGhlbSBhbmQgdGhlIGZ1 bmN0aW9uIGludG8gdGhlIGJldHRlciBsb2NhdGlvbi4NCg0KSUY6IEZ1bmN0aW9ucyBtb3ZlZC4N Cg0KPiArDQo+ICsvKiBTdXNwZW5kL3Jlc3VtZSBzeW5jaHJvbml6YXRpb24gbXV0ZXggKi8NCj4g K3N0YXRpYyBERUZJTkVfTVVURVgocGxvY2spOw0KPiArDQo+ICsvKg0KPiArICogSWRsZSB0aW1l ciBjYWxsYmFjaw0KPiArICovDQo+ICtzdGF0aWMgdm9pZCBiY21faWRsZV90aW1lb3V0KHVuc2ln bmVkIGxvbmcgYXJnKQ0KPiB7DQo+IC0Jc3RydWN0IGJjbV9kYXRhICpiY207DQo+ICsJc3RydWN0 IGhjaV91YXJ0ICpodSA9IChzdHJ1Y3QgaGNpX3VhcnQgKilhcmc7DQo+ICsJc3RydWN0IGJjbV9o NF9zdHJ1Y3QgKmg0ID0gaHUtPnByaXY7DQo+ICsJaW50IHN0YXR1czsNCj4gDQo+IC0JQlRfREJH KCJodSAlcCIsIGh1KTsNCj4gKwlCVF9EQkcoImJjbV9pZGxlX3RpbWVvdXQgaHUgJXAiLCBodSk7 DQo+ICsNCj4gKwkvKiBTdXNwZW5kL3Jlc3VtZSBvcGVyYXRpb25zIGFyZSBzZXJpYWxpemVkICov DQo+ICsJbXV0ZXhfbG9jaygmcGxvY2spOw0KPiArDQo+ICsJaWYgKCFoNC0+aXNfc3VzcGVuZGVk KSB7DQo+ICsJCS8qIEZsb3cgY29udHJvbCB0aGUgcG9ydCBpZiBjb25maWd1cmVkICovDQo+ICsJ CXN1c3BlbmRfbm90aWZpY2F0aW9uKGh1KTsNCj4gKw0KPiArCQkvKiBTdXNwZW5kIHRoZSBkZXZp Y2UgKi8NCj4gKwkJc3RhdHVzID0gYnRiY21fdWFydF9jb250cm9sKEJUQkNNX1VBUlRfQUNUSU9O X1NVU1BFTkQsDQo+ICsJCQkJCSAgICBoNC0+ZGV2aWNlX2NvbnRleHQsIE5VTEwsIE5VTEwpOw0K PiArCQlpZiAoc3RhdHVzKQ0KPiArCQkJQlRfREJHKCJiY21faWRsZV90aW1lb3V0IGZhaWxlZCB0 byBzdXNwZW5kIGRldmljZSAlZCIsDQo+ICsJCQkgICAgICAgc3RhdHVzKTsNCj4gKwl9DQo+IA0K PiAtCWJjbSA9IGt6YWxsb2Moc2l6ZW9mKCpiY20pLCBHRlBfS0VSTkVMKTsNCj4gLQlpZiAoIWJj bSkNCj4gKwltdXRleF91bmxvY2soJnBsb2NrKTsNCj4gK30NCj4gKw0KPiArLyoNCj4gKyAqIElu aXRpYWxpemUgcHJvdG9jb2wNCj4gKyAqLw0KPiArc3RhdGljIGludCBiY21faDRfb3BlbihzdHJ1 Y3QgaGNpX3VhcnQgKmh1KQ0KPiArew0KPiArCXN0cnVjdCBidGJjbV91YXJ0X2NhbGxiYWNrcyBj YWxsYmFja3M7DQo+ICsJdW5zaWduZWQgbG9uZyBjYWxsYmFja3Nfc2l6ZSA9IHNpemVvZihjYWxs YmFja3MpOw0KPiArCWludCBzdGF0dXM7DQo+ICsJc3RydWN0IGJjbV9oNF9zdHJ1Y3QgKmg0Ow0K PiArCXN0cnVjdCB0dHlfc3RydWN0ICp0dHkgPSBodS0+dHR5Ow0KPiArDQo+ICsJQlRfREJHKCJi Y21faDRfb3BlbiBodSAlcCIsIGh1KTsNCj4gKw0KPiArCWg0ID0ga3phbGxvYyhzaXplb2YoKmg0 KSwgR0ZQX0tFUk5FTCk7DQo+ICsJaWYgKCFoNCkNCj4gCQlyZXR1cm4gLUVOT01FTTsNCj4gDQo+ IC0Jc2tiX3F1ZXVlX2hlYWRfaW5pdCgmYmNtLT50eHEpOw0KPiArCXNrYl9xdWV1ZV9oZWFkX2lu aXQoJmg0LT50eHEpOw0KPiArCWh1LT5wcml2ID0gaDQ7DQo+ICsJaDQtPmh1ID0gaHU7DQo+ICsJ aDQtPmlzX3N1c3BlbmRlZCA9IGZhbHNlOw0KPiArCWg0LT5wYXJzZV9yZWN2ID0gZmFsc2U7DQo+ ICsJaDQtPnJzaXplID0gMDsNCj4gKw0KPiArCS8qIENvbmZpZ3VyZSBjYWxsYmFja3Mgb24gdGhl IGRyaXZlciAqLw0KPiArCWNhbGxiYWNrcy5pbnRlcmZhY2VfdmVyc2lvbiA9IEJUQkNNX1VBUlRf SU5URVJGQUNFX1ZFUlNJT047DQo+ICsJY2FsbGJhY2tzLmNvbnRleHQgPSBodTsNCj4gKwlzdHJj cHkoY2FsbGJhY2tzLm5hbWUsIHR0eS0+bmFtZSk7DQo+ICsJY2FsbGJhY2tzLnBfc3VzcGVuZCA9 IHN1c3BlbmRfbm90aWZpY2F0aW9uOw0KPiArCWNhbGxiYWNrcy5wX3Jlc3VtZSA9IHJlc3VtZV9u b3RpZmljYXRpb247DQo+ICsJY2FsbGJhY2tzLnBfd2FrZXVwID0gd2FrZXVwX25vdGlmaWNhdGlv bjsNCj4gKwlzdGF0dXMgPSBidGJjbV91YXJ0X2NvbnRyb2woQlRCQ01fVUFSVF9BQ1RJT05fQ09O RklHVVJFX0NBTExCQUNLUywNCj4gKwkJCQkgICAgTlVMTCwgJmNhbGxiYWNrcywgJmNhbGxiYWNr c19zaXplKTsNCj4gKwlpZiAoc3RhdHVzKSB7DQo+ICsJCUJUX0RCRygiYmNtX2g0X29wZW4gZmFp bGVkIHRvIHNldCBkcml2ZXIgY2FsbGJhY2tzICVkIiwgc3RhdHVzKTsNCj4gKwkJcmV0dXJuIHN0 YXR1czsNCj4gKwl9DQo+ICsJaWYgKGNhbGxiYWNrc19zaXplICE9IHNpemVvZih2b2lkICopKSB7 DQo+ICsJCUJUX0RCRygiYmNtX2g0X29wZW4gZ290IGJhY2sgJWQgYnl0ZXMgZnJvbSBjYWxsYmFj a3M/ISIsDQo+ICsJCSAgICAgICAoaW50KWNhbGxiYWNrc19zaXplKTsNCj4gKwkJcmV0dXJuIC1F TVNHU0laRTsNCj4gKwl9DQo+ICsJbWVtY3B5KCZoNC0+ZGV2aWNlX2NvbnRleHQsICZjYWxsYmFj a3MsIHNpemVvZih2b2lkICopKTsNCj4gKwlCVF9EQkcoImJjbV9oNF9vcGVuIGNhbGxiYWNrcyBj b250ZXh0ICVwIiwgaDQtPmRldmljZV9jb250ZXh0KTsNCj4gKw0KPiArCS8qIFJldHJpZXZlIGRl dmljZSBwYXJhbWV0ZXJzICovDQo+ICsJY2FsbGJhY2tzX3NpemUgPSBzaXplb2YoaDQtPnBhcnMp Ow0KPiArCXN0YXR1cyA9IGJ0YmNtX3VhcnRfY29udHJvbChCVEJDTV9VQVJUX0FDVElPTl9HRVRf UEFSQU1FVEVSUywNCj4gKwkJCQkgICAgaDQtPmRldmljZV9jb250ZXh0LCAmaDQtPnBhcnMsDQo+ ICsJCQkJICAgICZjYWxsYmFja3Nfc2l6ZSk7DQo+ICsJaWYgKHN0YXR1cykgew0KPiArCQlCVF9E QkcoImJjbV9oNF9vcGVuIGZhaWxlZCB0byBnZXQgZGV2IHBhcmFtZXRlcnMgJWQiLCBzdGF0dXMp Ow0KPiArCQlyZXR1cm4gc3RhdHVzOw0KPiArCX0NCj4gKwlCVF9EQkcoIlBhcnMgdmVyICVkIGNz bGVlcCAlZCBkYWxvdyAlZCBiYWxvdyAlZCBpZGxlICVkIiwNCj4gKwkgICAgICAgaDQtPnBhcnMu aW50ZXJmYWNlX3ZlcnNpb24sIGg0LT5wYXJzLmNvbmZpZ3VyZV9zbGVlcCwNCj4gKwkgICAgICAg aDQtPnBhcnMuZGV2X3dha2VfYWN0aXZlX2xvdywgaDQtPnBhcnMuYnRfd2FrZV9hY3RpdmVfbG93 LA0KPiArCSAgICAgICBoNC0+cGFycy5pZGxlX3RpbWVvdXRfaW5fc2Vjcyk7DQo+ICsNCj4gKwkv KiBDeWNsZSBwb3dlciB0byBtYWtlIHN1cmUgdGhlIGRldmljZSBpcyBpbiB0aGUga25vd24gc3Rh dGUgKi8NCj4gKwlzdGF0dXMgPSBidGJjbV91YXJ0X2NvbnRyb2woQlRCQ01fVUFSVF9BQ1RJT05f UE9XRVJfT0ZGLA0KPiArCQkJCSAgICBoNC0+ZGV2aWNlX2NvbnRleHQsIE5VTEwsIE5VTEwpOw0K PiArCWlmIChzdGF0dXMpIHsNCj4gKwkJQlRfREJHKCJiY21faDRfb3BlbiBmYWlsZWQgdG8gcG93 ZXIgb2ZmICVkIiwgc3RhdHVzKTsNCj4gKwl9IGVsc2Ugew0KPiArCQlzdGF0dXMgPSBidGJjbV91 YXJ0X2NvbnRyb2woQlRCQ01fVUFSVF9BQ1RJT05fUE9XRVJfT04sDQo+ICsJCQkJCSAgICBoNC0+ ZGV2aWNlX2NvbnRleHQsIE5VTEwsIE5VTEwpOw0KPiArCQlpZiAoc3RhdHVzKQ0KPiArCQkJQlRf REJHKCJiY21faDRfb3BlbiBmYWlsZWQgdG8gcG93ZXIgb24gJWQiLCBzdGF0dXMpOw0KPiArCX0N Cj4gKw0KPiArCS8qIFN0YXJ0IHRoZSBpZGxlIHRpbWVyICovDQo+ICsJaWYgKGg0LT5wYXJzLmNv bmZpZ3VyZV9zbGVlcCkgew0KPiArCQlzZXR1cF90aW1lcigmaDQtPnRpbWVyLCBiY21faWRsZV90 aW1lb3V0LCAodW5zaWduZWQgbG9uZylodSk7DQo+ICsJCWlmIChoNC0+cGFycy5jb25maWd1cmVf c2xlZXApDQo+ICsJCQltb2RfdGltZXIoJmg0LT50aW1lciwgamlmZmllcyArIG1zZWNzX3RvX2pp ZmZpZXMoDQo+ICsJCQkJICBoNC0+cGFycy5pZGxlX3RpbWVvdXRfaW5fc2VjcyAqIDEwMDApKTsN Cj4gKwl9DQo+ICsNCj4gKwlyZXR1cm4gMDsNCj4gK30NCj4gKw0KPiArLyoNCj4gKyAqIEZsdXNo IHByb3RvY29sIGRhdGENCj4gKyAqLw0KPiArc3RhdGljIGludCBiY21faDRfZmx1c2goc3RydWN0 IGhjaV91YXJ0ICpodSkNCj4gK3sNCj4gKwlzdHJ1Y3QgYmNtX2g0X3N0cnVjdCAqaDQgPSBodS0+ cHJpdjsNCj4gDQo+IC0JaHUtPnByaXYgPSBiY207DQo+ICsJQlRfREJHKCJiY21faDRfZmx1c2gg aHUgJXAiLCBodSk7DQo+ICsNCj4gKwlza2JfcXVldWVfcHVyZ2UoJmg0LT50eHEpOw0KPiAJcmV0 dXJuIDA7DQo+IH0NCj4gDQo+IC1zdGF0aWMgaW50IGJjbV9jbG9zZShzdHJ1Y3QgaGNpX3VhcnQg Kmh1KQ0KPiArLyoNCj4gKyAqIE1ha2Ugc3VyZSB3ZSdyZSBhd2FrZQ0KPiArICogKGNhbGxlZCB3 aGVuIHRoZSByZXN1bWVkIHN0YXRlIGlzIHJlcXVpcmVkKQ0KPiArICovDQo+ICtzdGF0aWMgdm9p ZCBiY21fZW5zdXJlX3dha2V1cChzdHJ1Y3QgaGNpX3VhcnQgKmh1KQ0KPiB7DQo+IC0Jc3RydWN0 IGJjbV9kYXRhICpiY20gPSBodS0+cHJpdjsNCj4gKwlzdHJ1Y3QgYmNtX2g0X3N0cnVjdCAqaDQg PSBodS0+cHJpdjsNCj4gKwlpbnQgc3RhdHVzOw0KPiArDQo+ICsJaWYgKCFoNC0+cGFycy5jb25m aWd1cmVfc2xlZXApDQo+ICsJCXJldHVybjsNCj4gKw0KPiArCS8qIFN1c3BlbmQvcmVzdW1lIG9w ZXJhdGlvbnMgYXJlIHNlcmlhbGl6ZWQgKi8NCj4gKwltdXRleF9sb2NrKCZwbG9jayk7DQo+ICsN Cj4gKwkvKiBOb3RoaW5nIHRvIGRvIGlmIHJlc3VtZWQgYWxyZWFkeSAqLw0KPiArCWlmICghaDQt PmlzX3N1c3BlbmRlZCkgew0KPiArCQltdXRleF91bmxvY2soJnBsb2NrKTsNCj4gDQo+IC0JQlRf REJHKCJodSAlcCIsIGh1KTsNCj4gKwkJLyogSnVzdCByZXNldCB0aGUgdGltZXIgKi8NCj4gKwkJ c3RhdHVzID0gbW9kX3RpbWVyKCZoNC0+dGltZXIsIGppZmZpZXMgKyBtc2Vjc190b19qaWZmaWVz KA0KPiArCQkJCSAgIGg0LT5wYXJzLmlkbGVfdGltZW91dF9pbl9zZWNzICogMTAwMCkpOw0KPiAr CQlyZXR1cm47DQo+ICsJfQ0KDQpVc2luZyBhIHRpbWVyIGlzIHByZXR0eSBkYW5nZXJvdXMuIFdl IGFyZSB0cnlpbmcgdG8gZ2V0IGF3YXkgZnJvbSB0aGVtIGFzIG11Y2ggYXMgcG9zc2libGUgdW5s ZXNzIHdlIHJlYWxseSBuZWVkIHRoZW0uIENhbiB3ZSBqdXN0IHVzZSBhIGRlbGF5ZWQgd29yayBz dHJ1Y3QgaGVyZT8NCg0KSUY6IFRoZSBnb2FsIGhlcmUgaXMgdG8gdHJpZ2dlciBjZXJ0YWluIGFj dGlvbnMgd2hlbiB0aGVyZSBoYXMgYmVlbiB0aGF0IG1hbnkgc2Vjb25kcyB3aXRoIG5vIGFjdGl2 aXR5LiBJIGJlbGlldmUgdGhhdCwgc2hvcnQgb2YgYSBkZWRpY2F0ZWQgdGhyZWFkIG9yIGEgbmV2 ZXIgZW5kaW5nIHdvcmsgcXVldWUsIHRpbWVyIGlzIHRoZSBiZXN0IG1lY2hhbmlzbSB0byBpbXBs ZW1lbnQgdGhhdC4gVGltZXIgaXMgY2xlYXJseSBjaGVhcGVyIHRoYW4gYSB0aHJlYWQuDQoNCj4g Kw0KPiArCS8qIFdha2V1cCB0aGUgZGV2aWNlICovDQo+ICsJc3RhdHVzID0gYnRiY21fdWFydF9j b250cm9sKEJUQkNNX1VBUlRfQUNUSU9OX1JFU1VNRSwNCj4gKwkJCQkgICAgaDQtPmRldmljZV9j b250ZXh0LCBOVUxMLCBOVUxMKTsNCj4gKwlpZiAoc3RhdHVzKQ0KPiArCQlCVF9EQkcoImJjbV9l bnN1cmVfd2FrZXVwIGZhaWxlZCB0byByZXN1bWUgZHJpdmVyICVkIiwgc3RhdHVzKTsNCj4gDQo+ IC0Jc2tiX3F1ZXVlX3B1cmdlKCZiY20tPnR4cSk7DQo+IC0Ja2ZyZWVfc2tiKGJjbS0+cnhfc2ti KTsNCj4gLQlrZnJlZShiY20pOw0KPiArCS8qIFVuZmxvdyBjb250cm9sIHRoZSBwb3J0IGlmIGNv bmZpZ3VyZWQgKi8NCj4gKwlyZXN1bWVfbm90aWZpY2F0aW9uKGh1KTsNCj4gKw0KPiArCW11dGV4 X3VubG9jaygmcGxvY2spOw0KPiArfQ0KPiArDQo+ICsvKg0KPiArICogQ2xvc2UgcHJvdG9jb2wN Cj4gKyAqLw0KPiArc3RhdGljIGludCBiY21faDRfY2xvc2Uoc3RydWN0IGhjaV91YXJ0ICpodSkN Cj4gK3sNCj4gKwlzdHJ1Y3QgYnRiY21fdWFydF9jYWxsYmFja3MgY2FsbGJhY2tzOw0KPiArCXVu c2lnbmVkIGxvbmcgY2FsbGJhY2tzX3NpemUgPSBzaXplb2YoY2FsbGJhY2tzKTsNCj4gKwlzdHJ1 Y3QgYmNtX2g0X3N0cnVjdCAqaDQgPSBodS0+cHJpdjsNCj4gKwlpbnQgc3RhdHVzOw0KPiANCj4g CWh1LT5wcml2ID0gTlVMTDsNCj4gKw0KPiArCUJUX0RCRygiYmNtX2g0X2Nsb3NlIGh1ICVwIiwg aHUpOw0KPiArDQo+ICsJLyogSWYgd2UncmUgYmVpbmcgY2xvc2VkLCB3ZSBtdXN0IHN1c3BlbmQg Ki8NCj4gKwlpZiAoaDQtPnBhcnMuY29uZmlndXJlX3NsZWVwKSB7DQo+ICsJCW11dGV4X2xvY2so JnBsb2NrKTsNCj4gKw0KPiArCQlpZiAoIWg0LT5pc19zdXNwZW5kZWQpIHsNCj4gKwkJCS8qIEZs b3cgY29udHJvbCB0aGUgcG9ydCAqLw0KPiArCQkJc3VzcGVuZF9ub3RpZmljYXRpb24oaHUpOw0K PiArDQo+ICsJCQkvKiBTdXNwZW5kIHRoZSBkZXZpY2UgKi8NCj4gKwkJCXN0YXR1cyA9IGJ0YmNt X3VhcnRfY29udHJvbChCVEJDTV9VQVJUX0FDVElPTl9TVVNQRU5ELA0KPiArCQkJCQkJICAgIGg0 LT5kZXZpY2VfY29udGV4dCwgTlVMTCwNCj4gKwkJCQkJCSAgICBOVUxMKTsNCj4gKwkJCWlmIChz dGF0dXMpIHsNCj4gKwkJCQlCVF9EQkcoImJjbV9oNF9jbG9zZSBzdXNwZW5kIGRyaXZlciBmYWls ICVkIiwNCj4gKwkJCQkgICAgICAgc3RhdHVzKTsNCj4gKwkJCX0NCj4gKwkJfQ0KPiArDQo+ICsJ bXV0ZXhfdW5sb2NrKCZwbG9jayk7DQo+ICsNCj4gKwlkZWxfdGltZXJfc3luYygmaDQtPnRpbWVy KTsNCj4gKwl9DQo+ICsNCj4gKwkvKiBQb3dlciBvZmYgdGhlIGRldmljZSBpZiBwb3NzaWJsZSAq Lw0KPiArCXN0YXR1cyA9IGJ0YmNtX3VhcnRfY29udHJvbChCVEJDTV9VQVJUX0FDVElPTl9QT1dF Ul9PRkYsDQo+ICsJCQkJICAgIGg0LT5kZXZpY2VfY29udGV4dCwgTlVMTCwgTlVMTCk7DQo+ICsJ aWYgKHN0YXR1cykNCj4gKwkJQlRfREJHKCJiY21faDRfY2xvc2UgZmFpbGVkIHRvIHBvd2VyIG9m ZiAlZCIsIHN0YXR1cyk7DQo+ICsNCj4gKwkvKiBkZS1jb25maWd1cmUgY2FsbGJhY2tzIG9uIHRo ZSBkcml2ZXIgKi8NCj4gKwljYWxsYmFja3MuaW50ZXJmYWNlX3ZlcnNpb24gPSBCVEJDTV9VQVJU X0lOVEVSRkFDRV9WRVJTSU9OOw0KPiArCWNhbGxiYWNrcy5jb250ZXh0ID0gaHU7DQo+ICsJY2Fs bGJhY2tzLnBfc3VzcGVuZCA9IE5VTEw7DQo+ICsJY2FsbGJhY2tzLnBfcmVzdW1lID0gTlVMTDsN Cj4gKwljYWxsYmFja3MucF93YWtldXAgPSBOVUxMOw0KPiArCXN0YXR1cyA9IGJ0YmNtX3VhcnRf Y29udHJvbChCVEJDTV9VQVJUX0FDVElPTl9DT05GSUdVUkVfQ0FMTEJBQ0tTLA0KPiArCQkJCSAg ICBoNC0+ZGV2aWNlX2NvbnRleHQsICZjYWxsYmFja3MsDQo+ICsJCQkJICAgICZjYWxsYmFja3Nf c2l6ZSk7DQo+ICsJaWYgKHN0YXR1cykNCj4gKwkJQlRfREJHKCJiY21faDRfY2xvc2UgZmFpbGVk IHRvIHJlc2V0IGRydiBjYWxsYmFja3MgJWQiLCBzdGF0dXMpOw0KPiArCXNrYl9xdWV1ZV9wdXJn ZSgmaDQtPnR4cSk7DQo+ICsNCj4gKwlodS0+cHJpdiA9IE5VTEw7DQo+ICsJa2ZyZWUoaDQpOw0K PiArDQo+IAlyZXR1cm4gMDsNCj4gfQ0KPiANCj4gLXN0YXRpYyBpbnQgYmNtX2ZsdXNoKHN0cnVj dCBoY2lfdWFydCAqaHUpDQo+ICsvKg0KPiArICogRW5xdWV1ZSBmcmFtZSBmb3IgdHJhbnNtaXR0 aW9uIChwYWRkaW5nLCBjcmMsIGV0YykNCj4gKyAqLw0KPiArc3RhdGljIGludCBiY21faDRfZW5x dWV1ZShzdHJ1Y3QgaGNpX3VhcnQgKmh1LCBzdHJ1Y3Qgc2tfYnVmZiAqc2tiKQ0KPiB7DQo+IC0J c3RydWN0IGJjbV9kYXRhICpiY20gPSBodS0+cHJpdjsNCj4gKwlzdHJ1Y3QgYmNtX2g0X3N0cnVj dCAqaDQgPSBodS0+cHJpdjsNCj4gKw0KPiArCUJUX0RCRygiYmNtX2g0X2VucXVldWUgaHUgJXAg c2tiICVwIHR5cGUgJWQgbGVuICVkICgleCAleCAleCkiLA0KPiArCSAgICAgICBodSwgc2tiLCBi dF9jYihza2IpLT5wa3RfdHlwZSwgc2tiLT5sZW4sDQo+ICsJCXNrYi0+ZGF0YVswXSwgc2tiLT5k YXRhWzFdLCBza2ItPmRhdGFbMl0pOw0KPiANCj4gLQlCVF9EQkcoImh1ICVwIiwgaHUpOw0KPiAr CS8qIE1ha2Ugc3VyZSB3ZSdyZSByZXN1bWVkICovDQo+ICsJYmNtX2Vuc3VyZV93YWtldXAoaHUp Ow0KPiANCj4gLQlza2JfcXVldWVfcHVyZ2UoJmJjbS0+dHhxKTsNCj4gKwkvKiBQcmVwZW5kIHNr YiB3aXRoIGZyYW1lIHR5cGUgKi8NCj4gKwltZW1jcHkoc2tiX3B1c2goc2tiLCAxKSwgJmJ0X2Ni KHNrYiktPnBrdF90eXBlLCAxKTsNCj4gKwlza2JfcXVldWVfdGFpbCgmaDQtPnR4cSwgc2tiKTsN Cj4gDQo+IAlyZXR1cm4gMDsNCj4gfQ0KPiANCj4gLXN0YXRpYyBpbnQgYmNtX3NldHVwKHN0cnVj dCBoY2lfdWFydCAqaHUpDQo+ICsvKg0KPiArICogSENJIGV2ZW50IHByb2Nlc3NpbmcgaWYgb3Vy IG93biBwYXJzaW5nIG9mIGV2ZW50cyBpcyByZXF1aXJlZA0KPiArICogTk9URTogcmV0dXJuIDAg aWYgdGhlIGV2ZW50IGlzIG5vdCB0byBiZSBwYXNzZWQgdXAgdG8gQmx1ZVoNCj4gKyAqLw0KPiAr c3RhdGljIGJvb2wgYmNtX3Byb2Nlc3NfaGNpX2V2ZW50KHN0cnVjdCBoY2lfdWFydCAqaHUpDQo+ ICt7DQo+ICsJc3RydWN0IGJjbV9oNF9zdHJ1Y3QgKmg0ID0gaHUtPnByaXY7DQo+ICsJaW50IHN0 YXR1czsNCj4gKwl1bnNpZ25lZCBjaGFyIGV2dF9jb2RlID0gaDQtPnJlYXNzZW1ibHlbMV07DQo+ ICsJdW5zaWduZWQgY2hhciBsZW4gPSBoNC0+cmVhc3NlbWJseVsyXTsNCj4gKw0KPiArCUJUX0RC RygiYmNtX3Byb2Nlc3NfaGNpX2V2ZW50ICUwMnggZXZlbnQgJTAyeCBsZW4gJTAyeCAlMDJ4IiwN Cj4gKwkgICAgICAgaDQtPnJlYXNzZW1ibHlbMF0sIGV2dF9jb2RlLCBsZW4sIGg0LT5yZWFzc2Vt Ymx5WzNdKTsNCj4gKw0KPiArCS8qIHN3aXRjaCAoZXZ0X2NvZGUpIHsgY2FzZSBIQ0lfRVZfQ01E X0NPTVBMRVRFOiBicmVhayB9ICovDQo+ICsNCj4gKwlzdGF0dXMgPSBoY2lfcmVjdl9zdHJlYW1f ZnJhZ21lbnQoaHUtPmhkZXYsIGg0LT5yZWFzc2VtYmx5LCBoNC0+cnNpemUpOw0KPiArCWlmIChz dGF0dXMgPCAwKQ0KPiArCQlCVF9FUlIoImJjbV9wcm9jZXNzX2hjaV9ldmVudCAtIHJlYXNzZW1i bHkgZmFpbGVkICVkIiwgc3RhdHVzKTsNCj4gKwlyZXR1cm4gdHJ1ZTsNCj4gK30NCj4gKw0KPiAr LyoNCj4gKyAqIEFDTCBkYXRhIHByb2Nlc3NpbmcgaWYgb3VyIG93biBwYXJzaW5nIG9mIGRhdGEg aXMgcmVxdWlyZWQNCj4gKyAqIE5PVEU6IHJldHVybiAwIGlmIHRoZSBkYXRhIGlzIG5vdCB0byBi ZSBwYXNzZWQgdXAgdG8gQmx1ZVoNCj4gKyAqLw0KPiArc3RhdGljIGJvb2wgYmNtX3Byb2Nlc3Nf YWNsX2RhdGEoc3RydWN0IGhjaV91YXJ0ICpodSkNCj4gew0KPiAtCUJUX0RCRygiaHUgJXAiLCBo dSk7DQo+ICsJc3RydWN0IGJjbV9oNF9zdHJ1Y3QgKmg0ID0gaHUtPnByaXY7DQo+ICsJaW50IHJl dDsNCj4gDQo+IC0JaHUtPmhkZXYtPnNldF9iZGFkZHIgPSBidGJjbV9zZXRfYmRhZGRyOw0KPiAr CUJUX0RCRygiYmNtX3Byb2Nlc3NfYWNsX2RhdGEgJTAyeCAlMDJ4ICUwMnggJTAyeCAlMDJ4IiwN Cj4gKwkgICAgICAgaDQtPnJlYXNzZW1ibHlbMF0sIGg0LT5yZWFzc2VtYmx5WzFdLCBoNC0+cmVh c3NlbWJseVsyXSwNCj4gKwkgICAgICAgaDQtPnJlYXNzZW1ibHlbM10sIGg0LT5yZWFzc2VtYmx5 WzRdKTsNCj4gDQo+IC0JcmV0dXJuIGJ0YmNtX3NldHVwX3BhdGNocmFtKGh1LT5oZGV2KTsNCj4g KwlyZXQgPSBoY2lfcmVjdl9zdHJlYW1fZnJhZ21lbnQoaHUtPmhkZXYsIGg0LT5yZWFzc2VtYmx5 LCBoNC0+cnNpemUpOw0KPiArCWlmIChyZXQgPCAwKQ0KPiArCQlCVF9FUlIoImJjbV9wcm9jZXNz X2FjbF9kYXRhIC0gRnJhbWUgUmVhc3NlbWJseSBGYWlsZWQiKTsNCj4gKwlyZXR1cm4gdHJ1ZTsN Cj4gfQ0KPiANCj4gLXN0YXRpYyBjb25zdCBzdHJ1Y3QgaDRfcmVjdl9wa3QgYmNtX3JlY3ZfcGt0 c1tdID0gew0KPiAtCXsgSDRfUkVDVl9BQ0wsICAgLnJlY3YgPSBoY2lfcmVjdl9mcmFtZSB9LA0K PiAtCXsgSDRfUkVDVl9TQ08sICAgLnJlY3YgPSBoY2lfcmVjdl9mcmFtZSB9LA0KPiAtCXsgSDRf UkVDVl9FVkVOVCwgLnJlY3YgPSBoY2lfcmVjdl9mcmFtZSB9LA0KPiAtfTsNCj4gKy8qDQo+ICsg KiBGcmFnbWVudCBwYXJzaW5nIGluIHRoZSBhY3RpdmUgZmlsdGVyaW5nIHBoYXNlDQo+ICsgKiAo bm90IGN1cnJlbnRseSBhY3RpdmVseSB1c2VkKQ0KPiArICovDQo+ICtzdGF0aWMgdm9pZCBwYXJz ZV9mcmFnbWVudChzdHJ1Y3QgaGNpX3VhcnQgKmh1LCB1bnNpZ25lZCBjaGFyICpkYXRhLCBpbnQg Y291bnQpDQo+ICt7DQo+ICsJc3RydWN0IGJjbV9oNF9zdHJ1Y3QgKmg0ID0gaHUtPnByaXY7DQo+ ICsNCj4gKwlpZiAoaDQtPnJzaXplKQ0KPiArCQlCVF9EQkcoInBhcnNlX2ZyYWdtZW50IHR5cGUg JXggZXhwZWN0ZWQgJWQiLA0KPiArCQkgICAgICAgaDQtPnJlYXNzZW1ibHlbMF0sIGg0LT5yZXhw ZWN0ZWQpOw0KPiArDQo+ICsJd2hpbGUgKGNvdW50KSB7DQo+ICsJCWlmICghaDQtPnJzaXplKSB7 DQo+ICsJCQkvKiBTdGFydCBvZiB0aGUgZnJhbWUgKi8NCj4gKwkJCWg0LT5yZWFzc2VtYmx5WzBd ID0gKmRhdGErKzsNCj4gKwkJCWg0LT5yc2l6ZSsrOw0KPiArCQkJY291bnQtLTsNCj4gKwkJCWNv bnRpbnVlOw0KPiArCQl9DQo+ICsNCj4gKwkJc3dpdGNoIChoNC0+cmVhc3NlbWJseVswXSkgew0K PiArCQljYXNlIEhDSV9FVkVOVF9QS1Q6DQo+ICsJCWlmIChoNC0+cnNpemUgPT0gMSkgew0KPiAr CQkJLyogZXZlbnQgcHJvcGVyICovDQo+ICsJCQloNC0+cmVhc3NlbWJseVtoNC0+cnNpemUrK10g PSAqZGF0YSsrOw0KPiArCQkJY291bnQtLTsNCj4gKwkJCWNvbnRpbnVlOw0KPiArCQl9DQo+ICsJ CWlmIChoNC0+cnNpemUgPT0gMikgew0KPiArCQkJLyogbGVuZ3RoICovDQo+ICsJCQloNC0+cmV4 cGVjdGVkID0gKmRhdGE7DQo+ICsJCQloNC0+cmVhc3NlbWJseVtoNC0+cnNpemUrK10gPSAqZGF0 YSsrOw0KPiArCQkJY291bnQtLTsNCj4gKwkJCUJUX0RCRygiZXZ0aGRyIGxlbiAlZCwgbGVmdCAl ZCIsIGg0LT5yZXhwZWN0ZWQsIGNvdW50KTsNCj4gKwkJCWNvbnRpbnVlOw0KPiArCQl9DQo+ICsJ CWlmIChjb3VudCA+PSBoNC0+cmV4cGVjdGVkKSB7DQo+ICsJCQltZW1jcHkoJmg0LT5yZWFzc2Vt Ymx5W2g0LT5yc2l6ZV0sIGRhdGEsIGg0LT5yZXhwZWN0ZWQpOw0KPiArCQkJaDQtPnJzaXplICs9 IGg0LT5yZXhwZWN0ZWQ7DQo+ICsJCQlkYXRhICs9IGg0LT5yZXhwZWN0ZWQ7DQo+ICsJCQljb3Vu dCAtPSBoNC0+cmV4cGVjdGVkOw0KPiArCQkJYmNtX3Byb2Nlc3NfaGNpX2V2ZW50KGh1KTsNCj4g KwkJCWg0LT5yc2l6ZSA9IDA7IC8qIHN0YXJ0aW5nIGFuZXcgKi8NCj4gKwkJCWNvbnRpbnVlOw0K PiArCQl9DQo+ICsJCS8qIG9ubHkgcGllY2Ugb2YgdGhlIGV2ZW50IHJlY2VpdmVkICovDQo+ICsJ CW1lbWNweSgmaDQtPnJlYXNzZW1ibHlbaDQtPnJzaXplXSwgZGF0YSwgY291bnQpOw0KPiArCQlo NC0+cnNpemUgKz0gY291bnQ7DQo+ICsJCWRhdGEgKz0gY291bnQ7DQo+ICsJCWg0LT5yZXhwZWN0 ZWQgLT0gY291bnQ7DQo+ICsJCWNvdW50ID0gMDsNCj4gKwkJYnJlYWs7DQo+ICsNCj4gKwkJY2Fz ZSBIQ0lfQUNMREFUQV9QS1Q6DQo+ICsJCWlmICgoaDQtPnJzaXplID09IDEpIHx8IChoNC0+cnNp emUgPT0gMikgfHwgKGg0LT5yc2l6ZSA9PSAzKSkgew0KPiArCQkJLyogaGFuZGxlIGFuZCBmaXJz dCBieXRlIG9mIGxlbmd0aCAqLw0KPiArCQkJaDQtPnJlYXNzZW1ibHlbaDQtPnJzaXplKytdID0g KmRhdGErKzsNCj4gKwkJCWNvdW50LS07DQo+ICsJCQljb250aW51ZTsNCj4gKwkJfQ0KPiArCQlp ZiAoaDQtPnJzaXplID09IDQpIHsNCj4gKwkJCS8qIGxhc3QgYnl0ZSBvZiB0aGUgbGVuZ3RoICov DQo+ICsJCQloNC0+cmVhc3NlbWJseVtoNC0+cnNpemUrK10gPSAqZGF0YSsrOw0KPiArCQkJaDQt PnJleHBlY3RlZCA9IGg0LT5yZWFzc2VtYmx5W2g0LT5yc2l6ZSAtIDJdICsNCj4gKwkJCQkoaDQt PnJlYXNzZW1ibHlbaDQtPnJzaXplIC0gMV0gPDwgOCk7DQo+ICsJCQljb3VudC0tOw0KPiArCQkJ QlRfREJHKCJkYXRoZHIgbGVuICVkLCBsZWZ0ICVkIiwgaDQtPnJleHBlY3RlZCwgY291bnQpOw0K PiArCQkJY29udGludWU7DQo+ICsJCX0NCj4gKwkJaWYgKGNvdW50ID49IGg0LT5yZXhwZWN0ZWQp IHsNCj4gKwkJCW1lbWNweSgmaDQtPnJlYXNzZW1ibHlbaDQtPnJzaXplXSwgZGF0YSwgaDQtPnJl eHBlY3RlZCk7DQo+ICsJCQloNC0+cnNpemUgKz0gaDQtPnJleHBlY3RlZDsNCj4gKwkJCWRhdGEg Kz0gaDQtPnJleHBlY3RlZDsNCj4gKwkJCWNvdW50IC09IGg0LT5yZXhwZWN0ZWQ7DQo+ICsJCQli Y21fcHJvY2Vzc19hY2xfZGF0YShodSk7DQo+ICsJCQloNC0+cnNpemUgPSAwOyAvKiBzdGFydGlu ZyBhbmV3ICovDQo+ICsJCQljb250aW51ZTsNCj4gKwkJfQ0KPiArCQkvKiBvbmx5IHBpZWNlIG9m IGRhdGEgcmVjZWl2ZWQgKi8NCj4gKwkJbWVtY3B5KCZoNC0+cmVhc3NlbWJseVtoNC0+cnNpemVd LCBkYXRhLCBjb3VudCk7DQo+ICsJCWg0LT5yc2l6ZSArPSBjb3VudDsNCj4gKwkJZGF0YSArPSBj b3VudDsNCj4gKwkJaDQtPnJleHBlY3RlZCAtPSBjb3VudDsNCj4gKwkJY291bnQgPSAwOw0KPiAr CQlicmVhazsNCj4gKw0KPiArCQlkZWZhdWx0OiAvKiBOb3RlIHRoYXQgU0NPIG1heSBOT1QgY29t ZSB0aHJvdWdoIHRoZSBVQVJUICovDQoNCllvdSBjYW4gbm90IHJlYWxseSBtYWtlIHRoaXMgc3Rh dGVtZW50LiBUaGlzIGhhcyB0byB3b3JrIGV2ZW4gd2l0aCBwbGF0Zm9ybSB3aGVyZSBTQ08gbWln aHQgYWN0dWFsbHkgY29tZSB0aHJvdWdoIGFuIFVBUlQuIFRoZSBhdXRvbW90aXZlIHBsYXRmb3Jt cyBoaXN0b3JpY2FsbHkgcHJlZmVycmVkIFNDTyBvdmVyIFVBUlQuDQoNClRoZW4gYWdhaW4sIEkg YW0gbm90IGV2ZW4gcmV2aWV3aW5nIHRoaXMgcGllY2Ugb2YgY29kZS4gVXNlIHRoZSBoNF9yZWN2 X2J1ZiBoZWxwZXIuIEkgc2VuZCBhcm91bmQgZXhhbXBsZXMgZm9yIHVzaW5nIGl0IGV2ZW4gd2l0 aCB2ZW5kb3IgcGFja2V0cyBsaWtlIHdoYXQgTm9raWEgdXNlZCBpbiB0aGVpciBwbGF0Zm9ybXMu DQoNCklGOiBTQ08gbWF5IG5vdCBjb21lIHRocm91Z2ggVUFSVCBpbiBCcm9hZGNvbSBkZXZpY2Vz LiBJbiBhbnkgY2FzZSwgSSAndmUgcmVtb3ZlZCB0aGlzIGNvZGUuDQoNCj4gKwkJaWYgKGNvdW50 ID49IDMpDQo+ICsJCQlCVF9EQkcoInVuZXhwZWN0ZWQgcGt0IHR5cGUgb2YgJXggKCUwMnggJTAy eCAlMDJ4KT8hIiwNCj4gKwkJCSAgICAgICBoNC0+cmVhc3NlbWJseVswXSwgZGF0YVswXSwgZGF0 YVsxXSwgZGF0YVsyXSk7DQo+ICsJCWVsc2UgaWYgKGNvdW50ID09IDIpDQo+ICsJCQlCVF9EQkco InVuZXhwZWN0ZWQgcGt0IHR5cGUgb2YgJXggKCUwMnggJTAyeCk/ISIsDQo+ICsJCQkgICAgICAg aDQtPnJlYXNzZW1ibHlbMF0sIGRhdGFbMF0sIGRhdGFbMV0pOw0KPiArCQllbHNlIGlmIChjb3Vu dCA9PSAxKQ0KPiArCQkJQlRfREJHKCJ1bmV4cGVjdGVkIHBrdCB0eXBlIG9mICV4ICglMDJ4KT8h IiwNCj4gKwkJCSAgICAgICBoNC0+cmVhc3NlbWJseVswXSwgZGF0YVswXSk7DQo+ICsJCWVsc2UN Cj4gKwkJCUJUX0RCRygidW5leHBlY3RlZCBwa3QgdHlwZSBvZiAleD8hIiwNCj4gKwkJCSAgICAg ICBoNC0+cmVhc3NlbWJseVswXSk7DQo+ICsJCWg0LT5yc2l6ZSA9IDA7DQo+ICsJCXJldHVybjsN Cj4gKwl9DQo+ICsJfQ0KPiArfQ0KPiANCj4gLXN0YXRpYyBpbnQgYmNtX3JlY3Yoc3RydWN0IGhj aV91YXJ0ICpodSwgY29uc3Qgdm9pZCAqZGF0YSwgaW50IGNvdW50KQ0KPiArLyoNCj4gKyAqIERh dGEgaW5kaWNhdGlvbiBmcm9tIHRoZSBsaW5lIGRpc2NpcGxpbmUNCj4gKyAqLw0KPiArc3RhdGlj IGludCBiY21faDRfcmVjdihzdHJ1Y3QgaGNpX3VhcnQgKmh1LCB2b2lkICpkYXRhLCBpbnQgY291 bnQpDQo+IHsNCj4gLQlzdHJ1Y3QgYmNtX2RhdGEgKmJjbSA9IGh1LT5wcml2Ow0KPiArCXN0cnVj dCBiY21faDRfc3RydWN0ICpoNCA9IGh1LT5wcml2Ow0KPiArCWludCByZXQ7DQo+IA0KPiAtCWlm ICghdGVzdF9iaXQoSENJX1VBUlRfUkVHSVNURVJFRCwgJmh1LT5mbGFncykpDQo+ICsJQlRfREJH KCJiY21faDRfcmVjdiBodSAlcCBsZW4gJWQiLCBodSwgY291bnQpOw0KPiArDQo+ICsJaWYgKCF0 ZXN0X2JpdChIQ0lfVUFSVF9SRUdJU1RFUkVELCAmaHUtPmZsYWdzKSkgew0KPiArCQlCVF9EQkco Img0X3JlY3YgVUFSVCBub3QgcmVnaXN0ZXJlZCEiKTsNCj4gCQlyZXR1cm4gLUVVTkFUQ0g7DQo+ ICsJfQ0KDQpBbGwgdGhlc2UgZGVidWcgYWRkaXRpb25zIGFyZSBjbHV0dGVyaW5nIHRoZSBwYXRj aCByZXZpZXcuIE1ha2VzIGl0IGEgbG90IGhhcmR3YXJlIGZvciBtZSB0byByZXZpZXcuIEl0IGlz IGZpbmUgaWYgeW91IGtlZXAgdGhlbSBpbiBhIHNlcmllcyBhcyB0ZW1wb3JhcnkgcGF0Y2hlcywg YnV0IGhlcmUgaXQgaXMganVzdCBjYXVzaW5nIGV4dHJhIHdvcmsgZm9yIG1lLg0KDQpJRjogUmVt b3ZlZCBleHRyYSBkZWJ1ZyBzdGF0ZW1lbnRzLg0KDQo+IA0KPiAtCWJjbS0+cnhfc2tiID0gaDRf cmVjdl9idWYoaHUtPmhkZXYsIGJjbS0+cnhfc2tiLCBkYXRhLCBjb3VudCwNCj4gLQkJCQkgIGJj bV9yZWN2X3BrdHMsIEFSUkFZX1NJWkUoYmNtX3JlY3ZfcGt0cykpOw0KPiAtCWlmIChJU19FUlIo YmNtLT5yeF9za2IpKSB7DQo+IC0JCWludCBlcnIgPSBQVFJfRVJSKGJjbS0+cnhfc2tiKTsNCj4g LQkJQlRfRVJSKCIlczogRnJhbWUgcmVhc3NlbWJseSBmYWlsZWQgKCVkKSIsIGh1LT5oZGV2LT5u YW1lLCBlcnIpOw0KPiAtCQlyZXR1cm4gZXJyOw0KPiArCS8qIE1ha2Ugc3VyZSB3ZSdyZSByZXN1 bWVkICovDQo+ICsJYmNtX2Vuc3VyZV93YWtldXAoaHUpOw0KPiArDQo+ICsJLyogSWYgd2UncmUg aW4gdGhlIGFjdGl2ZSBwaGFzZSwgcGFyc2Ugd2hhdCB3ZSBnZXQgKi8NCj4gKwlpZiAoaDQtPnBh cnNlX3JlY3YpIHsNCj4gKwkJcGFyc2VfZnJhZ21lbnQoaHUsIGRhdGEsIGNvdW50KTsNCj4gKwl9 IGVsc2Ugew0KPiArCQlyZXQgPSBoY2lfcmVjdl9zdHJlYW1fZnJhZ21lbnQoaHUtPmhkZXYsIGRh dGEsIGNvdW50KTsNCg0KVGhlIGhjaV9yZWN2X3N0cmVhbV9mcmFnZW1lbnQgZnVuY3Rpb24gaXMg Z29uZSBmcm9tIHVwc3RyZWFtLiBZb3UgY2FuIG5vdCB1c2UgaXQgYW55bW9yZS4NCg0KPiArCQlp ZiAocmV0IDwgMCkgew0KPiArCQkJQlRfRVJSKCJiY21faDRfcmVjdjogZnJhbWUgcmVhc3NlbWJs eSBmYWlsZWQiKTsNCj4gKwkJCXJldHVybiByZXQ7DQo+ICsJCX0NCj4gCX0NCj4gDQo+IAlyZXR1 cm4gY291bnQ7DQo+IH0NCj4gDQo+IC1zdGF0aWMgaW50IGJjbV9lbnF1ZXVlKHN0cnVjdCBoY2lf dWFydCAqaHUsIHN0cnVjdCBza19idWZmICpza2IpDQo+ICsvKg0KPiArICogTGluZSBkaXNjaXBs aW5lIGlzIGdyYWJiaW5nIGEgcGFja2V0IGZyb20gdGhlIHR4IHF1ZXVlDQo+ICsgKi8NCj4gK3N0 YXRpYyBzdHJ1Y3Qgc2tfYnVmZiAqYmNtX2g0X2RlcXVldWUoc3RydWN0IGhjaV91YXJ0ICpodSkN Cj4gew0KDQpUaGlzIHJlbmFtaW5nIGlzIHJlYWxseSBub3QgaGVscGluZyB0byBtYWtlIHRoZSBw YXRjaCBsb29rIHNpbXBsZXIuDQoNCklGOiBSZXN0b3JlZCB0aGUgb3JpZ2luYWwgbmFtaW5nLg0K DQo+IC0Jc3RydWN0IGJjbV9kYXRhICpiY20gPSBodS0+cHJpdjsNCj4gKwlzdHJ1Y3QgYmNtX2g0 X3N0cnVjdCAqaDQgPSBodS0+cHJpdjsNCj4gKwlpbnQgaXNfcWVtcHR5ID0gc2tiX3F1ZXVlX2Vt cHR5KCZoNC0+dHhxKTsNCj4gDQo+IC0JQlRfREJHKCJodSAlcCBza2IgJXAiLCBodSwgc2tiKTsN Cj4gKwlpZiAoIWlzX3FlbXB0eSkNCj4gKwkJQlRfREJHKCJiY21faDRfZGVxdWV1ZSB3aXRoIG5v bi1lbXB0eSBxdWV1ZSIpOw0KPiArCXJldHVybiBza2JfZGVxdWV1ZSgmaDQtPnR4cSk7DQo+ICt9 DQo+IA0KPiAtCS8qIFByZXBlbmQgc2tiIHdpdGggZnJhbWUgdHlwZSAqLw0KPiAtCW1lbWNweShz a2JfcHVzaChza2IsIDEpLCAmYnRfY2Ioc2tiKS0+cGt0X3R5cGUsIDEpOw0KPiAtCXNrYl9xdWV1 ZV90YWlsKCZiY20tPnR4cSwgc2tiKTsNCj4gKy8qDQo+ICsgKiBDYWxsYmFja3MgZnJvbSB0aGUg QkNNQlRfVUFSVCBkZXZpY2UNCj4gKyAqLw0KPiANCj4gLQlyZXR1cm4gMDsNCj4gKy8qDQo+ICsg KiBUaGUgcGxhdGZvcm0gaXMgc3VzcGVuZGluZy4gU3RvcCBVQVJUIGFjdGl2aXR5DQo+ICsgKi8N Cj4gK3N0YXRpYyB2b2lkIHN1c3BlbmRfbm90aWZpY2F0aW9uKHZvaWQgKmNvbnRleHQpDQo+ICt7 DQo+ICsJc3RydWN0IGt0ZXJtaW9zIGt0ZXJtaW9zOw0KPiArCXN0cnVjdCBoY2lfdWFydCAqaHUg PSAoc3RydWN0IGhjaV91YXJ0ICopY29udGV4dDsNCj4gKwlzdHJ1Y3QgYmNtX2g0X3N0cnVjdCAq aDQgPSBodS0+cHJpdjsNCj4gKwlzdHJ1Y3QgdHR5X3N0cnVjdCAqdHR5ID0gaHUtPnR0eTsNCj4g KwlpbnQgc3RhdHVzOw0KPiArCXVuc2lnbmVkIGludCBzZXQgPSAwOw0KPiArCXVuc2lnbmVkIGlu dCBjbGVhciA9IDA7DQo+ICsNCj4gKwlCVF9EQkcoInN1c3BlbmRfbm90aWZpY2F0aW9uIHdpdGgg aXNfc3VzcGVuZGVkICVkIiwgaDQtPmlzX3N1c3BlbmRlZCk7DQo+ICsNCj4gKwlpZiAoIWg0LT5w YXJzLmNvbmZpZ3VyZV9zbGVlcCkNCj4gKwkJcmV0dXJuOw0KPiArDQo+ICsJaWYgKCFoNC0+aXNf c3VzcGVuZGVkKSB7DQo+ICsJCWlmIChoNC0+cGFycy5tYW51YWxfZmMpIHsNCj4gKwkJCS8qIERp c2FibGUgaGFyZHdhcmUgZmxvdyBjb250cm9sICovDQo+ICsJCQlrdGVybWlvcyA9IHR0eS0+dGVy bWlvczsNCj4gKwkJCWt0ZXJtaW9zLmNfY2ZsYWcgJj0gfkNSVFNDVFM7DQo+ICsJCQlzdGF0dXMg PSB0dHlfc2V0X3Rlcm1pb3ModHR5LCAma3Rlcm1pb3MpOw0KPiArCQkJaWYgKHN0YXR1cykNCj4g KwkJCQlCVF9EQkcoInN1c3BlbmRfbm90aWZpY2F0aW9uIGRpcyBmYyBmYWlsICVkIiwNCj4gKwkJ CQkgICAgICAgc3RhdHVzKTsNCj4gKwkJCWVsc2UNCj4gKwkJCQlCVF9EQkcoInN1c3BlbmRfbm90 aWZpY2F0aW9uIGh3IGZjIGRpc2FibGVkIik7DQo+ICsNCj4gKwkJCS8qIENsZWFyIFJUUyB0byBw cmV2ZW50IHRoZSBkZXZpY2UgZnJvbSBzZW5kaW5nICovDQo+ICsJCQkvKiAobW9zdCBQQ3MgbmVl ZCBPVVQyIHRvIGVuYWJsZSBpbnRlcnJ1cHRzKSAgICAqLw0KPiArCQkJc3RhdHVzID0gdHR5LT5k cml2ZXItPm9wcy0+dGlvY21nZXQodHR5KTsNCj4gKwkJCUJUX0RCRygic3VzcGVuZF9ub3RpZmlj YXRpb24gY3VyIHRpb2NtIDB4JXgiLCBzdGF0dXMpOw0KPiArCQkJc2V0ICY9IH4oVElPQ01fT1VU MiB8IFRJT0NNX1JUUyk7DQo+ICsJCQljbGVhciA9IH5zZXQ7DQo+ICsJCQlzZXQgJj0gVElPQ01f RFRSIHwgVElPQ01fUlRTIHwgVElPQ01fT1VUMSB8DQo+ICsJCQkJVElPQ01fT1VUMiB8IFRJT0NN X0xPT1A7DQo+ICsJCQljbGVhciAmPSBUSU9DTV9EVFIgfCBUSU9DTV9SVFMgfCBUSU9DTV9PVVQx IHwNCj4gKwkJCQlUSU9DTV9PVVQyIHwgVElPQ01fTE9PUDsNCj4gKwkJCXN0YXR1cyA9IHR0eS0+ ZHJpdmVyLT5vcHMtPnRpb2Ntc2V0KHR0eSwgc2V0LCBjbGVhcik7DQo+ICsJCQlpZiAoc3RhdHVz KQ0KPiArCQkJCUJUX0RCRygic3VzcGVuZF9ub3RpZmljYXRpb24gY2xyIFJUUyBmYWlsICVkIiwN Cj4gKwkJCQkgICAgICAgc3RhdHVzKTsNCj4gKwkJCWVsc2UNCj4gKwkJCQlCVF9EQkcoInN1c3Bl bmRfbm90aWZpY2F0aW9uIFJUUyBjbGVhcmVkIik7DQo+ICsJCQlzdGF0dXMgPSB0dHktPmRyaXZl ci0+b3BzLT50aW9jbWdldCh0dHkpOw0KPiArCQkJQlRfREJHKCJzdXNwZW5kX25vdGlmaWNhdGlv biBlbmQgdGlvY20gMHgleCIsIHN0YXR1cyk7DQo+ICsJCX0NCg0KSSB0aGluayB0aGF0IGhjaV9s ZGlzYy5jIHNob3VsZCBtYXliZSBwcm92aWRlIGNvbW1vbiBoZWxwZXJzIGZvciBjbGVhcmluZyBS VFMgZXRjLiBJIHdvdWxkIHdvcmsgb24gbWFraW5nIHRoYXQgZ2VuZXJpYyBhbmQgc3BsaXR0aW5n IGl0IG91dCBzbyBpdCBjYW4gYmUgdXNlZCBieSBvdGhlcnMuIFNlZW1zIGxpa2UgdGhlIEF0aGVy b3MgVUFSVCBkcml2ZXIgbmVlZHMgdGhhdCBhcyB3ZWxsLiBIb3dldmVyIGl0IGxvb2tzIGEgbG90 IHNpbXBsZXIgdGhlcmUuIEFueXdheSwgaXQgc2hvdWxkIGJlIGdlbmVyYWwgYW5kIG5vdCBkdXBs aWNhdGVkIGluIGV2ZXJ5IHN1YiBkcml2ZXIuDQoNCklGOiBBZ3JlZTogbGV0J3MgYXBwcm92ZSBy ZWxldmFudCBJbnRlbCBjaGFuZ2VzIGFuZCBJJ2xsIHVzZSB0aGVtLg0KDQo+ICsNCj4gKwkJLyog T25jZSB0aGlzIGNhbGxiYWNrIHJldHVybnMsIGRyaXZlciBzdXNwZW5kcyBCVCB2aWEgR1BJTyAq Lw0KPiArCQloNC0+aXNfc3VzcGVuZGVkID0gdHJ1ZTsNCj4gKwl9DQo+ICt9DQo+ICsNCj4gKy8q DQo+ICsgKiBUaGUgcGxhdGZvcm0gaXMgcmVzdW1pbmcuIFJlc3VtZSBVQVJUIGFjdGl2aXR5Lg0K PiArICovDQo+ICtzdGF0aWMgdm9pZCByZXN1bWVfbm90aWZpY2F0aW9uKHZvaWQgKmNvbnRleHQp DQo+ICt7DQo+ICsJc3RydWN0IGt0ZXJtaW9zIGt0ZXJtaW9zOw0KPiArCXN0cnVjdCBoY2lfdWFy dCAqaHUgPSAoc3RydWN0IGhjaV91YXJ0ICopY29udGV4dDsNCj4gKwlzdHJ1Y3QgYmNtX2g0X3N0 cnVjdCAqaDQgPSBodS0+cHJpdjsNCj4gKwlzdHJ1Y3QgdHR5X3N0cnVjdCAqdHR5ID0gaHUtPnR0 eTsNCj4gKwlpbnQgc3RhdHVzOw0KPiArCXVuc2lnbmVkIGludCBzZXQgPSAwOw0KPiArCXVuc2ln bmVkIGludCBjbGVhciA9IDA7DQo+ICsNCj4gKwlCVF9EQkcoInJlc3VtZV9ub3RpZmljYXRpb24g d2l0aCBpc19zdXNwZW5kZWQgJWQiLCBoNC0+aXNfc3VzcGVuZGVkKTsNCj4gKw0KPiArCWlmICgh aDQtPnBhcnMuY29uZmlndXJlX3NsZWVwKQ0KPiArCQlyZXR1cm47DQo+ICsNCj4gKwkvKiBXaGVu IHRoaXMgY2FsbGJhY2sgZXhlY3V0ZXMsIHRoZSBkZXZpY2UgaGFzIHdva2VuIHVwIGFscmVhZHkg Ki8NCj4gKwlpZiAoaDQtPmlzX3N1c3BlbmRlZCkgew0KPiArCQloNC0+aXNfc3VzcGVuZGVkID0g ZmFsc2U7DQo+ICsNCj4gKwkJaWYgKGg0LT5wYXJzLm1hbnVhbF9mYykgew0KPiArCQkJc3RhdHVz ID0gdHR5LT5kcml2ZXItPm9wcy0+dGlvY21nZXQodHR5KTsNCj4gKwkJCUJUX0RCRygicmVzdW1l X25vdGlmaWNhdGlvbiBjdXIgdGlvY20gMHgleCIsIHN0YXR1cyk7DQo+ICsJCQlzZXQgfD0gKFRJ T0NNX09VVDIgfCBUSU9DTV9SVFMpOw0KPiArCQkJY2xlYXIgPSB+c2V0Ow0KPiArCQkJc2V0ICY9 IFRJT0NNX0RUUiB8IFRJT0NNX1JUUyB8IFRJT0NNX09VVDEgfA0KPiArCQkJCVRJT0NNX09VVDIg fCBUSU9DTV9MT09QOw0KPiArCQkJY2xlYXIgJj0gVElPQ01fRFRSIHwgVElPQ01fUlRTIHwgVElP Q01fT1VUMSB8DQo+ICsJCQkJVElPQ01fT1VUMiB8IFRJT0NNX0xPT1A7DQo+ICsJCQlzdGF0dXMg PSB0dHktPmRyaXZlci0+b3BzLT50aW9jbXNldCh0dHksIHNldCwgY2xlYXIpOw0KPiArCQkJaWYg KHN0YXR1cykNCj4gKwkJCQlCVF9EQkcoInJlc3VtZV9ub3RpZmljYXRpb24gc2V0IFJUUyBmYWls ICVkIiwNCj4gKwkJCQkgICAgICAgc3RhdHVzKTsNCj4gKwkJCWVsc2UNCj4gKwkJCQlCVF9EQkco InJlc3VtZV9ub3RpZmljYXRpb24gUlRTIHNldCIpOw0KPiArDQo+ICsJCQkvKiBSZS1lbmFibGUg aGFyZHdhcmUgZmxvdyBjb250cm9sICovDQo+ICsJCQlrdGVybWlvcyA9IHR0eS0+dGVybWlvczsN Cj4gKwkJCWt0ZXJtaW9zLmNfY2ZsYWcgfD0gQ1JUU0NUUzsNCj4gKwkJCXN0YXR1cyA9IHR0eV9z ZXRfdGVybWlvcyh0dHksICZrdGVybWlvcyk7DQo+ICsJCQlpZiAoc3RhdHVzKQ0KPiArCQkJCUJU X0RCRygicmVzdW1lX25vdGlmaWNhdGlvbiBlbmFibGUgZmMgZmFpbCAlZCIsDQo+ICsJCQkJICAg ICAgIHN0YXR1cyk7DQo+ICsJCQllbHNlDQo+ICsJCQkJQlRfREJHKCJyZXN1bWVfbm90aWZpY2F0 aW9uIGh3IGZjIHJlLWVuYWJsZWQiKTsNCj4gKwkJfQ0KPiArCX0NCj4gKw0KPiArCS8qIElmIHdl J3JlIHJlc3VtZWQsIHRoZSBpZGxlIHRpbWVyIG11c3QgYmUgcnVubmluZyAqLw0KPiArCXN0YXR1 cyA9IG1vZF90aW1lcigmaDQtPnRpbWVyLCBqaWZmaWVzICsNCj4gKwkgICAgbXNlY3NfdG9famlm ZmllcyhoNC0+cGFycy5pZGxlX3RpbWVvdXRfaW5fc2VjcyAqIDEwMDApKTsNCj4gfQ0KPiANCj4g LXN0YXRpYyBzdHJ1Y3Qgc2tfYnVmZiAqYmNtX2RlcXVldWUoc3RydWN0IGhjaV91YXJ0ICpodSkN Cj4gKy8qDQo+ICsgKiBUaGUgQlQgZGV2aWNlIGlzIHJlc3VtaW5nLiBSZXN1bWUgVUFSVCBhY3Rp dml0eSBpZiBzdXNwZW5kZWQNCj4gKyAqLw0KPiArc3RhdGljIHZvaWQgd2FrZXVwX25vdGlmaWNh dGlvbih2b2lkICpjb250ZXh0KQ0KPiB7DQo+IC0Jc3RydWN0IGJjbV9kYXRhICpiY20gPSBodS0+ cHJpdjsNCj4gKwlzdHJ1Y3Qga3Rlcm1pb3Mga3Rlcm1pb3M7DQo+ICsJc3RydWN0IGhjaV91YXJ0 ICpodSA9IChzdHJ1Y3QgaGNpX3VhcnQgKiljb250ZXh0Ow0KPiArCXN0cnVjdCBiY21faDRfc3Ry dWN0ICpoNCA9IGh1LT5wcml2Ow0KPiArCXN0cnVjdCB0dHlfc3RydWN0ICp0dHkgPSBodS0+dHR5 Ow0KPiArCWludCBzdGF0dXM7DQo+ICsJdW5zaWduZWQgaW50IHNldCA9IDA7DQo+ICsJdW5zaWdu ZWQgaW50IGNsZWFyID0gMDsNCj4gKw0KPiArCWlmICghaDQtPnBhcnMuY29uZmlndXJlX3NsZWVw KQ0KPiArCQlyZXR1cm47DQo+ICsNCj4gKwlzdGF0dXMgPSB0dHktPmRyaXZlci0+b3BzLT50aW9j bWdldCh0dHkpOw0KPiArCUJUX0RCRygid2FrZXVwX25vdGlmaWNhdGlvbiBodSAlcCBjdXJyZW50 IHRpb2NtIDB4JXgiLCBodSwgc3RhdHVzKTsNCj4gKwlpZiAoaDQtPmlzX3N1c3BlbmRlZCkgew0K PiArCQlpZiAoaDQtPnBhcnMubWFudWFsX2ZjKSB7DQo+ICsJCQlzZXQgfD0gKFRJT0NNX09VVDIg fCBUSU9DTV9SVFMpOw0KPiArCQkJY2xlYXIgPSB+c2V0Ow0KPiArCQkJc2V0ICY9IFRJT0NNX0RU UiB8IFRJT0NNX1JUUyB8IFRJT0NNX09VVDEgfA0KPiArCQkJCVRJT0NNX09VVDIgfCBUSU9DTV9M T09QOw0KPiArCQkJY2xlYXIgJj0gVElPQ01fRFRSIHwgVElPQ01fUlRTIHwgVElPQ01fT1VUMSB8 DQo+ICsJCQkJVElPQ01fT1VUMiB8IFRJT0NNX0xPT1A7DQo+ICsJCQlzdGF0dXMgPSB0dHktPmRy aXZlci0+b3BzLT50aW9jbXNldCh0dHksIHNldCwgY2xlYXIpOw0KPiArCQkJaWYgKHN0YXR1cykN Cj4gKwkJCQlCVF9EQkcoIndha2V1cF9ub3RpZmljYXRpb24gc2V0IFJUUyBmYWlsICVkIiwNCj4g KwkJCQkgICAgICAgc3RhdHVzKTsNCj4gKwkJCWVsc2UNCj4gKwkJCQlCVF9EQkcoIndha2V1cF9u b3RpZmljYXRpb24gUlRTIHNldCIpOw0KPiArDQo+ICsJCQkvKiBSZS1lbmFibGUgaGFyZHdhcmUg ZmxvdyBjb250cm9sICovDQo+ICsJCQlrdGVybWlvcyA9IHR0eS0+dGVybWlvczsNCj4gKwkJCWt0 ZXJtaW9zLmNfY2ZsYWcgfD0gQ1JUU0NUUzsNCj4gKwkJCXN0YXR1cyA9IHR0eV9zZXRfdGVybWlv cyh0dHksICZrdGVybWlvcyk7DQo+ICsJCQlpZiAoc3RhdHVzKQ0KPiArCQkJCUJUX0RCRygid2Fr ZXVwX25vdGlmaWNhdGlvbiBmYy1lbiBmYWlsdXJlICVkIiwNCj4gKwkJCQkgICAgICAgc3RhdHVz KTsNCj4gKwkJCWVsc2UNCj4gKwkJCQlCVF9EQkcoIndha2V1cF9ub3RpZmljYXRpb24gaHcgZmMg cmUtZW5hYmxlZCIpOw0KPiArCQl9DQo+ICsNCj4gKwkJaDQtPmlzX3N1c3BlbmRlZCA9IGZhbHNl Ow0KPiArCX0NCj4gDQo+IC0JcmV0dXJuIHNrYl9kZXF1ZXVlKCZiY20tPnR4cSk7DQo+ICsJLyog SWYgd2UncmUgcmVzdW1lZCwgdGhlIGlkbGUgdGltZXIgbXVzdCBiZSBydW5uaW5nICovDQo+ICsJ c3RhdHVzID0gbW9kX3RpbWVyKCZoNC0+dGltZXIsIGppZmZpZXMgKyBtc2Vjc190b19qaWZmaWVz KA0KPiArCQkJICAgaDQtPnBhcnMuaWRsZV90aW1lb3V0X2luX3NlY3MgKiAxMDAwKSk7DQo+IH0N Cj4gDQo+IC1zdGF0aWMgY29uc3Qgc3RydWN0IGhjaV91YXJ0X3Byb3RvIGJjbV9wcm90byA9IHsN Cj4gKy8qDQo+ICsgKiBEZXZpY2Ugc2V0dXAgdGhhdCBmb2xsb3dzIHRoZSBwcm90b2NvbCBvcGVu DQo+ICsgKi8NCj4gK3N0YXRpYyBpbnQgYmNtX2g0X3NldHVwKHN0cnVjdCBoY2lfdWFydCAqaHUp DQo+ICt7DQo+ICsJc3RydWN0IGJjbV9oNF9zdHJ1Y3QgKmg0ID0gaHUtPnByaXY7DQo+ICsJaW50 IHN0YXR1czsNCj4gKwlzdHJ1Y3Qgc2tfYnVmZiAqc2tiOw0KPiArCXVuc2lnbmVkIGNoYXIgc2xl ZXBfcGFyc1tdID0gew0KPiArCTB4MDEsICAgICAgIC8qIHNsZWVwIG1vZGUgMT1VQVJUICovDQo+ ICsJMHgwMiwgICAgICAgLyogaWRsZSB0aHJlc2hvbGQgSE9TVCAodmFsdWUgKiAzMDBtcykgKi8N Cj4gKwkweDAyLCAgICAgICAvKiBpZGxlIHRocmVzaG9sZCBIQyAgICh2YWx1ZSAqIDMwMG1zKSAq Lw0KPiArCTB4MDEsICAgICAgIC8qIEJUX1dBS0UgYWN0aXZlIG1vZGUgLSAxPWFjdGl2ZSBoaWdo LCAwID0gYWN0aXZlIGxvdyAqLw0KPiArCTB4MDAsICAgICAgIC8qIEhPU1RfV0FLRSBhY3RpdmUg bW9kZSAtIDE9YWN0aXZlIGhpZ2gsIDAgPSBhY3RpdmUgbG93ICovDQo+ICsJMHgwMSwgICAgICAg LyogQWxsb3cgaG9zdCBzbGVlcCBkdXJpbmcgU0NPIC0gRkFMU0UgKi8NCj4gKwkweDAxLCAgICAg ICAvKiBjb21iaW5lIHNsZWVwIG1vZGUgYW5kIExQTSAtIDEgPT0gVFJVRSAqLw0KPiArCTB4MDAs ICAgICAgIC8qIGVuYWJsZSB0cmlzdGF0ZSBjb250cm9sIG9mIFVBUlQgVFggbGluZSAtIEZBTFNF ICovDQo+ICsJMHgwMCwgICAgICAgLyogVVNCIGF1dG8tc2xlZXAgb24gVVNCIFNVU1BFTkQgKi8N Cj4gKwkweDAwLCAgICAgICAvKiBVU0IgVVNCIFJFU1VNRSB0aW1lb3V0IChzZWNvbmRzKSAqLw0K PiArCTB4MDAsICAgICAgIC8qIFB1bHNlZCBIb3N0IFdha2UgKi8NCj4gKwkweDAwICAgICAgICAv KiBFbmFibGUgQnJlYWsgVG8gSG9zdCAqLw0KPiArCX07DQo+ICsJdW5zaWduZWQgY2hhciBwY21f aW50X3BhcnNbXSA9IHsNCj4gKwkweDAwLCAgICAgICAvKiAwPVBDTSByb3V0aW5nLCAxPVNDTyBv dmVyIEhDSSAqLw0KPiArCTB4MDIsICAgICAgIC8qIDA9MTI4S2JwcywxPTI1NkticHMsMj01MTJL YnBzLDM9MTAyNEticHMsND0yMDQ4S2JwcyAqLw0KPiArCTB4MDAsICAgICAgIC8qIHNob3J0IGZy YW1lIHN5bmMgIDA9c2hvcnQsIDE9bG9uZyAqLw0KPiArCTB4MDAsICAgICAgIC8qIHN5bmMgbW9k ZSAgICAgICAgIDA9c2xhdmUsIDE9bWFzdGVyICovDQo+ICsJMHgwMCAgICAgICAgLyogY2xvY2sg bW9kZSAgICAgICAgMD1zbGF2ZSwgMT1tYXN0ZXIgKi8NCj4gKwl9Ow0KPiArCXVuc2lnbmVkIGNo YXIgcGNtX2Zvcm1hdF9wYXJzW10gPSB7DQo+ICsJMHgwMCwgICAgICAgLyogTFNCX0ZpcnN0IDE9 VFJVRSwgMD1GQUxTRSAqLw0KPiArCTB4MDAsICAgICAgIC8qIEZpbGxfVmFsdWUgKHVzZSAwLTcg Zm9yIGZpbGwgYml0cyB2YWx1ZSkgKi8NCj4gKwkweDAyLCAgICAgICAvKiBGaWxsX01ldGhvZCAg ICgyPXNpZ24gZXh0ZW5kZWQpICovDQo+ICsJMHgwMywgICAgICAgLyogRmlsbF9OdW0gICAgICAj IG9mIGZpbGwgYml0cyAwLTMpICovDQo+ICsJMHgwMSAgICAgICAgLyogUmlnaHRfSnVzdGlmeSAx PVRSVUUsIDA9RkFMU0UgKi8NCj4gKwl9Ow0KDQpUaGlzIGlzIHZpb2xhdGluZyB0aGUgaW5kZW50 YXRpb24gY29kaW5nIHN0eWxlLg0KDQpJRjogVGhhdCdzIGNvcnJlY3QuIEJ1dCBpdCBkb2VzIGFs bG93IHVzIHRvIGhhdmUgbW9yZSByb29tIGZvciB0aGUgcGFyYW1ldGVyIGRlc2NyaXB0aW9ucy4N Cg0KPiArCXVuc2lnbmVkIGNoYXIgdGltZV9zbG90X251bWJlciA9IDA7DQo+ICsNCj4gKwlCVF9E QkcoImJjbV9oNF9zZXR1cCBodSAlcCIsIGh1KTsNCj4gKw0KPiArCS8qIEJyaW5nIHRoZSBVQVJU IGludG8ga25vd24gZGVmYXVsdCBzdGF0ZSAqLw0KPiArCXN0YXR1cyA9IGJ0YmNtX2luaXRfdWFy dChodSk7DQo+ICsJaWYgKHN0YXR1cykgew0KPiArCQlCVF9EQkcoImJjbV9oNF9zZXR1cCBmYWls ZWQgdG8gaW5pdCBCVCBkZXZpY2UgJWQiLCBzdGF0dXMpOw0KPiArCQlyZXR1cm4gc3RhdHVzOw0K PiArCX0NCj4gKw0KPiArCS8qIEJhc2ljIHNhbml0eSBjaGVjayAqLw0KPiArCXNrYiA9IF9faGNp X2NtZF9zeW5jKGh1LT5oZGV2LCBIQ0lfT1BfUkVTRVQsIDAsIE5VTEwsIEhDSV9JTklUX1RJTUVP VVQpOw0KPiArCWlmIChJU19FUlIoc2tiKSkgew0KPiArCQlzdGF0dXMgPSBQVFJfRVJSKHNrYik7 DQo+ICsJCUJUX0VSUigiYmNtX2g0X3NldHVwIEhDSSBSZXNldCBmYWlsZWQgKCVkKSIsIHN0YXR1 cyk7DQo+ICsJCXJldHVybiBzdGF0dXM7DQo+ICsJfQ0KPiArCWtmcmVlX3NrYihza2IpOw0KPiAr CUJUX0RCRygiYmNtX2g0X3NldHVwIEhDSSBSZXNldCBzdWNjZWVkZWQiKTsNCj4gKw0KPiArCS8q IFNldCB0aGUgbmV3IGJhdWQgcmF0ZSAqLw0KPiArCXN0YXR1cyA9IGJ0YmNtX3NldF9iYXVkX3Jh dGUoaHUsDQo+ICsJCQkJICAgICBoNC0+cGFycy5iYXVkX3JhdGVfYmVmb3JlX2NvbmZpZ19kb3du bG9hZCk7DQo+ICsJaWYgKHN0YXR1cykgew0KPiArCQlCVF9FUlIoImJjbV9oNF9zZXR1cCBzZXRf YmF1ZF9yYXRlIGZhaWlsdXJlICVkIiwgc3RhdHVzKTsNCj4gKwkJcmV0dXJuIHN0YXR1czsNCj4g Kwl9DQo+ICsNCj4gKwlodS0+aGRldi0+c2V0X2JkYWRkciA9IGJ0YmNtX3NldF9iZGFkZHI7DQo+ ICsNCj4gKwkvKiBEb3dubG9hZCB0aGUgZmlybXdhcmUgYW5kIHJlY29uZmlndXJlIHRoZSBVQVJU IGFmdGVyd2FyZHMgKi8NCj4gKwlzdGF0dXMgPSBidGJjbV9zZXR1cF9wYXRjaHJhbShodS0+aGRl dik7DQo+ICsJaWYgKHN0YXR1cykgew0KPiArCQlCVF9FUlIoImJjbV9oNF9zZXR1cCBzZXR1cF9w YXRjaHJhbSBmYWlpbHVyZSAlZCIsIHN0YXR1cyk7DQo+ICsJCXJldHVybiBzdGF0dXM7DQo+ICsJ fQ0KPiArDQo+ICsJLyogQ29uZmlndXJlIFNDTyBQQ00gcGFyYW1ldGVycyAqLw0KPiArCWlmICho NC0+cGFycy5jb25maWd1cmVfYXVkaW8pIHsNCj4gKwkJcGNtX2ludF9wYXJzWzBdID0gaDQtPnBh cnMuUENNUm91dGluZzsNCj4gKwkJcGNtX2ludF9wYXJzWzFdID0gaDQtPnBhcnMuUENNSW5DYWxs Qml0Y2xvY2s7DQo+ICsJCXBjbV9pbnRfcGFyc1syXSA9IGg0LT5wYXJzLlBDTVNob3J0RnJhbWVT eW5jOw0KPiArCQlwY21faW50X3BhcnNbM10gPSBoNC0+cGFycy5QQ01TeW5jTW9kZTsNCj4gKwkJ cGNtX2ludF9wYXJzWzRdID0gaDQtPnBhcnMuUENNQ2xvY2tNb2RlOw0KDQpJIHJlYWxseSBnZXQg dGhlIGZlZWxpbmcgd2Ugd2FudCBhIHByb3BlciBzdHJ1Y3QgZm9yIHRoaXMgSENJIGNvbW1hbmQu IEkgYWxzbyB3b25kZXIgaWYgdGhpcyBzaG91bGQgYmUgYWN0dWFsIHNvbWUgZ2VuZXJpYyBmdW5j dGlvbiBleHBvc2VkIGJ5IGJ0YmNtLmtvLiBJdCBpcyByZWFsbHkgbm90IGxpbWl0ZWQgdG8gVUFS VCBkZXZpY2UuIEl0IGlzIGFsc28gcG9zc2libGUgdG8gYnVpbGQgYW4gVVNCIGJhc2VkIHBsYXRm b3JtIHRoYXQgaGFzIFNDTyByb3V0ZWQgb3ZlciBQQ00uDQoNCklGOiBUaGlzIGlzIG5vdCBzdXBw b3J0ZWQgYnkgdGhlIEJyb2FkY29tIFVTQiBkZXZpY2VzLg0KDQo+ICsJCXNrYiA9IF9faGNpX2Nt ZF9zeW5jKGh1LT5oZGV2LCAweGZjMWMsIHNpemVvZihwY21faW50X3BhcnMpLA0KPiArCQkJCSAg ICAgcGNtX2ludF9wYXJzLCBIQ0lfSU5JVF9USU1FT1VUKTsNCj4gKwkJaWYgKElTX0VSUihza2Ip KSB7DQo+ICsJCQlzdGF0dXMgPSBQVFJfRVJSKHNrYik7DQo+ICsJCQlCVF9FUlIoImJjbV9oNF9z ZXR1cCBQQ00gSU5UIFZTQyBmYWlsZWQgKCVkKSIsIHN0YXR1cyk7DQo+ICsJCQlyZXR1cm4gc3Rh dHVzOw0KPiArCQl9DQo+ICsJCWtmcmVlX3NrYihza2IpOw0KPiArCQlCVF9EQkcoImJjbV9oNF9z ZXR1cCBQQ00gSU5UIFBhcmFtZXRlcnMgVlNDIHN1Y2NlZWRlZCIpOw0KPiArDQo+ICsJCXBjbV9m b3JtYXRfcGFyc1swXSA9IGg0LT5wYXJzLlBDTUxTQkZpcnN0Ow0KPiArCQlwY21fZm9ybWF0X3Bh cnNbMV0gPSBoNC0+cGFycy5QQ01GaWxsVmFsdWU7DQo+ICsJCXBjbV9mb3JtYXRfcGFyc1syXSA9 IGg0LT5wYXJzLlBDTUZpbGxNZXRob2Q7DQo+ICsJCXBjbV9mb3JtYXRfcGFyc1szXSA9IGg0LT5w YXJzLlBDTUZpbGxOdW07DQo+ICsJCXBjbV9mb3JtYXRfcGFyc1s0XSA9IGg0LT5wYXJzLlBDTVJp Z2h0SnVzdGlmeTsNCj4gKwkJc2tiID0gX19oY2lfY21kX3N5bmMoaHUtPmhkZXYsIDB4ZmMxZSwg c2l6ZW9mKHBjbV9mb3JtYXRfcGFycyksDQo+ICsJCQkJICAgICBwY21fZm9ybWF0X3BhcnMsIEhD SV9JTklUX1RJTUVPVVQpOw0KPiArCQlpZiAoSVNfRVJSKHNrYikpIHsNCj4gKwkJCXN0YXR1cyA9 IFBUUl9FUlIoc2tiKTsNCj4gKwkJCUJUX0VSUigiYmNtX2g0X3NldHVwIFBDTSBGb3JtYXQgVlND IGZhaWxlZCAoJWQpIiwNCj4gKwkJCSAgICAgICBzdGF0dXMpOw0KPiArCQkJcmV0dXJuIHN0YXR1 czsNCj4gKwkJfQ0KPiArCQlrZnJlZV9za2Ioc2tiKTsNCj4gKwkJQlRfREJHKCJiY21faDRfc2V0 dXAgUENNIEZvcm1hdCBWU0Mgc3VjY2VlZGVkIik7DQo+ICsNCj4gKwkJc2tiID0gX19oY2lfY21k X3N5bmMoaHUtPmhkZXYsIDB4ZmMyMiwgc2l6ZW9mKHRpbWVfc2xvdF9udW1iZXIpLA0KPiArCQkJ CSAgICAgJnRpbWVfc2xvdF9udW1iZXIsIEhDSV9JTklUX1RJTUVPVVQpOw0KPiArCQlpZiAoSVNf RVJSKHNrYikpIHsNCj4gKwkJCXN0YXR1cyA9IFBUUl9FUlIoc2tiKTsNCj4gKwkJCUJUX0VSUigi YmNtX2g0X3NldHVwIFNDTyBUaW1lIFNsb3QgVlNDIGZhaWxlZCAoJWQpIiwNCj4gKwkJCSAgICAg ICBzdGF0dXMpOw0KPiArCQkJcmV0dXJuIHN0YXR1czsNCj4gKwkJfQ0KPiArCQlrZnJlZV9za2Io c2tiKTsNCj4gKwkJQlRfREJHKCJiY21faDRfc2V0dXAgU0NPIFRpbWUgU2xvdCBWU0Mgc3VjY2Vl ZGVkIik7DQo+ICsJfQ0KPiArDQo+ICsJLyogQ29uZmlndXJlIGRldmljZSdzIHN1c3BlbmQvcmVz dW1lIG9wZXJhdGlvbiAqLw0KPiArCWlmIChoNC0+cGFycy5jb25maWd1cmVfc2xlZXApIHsNCj4g KwkJLyogT3ZlcnJpZGUgdGhlIGRlZmF1bHQgKi8NCj4gKwkJc2xlZXBfcGFyc1szXSA9ICh1bnNp Z25lZCBjaGFyKSFoNC0+cGFycy5idF93YWtlX2FjdGl2ZV9sb3c7DQo+ICsJCXNsZWVwX3BhcnNb NF0gPSAodW5zaWduZWQgY2hhcikhaDQtPnBhcnMuZGV2X3dha2VfYWN0aXZlX2xvdzsNCj4gKwkJ c2tiID0gX19oY2lfY21kX3N5bmMoaHUtPmhkZXYsIDB4ZmMyNywgc2l6ZW9mKHNsZWVwX3BhcnMp LA0KPiArCQkJCSAgICAgc2xlZXBfcGFycywgSENJX0lOSVRfVElNRU9VVCk7DQo+ICsJCWlmIChJ U19FUlIoc2tiKSkgew0KPiArCQkJc3RhdHVzID0gUFRSX0VSUihza2IpOw0KPiArCQkJQlRfRVJS KCJiY21faDRfc2V0dXAgU2xlZXAgVlNDIGZhaWxlZCAoJWQpIiwgc3RhdHVzKTsNCj4gKwkJCXJl dHVybiBzdGF0dXM7DQo+ICsJCX0NCj4gKwkJa2ZyZWVfc2tiKHNrYik7DQo+ICsJCUJUX0RCRygi YmNtX2g0X3NldHVwIFNldCBTbGVlcCBQYXJhbWV0ZXJzIFZTQyBzdWNjZWVkZWQiKTsNCj4gKwl9 DQo+ICsNCj4gKwlyZXR1cm4gMDsNCj4gK30NCj4gKw0KPiArLyoNCj4gKyAqIFByb3RvY29sIGNh bGxiYWNrcw0KPiArICovDQo+ICtzdGF0aWMgc3RydWN0IGhjaV91YXJ0X3Byb3RvIGg0cCA9IHsN Cg0KS2VlcCB0aGlzIGFzIGJjbV9wcm90by4NCg0KSUY6IFJlc3RvcmVkLg0KDQo+IAkuaWQJCT0g SENJX1VBUlRfQkNNLA0KPiAtCS5uYW1lCQk9ICJCQ00iLA0KPiAtCS5vcGVuCQk9IGJjbV9vcGVu LA0KPiAtCS5jbG9zZQkJPSBiY21fY2xvc2UsDQo+IC0JLmZsdXNoCQk9IGJjbV9mbHVzaCwNCj4g LQkuc2V0dXAJCT0gYmNtX3NldHVwLA0KPiAtCS5yZWN2CQk9IGJjbV9yZWN2LA0KPiAtCS5lbnF1 ZXVlCT0gYmNtX2VucXVldWUsDQo+IC0JLmRlcXVldWUJPSBiY21fZGVxdWV1ZSwNCj4gKwkubmFt ZQkJPSAiVUFSVEJDTeKAnSwNCg0KUGxlYXNlIHN0b3AgcmVuYW1pbmcgdGhpbmdzLiBUaGlzIGlz IGEgVUFSVCBkcml2ZXIgYW5kIHRodXMgbm8gbmVlZCB0byByZXBlYXQgdGhhdC4NCg0KSUY6IFJl c3RvcmVkLiBBZ2FpbiwgSSB3YXMgbm90IHJlbmFtaW5nIGFueXRoaW5nOiBJIHdyb3RlIGl0IGZp cnN0IGJlZm9yZSB5b3UuDQoNCj4gKwkub3BlbgkJPSBiY21faDRfb3BlbiwNCj4gKwkuY2xvc2UJ CT0gYmNtX2g0X2Nsb3NlLA0KPiArCS5mbHVzaAkJPSBiY21faDRfZmx1c2gsDQo+ICsJLnNldHVw CQk9IGJjbV9oNF9zZXR1cCwNCj4gKwkucmVjdgkJPSBiY21faDRfcmVjdiwNCj4gKwkuZW5xdWV1 ZQk9IGJjbV9oNF9lbnF1ZXVlLA0KPiArCS5kZXF1ZXVlCT0gYmNtX2g0X2RlcXVldWUsDQo+IH07 DQo+IA0KPiArLyoNCj4gKyAqIFByb3RvY29sIGluaXQNCj4gKyAqLw0KPiBpbnQgX19pbml0IGJj bV9pbml0KHZvaWQpDQo+IHsNCj4gLQlyZXR1cm4gaGNpX3VhcnRfcmVnaXN0ZXJfcHJvdG8oJmJj bV9wcm90byk7DQo+ICsJaW50IHN0YXR1cyA9IGhjaV91YXJ0X3JlZ2lzdGVyX3Byb3RvKCZoNHAp Ow0KPiArDQo+ICsJaWYgKCFzdGF0dXMpDQo+ICsJCUJUX0lORk8oIkJyb2FkY29tIEg0IHByb3Rv Y29sIGluaXRpYWxpemVkIik7DQo+ICsJZWxzZQ0KPiArCQlCVF9FUlIoIkJyb2FkY29tIEg0IHBy b3RvY29sIHJlZ2lzdHJhdGlvbiBmYWlsZWQgJWQiLCBzdGF0dXMpOw0KPiArDQo+ICsJcmV0dXJu IHN0YXR1czsNCg0KSSBtb3ZlIHRoaXMgZXJyb3IgcHJpbnRpbmcgaW50byBnZW5lcmljIGNvZGUg YW5kIHNvIHBsZWFzZSBkbyBub3QgbW9kaWZ5IHRoaXMgYW5kIHJldmVydCB3aGF0IEkgZGlkLg0K DQpJRjogRG9uZS4NCg0KPiB9DQo+IA0KPiArLyoNCj4gKyAqIFByb3RvY29sIHNodXRkb3duDQo+ ICsgKi8NCj4gaW50IF9fZXhpdCBiY21fZGVpbml0KHZvaWQpDQo+IHsNCj4gLQlyZXR1cm4gaGNp X3VhcnRfdW5yZWdpc3Rlcl9wcm90bygmYmNtX3Byb3RvKTsNCj4gKwlCVF9JTkZPKCJCcm9hZGNv bSBINCBwcm90b2NvbCBkZS1pbml0aWFsaXplZCIpOw0KPiArCXJldHVybiBoY2lfdWFydF91bnJl Z2lzdGVyX3Byb3RvKCZoNHApOw0KPiB9DQo+ICsNCg0KTm8gZXh0cmEgZW1wdHkgbGluZSBhdCB0 aGUgZW5kIG9mIGEgZmlsZS4NCg0KSUY6IFJlbW92ZWQuDQoNClJlZ2FyZHMNCg0KTWFyY2VsDQoN Cg== ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2015-05-13 21:50 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-05-07 20:25 [RFC 0/2] *** Broadcom Bluetooth UART Driver *** Ilya Faenson 2015-05-07 20:25 ` [RFC 1/2] Bluetooth UART Device Tree bindings Ilya Faenson 2015-05-11 19:14 ` Marcel Holtmann 2015-05-07 20:25 ` [RFC 2/2] Broadcom Bluetooth UART device driver Ilya Faenson 2015-05-11 19:03 ` Marcel Holtmann 2015-05-13 21:50 ` Ilya Faenson
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).