commit: f87a31d460efa048fccfc9735ab3390cf52db806 Author: Mike Pagano <mpagano <AT> gentoo <DOT> org> AuthorDate: Sat Apr 20 11:05:45 2019 +0000 Commit: Mike Pagano <mpagano <AT> gentoo <DOT> org> CommitDate: Sat Apr 20 11:05:45 2019 +0000 URL: https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=f87a31d4
Linux patch 4.9.170 Signed-off-by: Mike Pagano <mpagano <AT> gentoo.org> 0000_README | 4 + 1169_linux-4.9.170.patch | 4521 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 4525 insertions(+) diff --git a/0000_README b/0000_README index 3f7c1b9..ea31894 100644 --- a/0000_README +++ b/0000_README @@ -719,6 +719,10 @@ Patch: 1168_linux-4.9.169.patch From: http://www.kernel.org Desc: Linux 4.9.169 +Patch: 1169_linux-4.9.170.patch +From: http://www.kernel.org +Desc: Linux 4.9.170 + Patch: 1500_XATTR_USER_PREFIX.patch From: https://bugs.gentoo.org/show_bug.cgi?id=470644 Desc: Support for namespace user.pax.* on tmpfs. diff --git a/1169_linux-4.9.170.patch b/1169_linux-4.9.170.patch new file mode 100644 index 0000000..f6f1930 --- /dev/null +++ b/1169_linux-4.9.170.patch @@ -0,0 +1,4521 @@ +diff --git a/Makefile b/Makefile +index 23cc23c47adf..966069dab768 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 4 + PATCHLEVEL = 9 +-SUBLEVEL = 169 ++SUBLEVEL = 170 + EXTRAVERSION = + NAME = Roaring Lionus + +diff --git a/arch/arc/kernel/head.S b/arch/arc/kernel/head.S +index 1f945d0f40da..208bf2c9e7b0 100644 +--- a/arch/arc/kernel/head.S ++++ b/arch/arc/kernel/head.S +@@ -107,6 +107,7 @@ ENTRY(stext) + ; r2 = pointer to uboot provided cmdline or external DTB in mem + ; These are handled later in handle_uboot_args() + st r0, [@uboot_tag] ++ st r1, [@uboot_magic] + st r2, [@uboot_arg] + #endif + +diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c +index 9119bea503a7..9f96120eee6e 100644 +--- a/arch/arc/kernel/setup.c ++++ b/arch/arc/kernel/setup.c +@@ -32,6 +32,7 @@ unsigned int intr_to_DE_cnt; + + /* Part of U-boot ABI: see head.S */ + int __initdata uboot_tag; ++int __initdata uboot_magic; + char __initdata *uboot_arg; + + const struct machine_desc *machine_desc; +@@ -400,6 +401,8 @@ static inline bool uboot_arg_invalid(unsigned long addr) + #define UBOOT_TAG_NONE 0 + #define UBOOT_TAG_CMDLINE 1 + #define UBOOT_TAG_DTB 2 ++/* We always pass 0 as magic from U-boot */ ++#define UBOOT_MAGIC_VALUE 0 + + void __init handle_uboot_args(void) + { +@@ -415,6 +418,11 @@ void __init handle_uboot_args(void) + goto ignore_uboot_args; + } + ++ if (uboot_magic != UBOOT_MAGIC_VALUE) { ++ pr_warn(IGNORE_ARGS "non zero uboot magic\n"); ++ goto ignore_uboot_args; ++ } ++ + if (uboot_tag != UBOOT_TAG_NONE && + uboot_arg_invalid((unsigned long)uboot_arg)) { + pr_warn(IGNORE_ARGS "invalid uboot arg: '%px'\n", uboot_arg); +diff --git a/arch/arm/crypto/sha256-armv4.pl b/arch/arm/crypto/sha256-armv4.pl +index fac0533ea633..f64e8413ab9a 100644 +--- a/arch/arm/crypto/sha256-armv4.pl ++++ b/arch/arm/crypto/sha256-armv4.pl +@@ -205,10 +205,11 @@ K256: + .global sha256_block_data_order + .type sha256_block_data_order,%function + sha256_block_data_order: ++.Lsha256_block_data_order: + #if __ARM_ARCH__<7 + sub r3,pc,#8 @ sha256_block_data_order + #else +- adr r3,sha256_block_data_order ++ adr r3,.Lsha256_block_data_order + #endif + #if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) + ldr r12,.LOPENSSL_armcap +diff --git a/arch/arm/crypto/sha256-core.S_shipped b/arch/arm/crypto/sha256-core.S_shipped +index 555a1a8eec90..72c248081d27 100644 +--- a/arch/arm/crypto/sha256-core.S_shipped ++++ b/arch/arm/crypto/sha256-core.S_shipped +@@ -86,10 +86,11 @@ K256: + .global sha256_block_data_order + .type sha256_block_data_order,%function + sha256_block_data_order: ++.Lsha256_block_data_order: + #if __ARM_ARCH__<7 + sub r3,pc,#8 @ sha256_block_data_order + #else +- adr r3,sha256_block_data_order ++ adr r3,.Lsha256_block_data_order + #endif + #if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) + ldr r12,.LOPENSSL_armcap +diff --git a/arch/arm/crypto/sha512-armv4.pl b/arch/arm/crypto/sha512-armv4.pl +index a2b11a844357..5fe336420bcf 100644 +--- a/arch/arm/crypto/sha512-armv4.pl ++++ b/arch/arm/crypto/sha512-armv4.pl +@@ -267,10 +267,11 @@ WORD64(0x5fcb6fab,0x3ad6faec, 0x6c44198c,0x4a475817) + .global sha512_block_data_order + .type sha512_block_data_order,%function + sha512_block_data_order: ++.Lsha512_block_data_order: + #if __ARM_ARCH__<7 + sub r3,pc,#8 @ sha512_block_data_order + #else +- adr r3,sha512_block_data_order ++ adr r3,.Lsha512_block_data_order + #endif + #if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) + ldr r12,.LOPENSSL_armcap +diff --git a/arch/arm/crypto/sha512-core.S_shipped b/arch/arm/crypto/sha512-core.S_shipped +index 3694c4d4ca2b..de9bd7f55242 100644 +--- a/arch/arm/crypto/sha512-core.S_shipped ++++ b/arch/arm/crypto/sha512-core.S_shipped +@@ -134,10 +134,11 @@ WORD64(0x5fcb6fab,0x3ad6faec, 0x6c44198c,0x4a475817) + .global sha512_block_data_order + .type sha512_block_data_order,%function + sha512_block_data_order: ++.Lsha512_block_data_order: + #if __ARM_ARCH__<7 + sub r3,pc,#8 @ sha512_block_data_order + #else +- adr r3,sha512_block_data_order ++ adr r3,.Lsha512_block_data_order + #endif + #if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) + ldr r12,.LOPENSSL_armcap +diff --git a/arch/arm/kernel/patch.c b/arch/arm/kernel/patch.c +index 69bda1a5707e..1f665acaa6a9 100644 +--- a/arch/arm/kernel/patch.c ++++ b/arch/arm/kernel/patch.c +@@ -15,7 +15,7 @@ struct patch { + unsigned int insn; + }; + +-static DEFINE_SPINLOCK(patch_lock); ++static DEFINE_RAW_SPINLOCK(patch_lock); + + static void __kprobes *patch_map(void *addr, int fixmap, unsigned long *flags) + __acquires(&patch_lock) +@@ -32,7 +32,7 @@ static void __kprobes *patch_map(void *addr, int fixmap, unsigned long *flags) + return addr; + + if (flags) +- spin_lock_irqsave(&patch_lock, *flags); ++ raw_spin_lock_irqsave(&patch_lock, *flags); + else + __acquire(&patch_lock); + +@@ -47,7 +47,7 @@ static void __kprobes patch_unmap(int fixmap, unsigned long *flags) + clear_fixmap(fixmap); + + if (flags) +- spin_unlock_irqrestore(&patch_lock, *flags); ++ raw_spin_unlock_irqrestore(&patch_lock, *flags); + else + __release(&patch_lock); + } +diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig +index e8229b9fee4a..3265b8f86069 100644 +--- a/arch/arm/plat-samsung/Kconfig ++++ b/arch/arm/plat-samsung/Kconfig +@@ -258,7 +258,7 @@ config S3C_PM_DEBUG_LED_SMDK + + config SAMSUNG_PM_CHECK + bool "S3C2410 PM Suspend Memory CRC" +- depends on PM ++ depends on PM && (PLAT_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210) + select CRC32 + help + Enable the PM code's memory area checksum over sleep. This option +diff --git a/arch/x86/kernel/cpu/cyrix.c b/arch/x86/kernel/cpu/cyrix.c +index d39cfb2c6b63..311d0fad17e6 100644 +--- a/arch/x86/kernel/cpu/cyrix.c ++++ b/arch/x86/kernel/cpu/cyrix.c +@@ -121,7 +121,7 @@ static void set_cx86_reorder(void) + setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ + + /* Load/Store Serialize to mem access disable (=reorder it) */ +- setCx86_old(CX86_PCR0, getCx86_old(CX86_PCR0) & ~0x80); ++ setCx86(CX86_PCR0, getCx86(CX86_PCR0) & ~0x80); + /* set load/store serialize from 1GB to 4GB */ + ccr3 |= 0xe0; + setCx86(CX86_CCR3, ccr3); +@@ -132,11 +132,11 @@ static void set_cx86_memwb(void) + pr_info("Enable Memory-Write-back mode on Cyrix/NSC processor.\n"); + + /* CCR2 bit 2: unlock NW bit */ +- setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) & ~0x04); ++ setCx86(CX86_CCR2, getCx86(CX86_CCR2) & ~0x04); + /* set 'Not Write-through' */ + write_cr0(read_cr0() | X86_CR0_NW); + /* CCR2 bit 2: lock NW bit and set WT1 */ +- setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) | 0x14); ++ setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x14); + } + + /* +@@ -150,14 +150,14 @@ static void geode_configure(void) + local_irq_save(flags); + + /* Suspend on halt power saving and enable #SUSP pin */ +- setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) | 0x88); ++ setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x88); + + ccr3 = getCx86(CX86_CCR3); + setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ + + + /* FPU fast, DTE cache, Mem bypass */ +- setCx86_old(CX86_CCR4, getCx86_old(CX86_CCR4) | 0x38); ++ setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x38); + setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ + + set_cx86_memwb(); +@@ -293,7 +293,7 @@ static void init_cyrix(struct cpuinfo_x86 *c) + /* GXm supports extended cpuid levels 'ala' AMD */ + if (c->cpuid_level == 2) { + /* Enable cxMMX extensions (GX1 Datasheet 54) */ +- setCx86_old(CX86_CCR7, getCx86_old(CX86_CCR7) | 1); ++ setCx86(CX86_CCR7, getCx86(CX86_CCR7) | 1); + + /* + * GXm : 0x30 ... 0x5f GXm datasheet 51 +@@ -316,7 +316,7 @@ static void init_cyrix(struct cpuinfo_x86 *c) + if (dir1 > 7) { + dir0_msn++; /* M II */ + /* Enable MMX extensions (App note 108) */ +- setCx86_old(CX86_CCR7, getCx86_old(CX86_CCR7)|1); ++ setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1); + } else { + /* A 6x86MX - it has the bug. */ + set_cpu_bug(c, X86_BUG_COMA); +diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c +index 756634f14df6..775c23d4021a 100644 +--- a/arch/x86/kernel/hpet.c ++++ b/arch/x86/kernel/hpet.c +@@ -914,6 +914,8 @@ int __init hpet_enable(void) + return 0; + + hpet_set_mapping(); ++ if (!hpet_virt_address) ++ return 0; + + /* + * Read the period and check for a sane value: +diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c +index 8771766d46b6..9954a604a822 100644 +--- a/arch/x86/kernel/hw_breakpoint.c ++++ b/arch/x86/kernel/hw_breakpoint.c +@@ -352,6 +352,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) + #endif + default: + WARN_ON_ONCE(1); ++ return -EINVAL; + } + + /* +diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c +index ad0b13ad4bbb..4a76000bcf7a 100644 +--- a/drivers/acpi/sbs.c ++++ b/drivers/acpi/sbs.c +@@ -443,9 +443,13 @@ static int acpi_ac_get_present(struct acpi_sbs *sbs) + + /* + * The spec requires that bit 4 always be 1. If it's not set, assume +- * that the implementation doesn't support an SBS charger ++ * that the implementation doesn't support an SBS charger. ++ * ++ * And on some MacBooks a status of 0xffff is always returned, no ++ * matter whether the charger is plugged in or not, which is also ++ * wrong, so ignore the SBS charger for those too. + */ +- if (!((status >> 4) & 0x1)) ++ if (!((status >> 4) & 0x1) || status == 0xffff) + return -ENODEV; + + sbs->charger_present = (status >> 15) & 0x1; +diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c +index fa0f66809503..d29f78441cdb 100644 +--- a/drivers/char/tpm/tpm_crb.c ++++ b/drivers/char/tpm/tpm_crb.c +@@ -102,19 +102,29 @@ static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count) + struct crb_priv *priv = dev_get_drvdata(&chip->dev); + unsigned int expected; + +- /* sanity check */ +- if (count < 6) ++ /* A sanity check that the upper layer wants to get at least the header ++ * as that is the minimum size for any TPM response. ++ */ ++ if (count < TPM_HEADER_SIZE) + return -EIO; + ++ /* If this bit is set, according to the spec, the TPM is in ++ * unrecoverable condition. ++ */ + if (ioread32(&priv->cca->sts) & CRB_CTRL_STS_ERROR) + return -EIO; + +- memcpy_fromio(buf, priv->rsp, 6); +- expected = be32_to_cpup((__be32 *) &buf[2]); +- if (expected > count || expected < 6) ++ /* Read the first 8 bytes in order to get the length of the response. ++ * We read exactly a quad word in order to make sure that the remaining ++ * reads will be aligned. ++ */ ++ memcpy_fromio(buf, priv->rsp, 8); ++ ++ expected = be32_to_cpup((__be32 *)&buf[2]); ++ if (expected > count || expected < TPM_HEADER_SIZE) + return -EIO; + +- memcpy_fromio(&buf[6], &priv->rsp[6], expected - 6); ++ memcpy_fromio(&buf[8], &priv->rsp[8], expected - 8); + + return expected; + } +diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c +index 7a6305884f97..32d22bdf7164 100644 +--- a/drivers/gpio/gpio-pxa.c ++++ b/drivers/gpio/gpio-pxa.c +@@ -774,6 +774,9 @@ static int pxa_gpio_suspend(void) + struct pxa_gpio_bank *c; + int gpio; + ++ if (!pchip) ++ return 0; ++ + for_each_gpio_bank(gpio, c, pchip) { + c->saved_gplr = readl_relaxed(c->regbase + GPLR_OFFSET); + c->saved_gpdr = readl_relaxed(c->regbase + GPDR_OFFSET); +@@ -792,6 +795,9 @@ static void pxa_gpio_resume(void) + struct pxa_gpio_bank *c; + int gpio; + ++ if (!pchip) ++ return; ++ + for_each_gpio_bank(gpio, c, pchip) { + /* restore level with set/clear */ + writel_relaxed(c->saved_gplr, c->regbase + GPSR_OFFSET); +diff --git a/drivers/hid/i2c-hid/Makefile b/drivers/hid/i2c-hid/Makefile +index 832d8f9aaba2..099e1ce2f234 100644 +--- a/drivers/hid/i2c-hid/Makefile ++++ b/drivers/hid/i2c-hid/Makefile +@@ -3,3 +3,6 @@ + # + + obj-$(CONFIG_I2C_HID) += i2c-hid.o ++ ++i2c-hid-objs = i2c-hid-core.o ++i2c-hid-$(CONFIG_DMI) += i2c-hid-dmi-quirks.o +diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c +new file mode 100644 +index 000000000000..850527d5fab1 +--- /dev/null ++++ b/drivers/hid/i2c-hid/i2c-hid-core.c +@@ -0,0 +1,1359 @@ ++/* ++ * HID over I2C protocol implementation ++ * ++ * Copyright (c) 2012 Benjamin Tissoires <benjamin.tissoi...@gmail.com> ++ * Copyright (c) 2012 Ecole Nationale de l'Aviation Civile, France ++ * Copyright (c) 2012 Red Hat, Inc ++ * ++ * This code is partly based on "USB HID support for Linux": ++ * ++ * Copyright (c) 1999 Andreas Gal ++ * Copyright (c) 2000-2005 Vojtech Pavlik <vojt...@suse.cz> ++ * Copyright (c) 2005 Michael Haboustak <mi...@cinci.rr.com> for Concept2, Inc ++ * Copyright (c) 2007-2008 Oliver Neukum ++ * Copyright (c) 2006-2010 Jiri Kosina ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ */ ++ ++#include <linux/module.h> ++#include <linux/i2c.h> ++#include <linux/interrupt.h> ++#include <linux/input.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/pm.h> ++#include <linux/pm_runtime.h> ++#include <linux/device.h> ++#include <linux/wait.h> ++#include <linux/err.h> ++#include <linux/string.h> ++#include <linux/list.h> ++#include <linux/jiffies.h> ++#include <linux/kernel.h> ++#include <linux/hid.h> ++#include <linux/mutex.h> ++#include <linux/acpi.h> ++#include <linux/of.h> ++#include <linux/gpio/consumer.h> ++ ++#include <linux/i2c/i2c-hid.h> ++ ++#include "../hid-ids.h" ++#include "i2c-hid.h" ++ ++/* quirks to control the device */ ++#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0) ++ ++/* flags */ ++#define I2C_HID_STARTED 0 ++#define I2C_HID_RESET_PENDING 1 ++#define I2C_HID_READ_PENDING 2 ++ ++#define I2C_HID_PWR_ON 0x00 ++#define I2C_HID_PWR_SLEEP 0x01 ++ ++/* debug option */ ++static bool debug; ++module_param(debug, bool, 0444); ++MODULE_PARM_DESC(debug, "print a lot of debug information"); ++ ++#define i2c_hid_dbg(ihid, fmt, arg...) \ ++do { \ ++ if (debug) \ ++ dev_printk(KERN_DEBUG, &(ihid)->client->dev, fmt, ##arg); \ ++} while (0) ++ ++struct i2c_hid_desc { ++ __le16 wHIDDescLength; ++ __le16 bcdVersion; ++ __le16 wReportDescLength; ++ __le16 wReportDescRegister; ++ __le16 wInputRegister; ++ __le16 wMaxInputLength; ++ __le16 wOutputRegister; ++ __le16 wMaxOutputLength; ++ __le16 wCommandRegister; ++ __le16 wDataRegister; ++ __le16 wVendorID; ++ __le16 wProductID; ++ __le16 wVersionID; ++ __le32 reserved; ++} __packed; ++ ++struct i2c_hid_cmd { ++ unsigned int registerIndex; ++ __u8 opcode; ++ unsigned int length; ++ bool wait; ++}; ++ ++union command { ++ u8 data[0]; ++ struct cmd { ++ __le16 reg; ++ __u8 reportTypeID; ++ __u8 opcode; ++ } __packed c; ++}; ++ ++#define I2C_HID_CMD(opcode_) \ ++ .opcode = opcode_, .length = 4, \ ++ .registerIndex = offsetof(struct i2c_hid_desc, wCommandRegister) ++ ++/* fetch HID descriptor */ ++static const struct i2c_hid_cmd hid_descr_cmd = { .length = 2 }; ++/* fetch report descriptors */ ++static const struct i2c_hid_cmd hid_report_descr_cmd = { ++ .registerIndex = offsetof(struct i2c_hid_desc, ++ wReportDescRegister), ++ .opcode = 0x00, ++ .length = 2 }; ++/* commands */ ++static const struct i2c_hid_cmd hid_reset_cmd = { I2C_HID_CMD(0x01), ++ .wait = true }; ++static const struct i2c_hid_cmd hid_get_report_cmd = { I2C_HID_CMD(0x02) }; ++static const struct i2c_hid_cmd hid_set_report_cmd = { I2C_HID_CMD(0x03) }; ++static const struct i2c_hid_cmd hid_set_power_cmd = { I2C_HID_CMD(0x08) }; ++static const struct i2c_hid_cmd hid_no_cmd = { .length = 0 }; ++ ++/* ++ * These definitions are not used here, but are defined by the spec. ++ * Keeping them here for documentation purposes. ++ * ++ * static const struct i2c_hid_cmd hid_get_idle_cmd = { I2C_HID_CMD(0x04) }; ++ * static const struct i2c_hid_cmd hid_set_idle_cmd = { I2C_HID_CMD(0x05) }; ++ * static const struct i2c_hid_cmd hid_get_protocol_cmd = { I2C_HID_CMD(0x06) }; ++ * static const struct i2c_hid_cmd hid_set_protocol_cmd = { I2C_HID_CMD(0x07) }; ++ */ ++ ++static DEFINE_MUTEX(i2c_hid_open_mut); ++ ++/* The main device structure */ ++struct i2c_hid { ++ struct i2c_client *client; /* i2c client */ ++ struct hid_device *hid; /* pointer to corresponding HID dev */ ++ union { ++ __u8 hdesc_buffer[sizeof(struct i2c_hid_desc)]; ++ struct i2c_hid_desc hdesc; /* the HID Descriptor */ ++ }; ++ __le16 wHIDDescRegister; /* location of the i2c ++ * register of the HID ++ * descriptor. */ ++ unsigned int bufsize; /* i2c buffer size */ ++ u8 *inbuf; /* Input buffer */ ++ u8 *rawbuf; /* Raw Input buffer */ ++ u8 *cmdbuf; /* Command buffer */ ++ u8 *argsbuf; /* Command arguments buffer */ ++ ++ unsigned long flags; /* device flags */ ++ unsigned long quirks; /* Various quirks */ ++ ++ wait_queue_head_t wait; /* For waiting the interrupt */ ++ struct gpio_desc *desc; ++ int irq; ++ ++ struct i2c_hid_platform_data pdata; ++ ++ bool irq_wake_enabled; ++ struct mutex reset_lock; ++}; ++ ++static const struct i2c_hid_quirks { ++ __u16 idVendor; ++ __u16 idProduct; ++ __u32 quirks; ++} i2c_hid_quirks[] = { ++ { USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8752, ++ I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV }, ++ { USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8755, ++ I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV }, ++ { 0, 0 } ++}; ++ ++/* ++ * i2c_hid_lookup_quirk: return any quirks associated with a I2C HID device ++ * @idVendor: the 16-bit vendor ID ++ * @idProduct: the 16-bit product ID ++ * ++ * Returns: a u32 quirks value. ++ */ ++static u32 i2c_hid_lookup_quirk(const u16 idVendor, const u16 idProduct) ++{ ++ u32 quirks = 0; ++ int n; ++ ++ for (n = 0; i2c_hid_quirks[n].idVendor; n++) ++ if (i2c_hid_quirks[n].idVendor == idVendor && ++ (i2c_hid_quirks[n].idProduct == (__u16)HID_ANY_ID || ++ i2c_hid_quirks[n].idProduct == idProduct)) ++ quirks = i2c_hid_quirks[n].quirks; ++ ++ return quirks; ++} ++ ++static int __i2c_hid_command(struct i2c_client *client, ++ const struct i2c_hid_cmd *command, u8 reportID, ++ u8 reportType, u8 *args, int args_len, ++ unsigned char *buf_recv, int data_len) ++{ ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ union command *cmd = (union command *)ihid->cmdbuf; ++ int ret; ++ struct i2c_msg msg[2]; ++ int msg_num = 1; ++ ++ int length = command->length; ++ bool wait = command->wait; ++ unsigned int registerIndex = command->registerIndex; ++ ++ /* special case for hid_descr_cmd */ ++ if (command == &hid_descr_cmd) { ++ cmd->c.reg = ihid->wHIDDescRegister; ++ } else { ++ cmd->data[0] = ihid->hdesc_buffer[registerIndex]; ++ cmd->data[1] = ihid->hdesc_buffer[registerIndex + 1]; ++ } ++ ++ if (length > 2) { ++ cmd->c.opcode = command->opcode; ++ cmd->c.reportTypeID = reportID | reportType << 4; ++ } ++ ++ memcpy(cmd->data + length, args, args_len); ++ length += args_len; ++ ++ i2c_hid_dbg(ihid, "%s: cmd=%*ph\n", __func__, length, cmd->data); ++ ++ msg[0].addr = client->addr; ++ msg[0].flags = client->flags & I2C_M_TEN; ++ msg[0].len = length; ++ msg[0].buf = cmd->data; ++ if (data_len > 0) { ++ msg[1].addr = client->addr; ++ msg[1].flags = client->flags & I2C_M_TEN; ++ msg[1].flags |= I2C_M_RD; ++ msg[1].len = data_len; ++ msg[1].buf = buf_recv; ++ msg_num = 2; ++ set_bit(I2C_HID_READ_PENDING, &ihid->flags); ++ } ++ ++ if (wait) ++ set_bit(I2C_HID_RESET_PENDING, &ihid->flags); ++ ++ ret = i2c_transfer(client->adapter, msg, msg_num); ++ ++ if (data_len > 0) ++ clear_bit(I2C_HID_READ_PENDING, &ihid->flags); ++ ++ if (ret != msg_num) ++ return ret < 0 ? ret : -EIO; ++ ++ ret = 0; ++ ++ if (wait) { ++ i2c_hid_dbg(ihid, "%s: waiting...\n", __func__); ++ if (!wait_event_timeout(ihid->wait, ++ !test_bit(I2C_HID_RESET_PENDING, &ihid->flags), ++ msecs_to_jiffies(5000))) ++ ret = -ENODATA; ++ i2c_hid_dbg(ihid, "%s: finished.\n", __func__); ++ } ++ ++ return ret; ++} ++ ++static int i2c_hid_command(struct i2c_client *client, ++ const struct i2c_hid_cmd *command, ++ unsigned char *buf_recv, int data_len) ++{ ++ return __i2c_hid_command(client, command, 0, 0, NULL, 0, ++ buf_recv, data_len); ++} ++ ++static int i2c_hid_get_report(struct i2c_client *client, u8 reportType, ++ u8 reportID, unsigned char *buf_recv, int data_len) ++{ ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ u8 args[3]; ++ int ret; ++ int args_len = 0; ++ u16 readRegister = le16_to_cpu(ihid->hdesc.wDataRegister); ++ ++ i2c_hid_dbg(ihid, "%s\n", __func__); ++ ++ if (reportID >= 0x0F) { ++ args[args_len++] = reportID; ++ reportID = 0x0F; ++ } ++ ++ args[args_len++] = readRegister & 0xFF; ++ args[args_len++] = readRegister >> 8; ++ ++ ret = __i2c_hid_command(client, &hid_get_report_cmd, reportID, ++ reportType, args, args_len, buf_recv, data_len); ++ if (ret) { ++ dev_err(&client->dev, ++ "failed to retrieve report from device.\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/** ++ * i2c_hid_set_or_send_report: forward an incoming report to the device ++ * @client: the i2c_client of the device ++ * @reportType: 0x03 for HID_FEATURE_REPORT ; 0x02 for HID_OUTPUT_REPORT ++ * @reportID: the report ID ++ * @buf: the actual data to transfer, without the report ID ++ * @len: size of buf ++ * @use_data: true: use SET_REPORT HID command, false: send plain OUTPUT report ++ */ ++static int i2c_hid_set_or_send_report(struct i2c_client *client, u8 reportType, ++ u8 reportID, unsigned char *buf, size_t data_len, bool use_data) ++{ ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ u8 *args = ihid->argsbuf; ++ const struct i2c_hid_cmd *hidcmd; ++ int ret; ++ u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister); ++ u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister); ++ u16 maxOutputLength = le16_to_cpu(ihid->hdesc.wMaxOutputLength); ++ u16 size; ++ int args_len; ++ int index = 0; ++ ++ i2c_hid_dbg(ihid, "%s\n", __func__); ++ ++ if (data_len > ihid->bufsize) ++ return -EINVAL; ++ ++ size = 2 /* size */ + ++ (reportID ? 1 : 0) /* reportID */ + ++ data_len /* buf */; ++ args_len = (reportID >= 0x0F ? 1 : 0) /* optional third byte */ + ++ 2 /* dataRegister */ + ++ size /* args */; ++ ++ if (!use_data && maxOutputLength == 0) ++ return -ENOSYS; ++ ++ if (reportID >= 0x0F) { ++ args[index++] = reportID; ++ reportID = 0x0F; ++ } ++ ++ /* ++ * use the data register for feature reports or if the device does not ++ * support the output register ++ */ ++ if (use_data) { ++ args[index++] = dataRegister & 0xFF; ++ args[index++] = dataRegister >> 8; ++ hidcmd = &hid_set_report_cmd; ++ } else { ++ args[index++] = outputRegister & 0xFF; ++ args[index++] = outputRegister >> 8; ++ hidcmd = &hid_no_cmd; ++ } ++ ++ args[index++] = size & 0xFF; ++ args[index++] = size >> 8; ++ ++ if (reportID) ++ args[index++] = reportID; ++ ++ memcpy(&args[index], buf, data_len); ++ ++ ret = __i2c_hid_command(client, hidcmd, reportID, ++ reportType, args, args_len, NULL, 0); ++ if (ret) { ++ dev_err(&client->dev, "failed to set a report to device.\n"); ++ return ret; ++ } ++ ++ return data_len; ++} ++ ++static int i2c_hid_set_power(struct i2c_client *client, int power_state) ++{ ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ int ret; ++ ++ i2c_hid_dbg(ihid, "%s\n", __func__); ++ ++ /* ++ * Some devices require to send a command to wakeup before power on. ++ * The call will get a return value (EREMOTEIO) but device will be ++ * triggered and activated. After that, it goes like a normal device. ++ */ ++ if (power_state == I2C_HID_PWR_ON && ++ ihid->quirks & I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV) { ++ ret = i2c_hid_command(client, &hid_set_power_cmd, NULL, 0); ++ ++ /* Device was already activated */ ++ if (!ret) ++ goto set_pwr_exit; ++ } ++ ++ ret = __i2c_hid_command(client, &hid_set_power_cmd, power_state, ++ 0, NULL, 0, NULL, 0); ++ ++ if (ret) ++ dev_err(&client->dev, "failed to change power setting.\n"); ++ ++set_pwr_exit: ++ return ret; ++} ++ ++static int i2c_hid_hwreset(struct i2c_client *client) ++{ ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ int ret; ++ ++ i2c_hid_dbg(ihid, "%s\n", __func__); ++ ++ /* ++ * This prevents sending feature reports while the device is ++ * being reset. Otherwise we may lose the reset complete ++ * interrupt. ++ */ ++ mutex_lock(&ihid->reset_lock); ++ ++ ret = i2c_hid_set_power(client, I2C_HID_PWR_ON); ++ if (ret) ++ goto out_unlock; ++ ++ /* ++ * The HID over I2C specification states that if a DEVICE needs time ++ * after the PWR_ON request, it should utilise CLOCK stretching. ++ * However, it has been observered that the Windows driver provides a ++ * 1ms sleep between the PWR_ON and RESET requests and that some devices ++ * rely on this. ++ */ ++ usleep_range(1000, 5000); ++ ++ i2c_hid_dbg(ihid, "resetting...\n"); ++ ++ ret = i2c_hid_command(client, &hid_reset_cmd, NULL, 0); ++ if (ret) { ++ dev_err(&client->dev, "failed to reset device.\n"); ++ i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); ++ } ++ ++out_unlock: ++ mutex_unlock(&ihid->reset_lock); ++ return ret; ++} ++ ++static void i2c_hid_get_input(struct i2c_hid *ihid) ++{ ++ int ret; ++ u32 ret_size; ++ int size = le16_to_cpu(ihid->hdesc.wMaxInputLength); ++ ++ if (size > ihid->bufsize) ++ size = ihid->bufsize; ++ ++ ret = i2c_master_recv(ihid->client, ihid->inbuf, size); ++ if (ret != size) { ++ if (ret < 0) ++ return; ++ ++ dev_err(&ihid->client->dev, "%s: got %d data instead of %d\n", ++ __func__, ret, size); ++ return; ++ } ++ ++ ret_size = ihid->inbuf[0] | ihid->inbuf[1] << 8; ++ ++ if (!ret_size) { ++ /* host or device initiated RESET completed */ ++ if (test_and_clear_bit(I2C_HID_RESET_PENDING, &ihid->flags)) ++ wake_up(&ihid->wait); ++ return; ++ } ++ ++ if ((ret_size > size) || (ret_size < 2)) { ++ dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n", ++ __func__, size, ret_size); ++ return; ++ } ++ ++ i2c_hid_dbg(ihid, "input: %*ph\n", ret_size, ihid->inbuf); ++ ++ if (test_bit(I2C_HID_STARTED, &ihid->flags)) ++ hid_input_report(ihid->hid, HID_INPUT_REPORT, ihid->inbuf + 2, ++ ret_size - 2, 1); ++ ++ return; ++} ++ ++static irqreturn_t i2c_hid_irq(int irq, void *dev_id) ++{ ++ struct i2c_hid *ihid = dev_id; ++ ++ if (test_bit(I2C_HID_READ_PENDING, &ihid->flags)) ++ return IRQ_HANDLED; ++ ++ i2c_hid_get_input(ihid); ++ ++ return IRQ_HANDLED; ++} ++ ++static int i2c_hid_get_report_length(struct hid_report *report) ++{ ++ return ((report->size - 1) >> 3) + 1 + ++ report->device->report_enum[report->type].numbered + 2; ++} ++ ++static void i2c_hid_init_report(struct hid_report *report, u8 *buffer, ++ size_t bufsize) ++{ ++ struct hid_device *hid = report->device; ++ struct i2c_client *client = hid->driver_data; ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ unsigned int size, ret_size; ++ ++ size = i2c_hid_get_report_length(report); ++ if (i2c_hid_get_report(client, ++ report->type == HID_FEATURE_REPORT ? 0x03 : 0x01, ++ report->id, buffer, size)) ++ return; ++ ++ i2c_hid_dbg(ihid, "report (len=%d): %*ph\n", size, size, buffer); ++ ++ ret_size = buffer[0] | (buffer[1] << 8); ++ ++ if (ret_size != size) { ++ dev_err(&client->dev, "error in %s size:%d / ret_size:%d\n", ++ __func__, size, ret_size); ++ return; ++ } ++ ++ /* hid->driver_lock is held as we are in probe function, ++ * we just need to setup the input fields, so using ++ * hid_report_raw_event is safe. */ ++ hid_report_raw_event(hid, report->type, buffer + 2, size - 2, 1); ++} ++ ++/* ++ * Initialize all reports ++ */ ++static void i2c_hid_init_reports(struct hid_device *hid) ++{ ++ struct hid_report *report; ++ struct i2c_client *client = hid->driver_data; ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ u8 *inbuf = kzalloc(ihid->bufsize, GFP_KERNEL); ++ ++ if (!inbuf) { ++ dev_err(&client->dev, "can not retrieve initial reports\n"); ++ return; ++ } ++ ++ /* ++ * The device must be powered on while we fetch initial reports ++ * from it. ++ */ ++ pm_runtime_get_sync(&client->dev); ++ ++ list_for_each_entry(report, ++ &hid->report_enum[HID_FEATURE_REPORT].report_list, list) ++ i2c_hid_init_report(report, inbuf, ihid->bufsize); ++ ++ pm_runtime_put(&client->dev); ++ ++ kfree(inbuf); ++} ++ ++/* ++ * Traverse the supplied list of reports and find the longest ++ */ ++static void i2c_hid_find_max_report(struct hid_device *hid, unsigned int type, ++ unsigned int *max) ++{ ++ struct hid_report *report; ++ unsigned int size; ++ ++ /* We should not rely on wMaxInputLength, as some devices may set it to ++ * a wrong length. */ ++ list_for_each_entry(report, &hid->report_enum[type].report_list, list) { ++ size = i2c_hid_get_report_length(report); ++ if (*max < size) ++ *max = size; ++ } ++} ++ ++static void i2c_hid_free_buffers(struct i2c_hid *ihid) ++{ ++ kfree(ihid->inbuf); ++ kfree(ihid->rawbuf); ++ kfree(ihid->argsbuf); ++ kfree(ihid->cmdbuf); ++ ihid->inbuf = NULL; ++ ihid->rawbuf = NULL; ++ ihid->cmdbuf = NULL; ++ ihid->argsbuf = NULL; ++ ihid->bufsize = 0; ++} ++ ++static int i2c_hid_alloc_buffers(struct i2c_hid *ihid, size_t report_size) ++{ ++ /* the worst case is computed from the set_report command with a ++ * reportID > 15 and the maximum report length */ ++ int args_len = sizeof(__u8) + /* ReportID */ ++ sizeof(__u8) + /* optional ReportID byte */ ++ sizeof(__u16) + /* data register */ ++ sizeof(__u16) + /* size of the report */ ++ report_size; /* report */ ++ ++ ihid->inbuf = kzalloc(report_size, GFP_KERNEL); ++ ihid->rawbuf = kzalloc(report_size, GFP_KERNEL); ++ ihid->argsbuf = kzalloc(args_len, GFP_KERNEL); ++ ihid->cmdbuf = kzalloc(sizeof(union command) + args_len, GFP_KERNEL); ++ ++ if (!ihid->inbuf || !ihid->rawbuf || !ihid->argsbuf || !ihid->cmdbuf) { ++ i2c_hid_free_buffers(ihid); ++ return -ENOMEM; ++ } ++ ++ ihid->bufsize = report_size; ++ ++ return 0; ++} ++ ++static int i2c_hid_get_raw_report(struct hid_device *hid, ++ unsigned char report_number, __u8 *buf, size_t count, ++ unsigned char report_type) ++{ ++ struct i2c_client *client = hid->driver_data; ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ size_t ret_count, ask_count; ++ int ret; ++ ++ if (report_type == HID_OUTPUT_REPORT) ++ return -EINVAL; ++ ++ /* +2 bytes to include the size of the reply in the query buffer */ ++ ask_count = min(count + 2, (size_t)ihid->bufsize); ++ ++ ret = i2c_hid_get_report(client, ++ report_type == HID_FEATURE_REPORT ? 0x03 : 0x01, ++ report_number, ihid->rawbuf, ask_count); ++ ++ if (ret < 0) ++ return ret; ++ ++ ret_count = ihid->rawbuf[0] | (ihid->rawbuf[1] << 8); ++ ++ if (ret_count <= 2) ++ return 0; ++ ++ ret_count = min(ret_count, ask_count); ++ ++ /* The query buffer contains the size, dropping it in the reply */ ++ count = min(count, ret_count - 2); ++ memcpy(buf, ihid->rawbuf + 2, count); ++ ++ return count; ++} ++ ++static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, ++ size_t count, unsigned char report_type, bool use_data) ++{ ++ struct i2c_client *client = hid->driver_data; ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ int report_id = buf[0]; ++ int ret; ++ ++ if (report_type == HID_INPUT_REPORT) ++ return -EINVAL; ++ ++ mutex_lock(&ihid->reset_lock); ++ ++ if (report_id) { ++ buf++; ++ count--; ++ } ++ ++ ret = i2c_hid_set_or_send_report(client, ++ report_type == HID_FEATURE_REPORT ? 0x03 : 0x02, ++ report_id, buf, count, use_data); ++ ++ if (report_id && ret >= 0) ++ ret++; /* add report_id to the number of transfered bytes */ ++ ++ mutex_unlock(&ihid->reset_lock); ++ ++ return ret; ++} ++ ++static int i2c_hid_output_report(struct hid_device *hid, __u8 *buf, ++ size_t count) ++{ ++ return i2c_hid_output_raw_report(hid, buf, count, HID_OUTPUT_REPORT, ++ false); ++} ++ ++static int i2c_hid_raw_request(struct hid_device *hid, unsigned char reportnum, ++ __u8 *buf, size_t len, unsigned char rtype, ++ int reqtype) ++{ ++ switch (reqtype) { ++ case HID_REQ_GET_REPORT: ++ return i2c_hid_get_raw_report(hid, reportnum, buf, len, rtype); ++ case HID_REQ_SET_REPORT: ++ if (buf[0] != reportnum) ++ return -EINVAL; ++ return i2c_hid_output_raw_report(hid, buf, len, rtype, true); ++ default: ++ return -EIO; ++ } ++} ++ ++static int i2c_hid_parse(struct hid_device *hid) ++{ ++ struct i2c_client *client = hid->driver_data; ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ struct i2c_hid_desc *hdesc = &ihid->hdesc; ++ unsigned int rsize; ++ char *rdesc; ++ int ret; ++ int tries = 3; ++ char *use_override; ++ ++ i2c_hid_dbg(ihid, "entering %s\n", __func__); ++ ++ rsize = le16_to_cpu(hdesc->wReportDescLength); ++ if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { ++ dbg_hid("weird size of report descriptor (%u)\n", rsize); ++ return -EINVAL; ++ } ++ ++ do { ++ ret = i2c_hid_hwreset(client); ++ if (ret) ++ msleep(1000); ++ } while (tries-- > 0 && ret); ++ ++ if (ret) ++ return ret; ++ ++ use_override = i2c_hid_get_dmi_hid_report_desc_override(client->name, ++ &rsize); ++ ++ if (use_override) { ++ rdesc = use_override; ++ i2c_hid_dbg(ihid, "Using a HID report descriptor override\n"); ++ } else { ++ rdesc = kzalloc(rsize, GFP_KERNEL); ++ ++ if (!rdesc) { ++ dbg_hid("couldn't allocate rdesc memory\n"); ++ return -ENOMEM; ++ } ++ ++ i2c_hid_dbg(ihid, "asking HID report descriptor\n"); ++ ++ ret = i2c_hid_command(client, &hid_report_descr_cmd, ++ rdesc, rsize); ++ if (ret) { ++ hid_err(hid, "reading report descriptor failed\n"); ++ kfree(rdesc); ++ return -EIO; ++ } ++ } ++ ++ i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc); ++ ++ ret = hid_parse_report(hid, rdesc, rsize); ++ if (!use_override) ++ kfree(rdesc); ++ ++ if (ret) { ++ dbg_hid("parsing report descriptor failed\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int i2c_hid_start(struct hid_device *hid) ++{ ++ struct i2c_client *client = hid->driver_data; ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ int ret; ++ unsigned int bufsize = HID_MIN_BUFFER_SIZE; ++ ++ i2c_hid_find_max_report(hid, HID_INPUT_REPORT, &bufsize); ++ i2c_hid_find_max_report(hid, HID_OUTPUT_REPORT, &bufsize); ++ i2c_hid_find_max_report(hid, HID_FEATURE_REPORT, &bufsize); ++ ++ if (bufsize > ihid->bufsize) { ++ i2c_hid_free_buffers(ihid); ++ ++ ret = i2c_hid_alloc_buffers(ihid, bufsize); ++ ++ if (ret) ++ return ret; ++ } ++ ++ if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS)) ++ i2c_hid_init_reports(hid); ++ ++ return 0; ++} ++ ++static void i2c_hid_stop(struct hid_device *hid) ++{ ++ hid->claimed = 0; ++} ++ ++static int i2c_hid_open(struct hid_device *hid) ++{ ++ struct i2c_client *client = hid->driver_data; ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ int ret = 0; ++ ++ mutex_lock(&i2c_hid_open_mut); ++ if (!hid->open++) { ++ ret = pm_runtime_get_sync(&client->dev); ++ if (ret < 0) { ++ hid->open--; ++ goto done; ++ } ++ set_bit(I2C_HID_STARTED, &ihid->flags); ++ } ++done: ++ mutex_unlock(&i2c_hid_open_mut); ++ return ret < 0 ? ret : 0; ++} ++ ++static void i2c_hid_close(struct hid_device *hid) ++{ ++ struct i2c_client *client = hid->driver_data; ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ ++ /* protecting hid->open to make sure we don't restart ++ * data acquistion due to a resumption we no longer ++ * care about ++ */ ++ mutex_lock(&i2c_hid_open_mut); ++ if (!--hid->open) { ++ clear_bit(I2C_HID_STARTED, &ihid->flags); ++ ++ /* Save some power */ ++ pm_runtime_put(&client->dev); ++ } ++ mutex_unlock(&i2c_hid_open_mut); ++} ++ ++static int i2c_hid_power(struct hid_device *hid, int lvl) ++{ ++ struct i2c_client *client = hid->driver_data; ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ ++ i2c_hid_dbg(ihid, "%s lvl:%d\n", __func__, lvl); ++ ++ switch (lvl) { ++ case PM_HINT_FULLON: ++ pm_runtime_get_sync(&client->dev); ++ break; ++ case PM_HINT_NORMAL: ++ pm_runtime_put(&client->dev); ++ break; ++ } ++ return 0; ++} ++ ++static struct hid_ll_driver i2c_hid_ll_driver = { ++ .parse = i2c_hid_parse, ++ .start = i2c_hid_start, ++ .stop = i2c_hid_stop, ++ .open = i2c_hid_open, ++ .close = i2c_hid_close, ++ .power = i2c_hid_power, ++ .output_report = i2c_hid_output_report, ++ .raw_request = i2c_hid_raw_request, ++}; ++ ++static int i2c_hid_init_irq(struct i2c_client *client) ++{ ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ int ret; ++ ++ dev_dbg(&client->dev, "Requesting IRQ: %d\n", ihid->irq); ++ ++ ret = request_threaded_irq(ihid->irq, NULL, i2c_hid_irq, ++ IRQF_TRIGGER_LOW | IRQF_ONESHOT, ++ client->name, ihid); ++ if (ret < 0) { ++ dev_warn(&client->dev, ++ "Could not register for %s interrupt, irq = %d," ++ " ret = %d\n", ++ client->name, ihid->irq, ret); ++ ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid) ++{ ++ struct i2c_client *client = ihid->client; ++ struct i2c_hid_desc *hdesc = &ihid->hdesc; ++ unsigned int dsize; ++ int ret; ++ ++ /* i2c hid fetch using a fixed descriptor size (30 bytes) */ ++ if (i2c_hid_get_dmi_i2c_hid_desc_override(client->name)) { ++ i2c_hid_dbg(ihid, "Using a HID descriptor override\n"); ++ ihid->hdesc = ++ *i2c_hid_get_dmi_i2c_hid_desc_override(client->name); ++ } else { ++ i2c_hid_dbg(ihid, "Fetching the HID descriptor\n"); ++ ret = i2c_hid_command(client, &hid_descr_cmd, ++ ihid->hdesc_buffer, ++ sizeof(struct i2c_hid_desc)); ++ if (ret) { ++ dev_err(&client->dev, "hid_descr_cmd failed\n"); ++ return -ENODEV; ++ } ++ } ++ ++ /* Validate the length of HID descriptor, the 4 first bytes: ++ * bytes 0-1 -> length ++ * bytes 2-3 -> bcdVersion (has to be 1.00) */ ++ /* check bcdVersion == 1.0 */ ++ if (le16_to_cpu(hdesc->bcdVersion) != 0x0100) { ++ dev_err(&client->dev, ++ "unexpected HID descriptor bcdVersion (0x%04hx)\n", ++ le16_to_cpu(hdesc->bcdVersion)); ++ return -ENODEV; ++ } ++ ++ /* Descriptor length should be 30 bytes as per the specification */ ++ dsize = le16_to_cpu(hdesc->wHIDDescLength); ++ if (dsize != sizeof(struct i2c_hid_desc)) { ++ dev_err(&client->dev, "weird size of HID descriptor (%u)\n", ++ dsize); ++ return -ENODEV; ++ } ++ i2c_hid_dbg(ihid, "HID Descriptor: %*ph\n", dsize, ihid->hdesc_buffer); ++ return 0; ++} ++ ++#ifdef CONFIG_ACPI ++ ++/* Default GPIO mapping */ ++static const struct acpi_gpio_params i2c_hid_irq_gpio = { 0, 0, true }; ++static const struct acpi_gpio_mapping i2c_hid_acpi_gpios[] = { ++ { "gpios", &i2c_hid_irq_gpio, 1 }, ++ { }, ++}; ++ ++static int i2c_hid_acpi_pdata(struct i2c_client *client, ++ struct i2c_hid_platform_data *pdata) ++{ ++ static u8 i2c_hid_guid[] = { ++ 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45, ++ 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE, ++ }; ++ union acpi_object *obj; ++ struct acpi_device *adev; ++ acpi_handle handle; ++ int ret; ++ ++ handle = ACPI_HANDLE(&client->dev); ++ if (!handle || acpi_bus_get_device(handle, &adev)) ++ return -ENODEV; ++ ++ obj = acpi_evaluate_dsm_typed(handle, i2c_hid_guid, 1, 1, NULL, ++ ACPI_TYPE_INTEGER); ++ if (!obj) { ++ dev_err(&client->dev, "device _DSM execution failed\n"); ++ return -ENODEV; ++ } ++ ++ pdata->hid_descriptor_address = obj->integer.value; ++ ACPI_FREE(obj); ++ ++ /* GPIOs are optional */ ++ ret = acpi_dev_add_driver_gpios(adev, i2c_hid_acpi_gpios); ++ return ret < 0 && ret != -ENXIO ? ret : 0; ++} ++ ++static void i2c_hid_acpi_fix_up_power(struct device *dev) ++{ ++ acpi_handle handle = ACPI_HANDLE(dev); ++ struct acpi_device *adev; ++ ++ if (handle && acpi_bus_get_device(handle, &adev) == 0) ++ acpi_device_fix_up_power(adev); ++} ++ ++static const struct acpi_device_id i2c_hid_acpi_match[] = { ++ {"ACPI0C50", 0 }, ++ {"PNP0C50", 0 }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(acpi, i2c_hid_acpi_match); ++#else ++static inline int i2c_hid_acpi_pdata(struct i2c_client *client, ++ struct i2c_hid_platform_data *pdata) ++{ ++ return -ENODEV; ++} ++ ++static inline void i2c_hid_acpi_fix_up_power(struct device *dev) {} ++#endif ++ ++#ifdef CONFIG_OF ++static int i2c_hid_of_probe(struct i2c_client *client, ++ struct i2c_hid_platform_data *pdata) ++{ ++ struct device *dev = &client->dev; ++ u32 val; ++ int ret; ++ ++ ret = of_property_read_u32(dev->of_node, "hid-descr-addr", &val); ++ if (ret) { ++ dev_err(&client->dev, "HID register address not provided\n"); ++ return -ENODEV; ++ } ++ if (val >> 16) { ++ dev_err(&client->dev, "Bad HID register address: 0x%08x\n", ++ val); ++ return -EINVAL; ++ } ++ pdata->hid_descriptor_address = val; ++ ++ return 0; ++} ++ ++static const struct of_device_id i2c_hid_of_match[] = { ++ { .compatible = "hid-over-i2c" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, i2c_hid_of_match); ++#else ++static inline int i2c_hid_of_probe(struct i2c_client *client, ++ struct i2c_hid_platform_data *pdata) ++{ ++ return -ENODEV; ++} ++#endif ++ ++static int i2c_hid_probe(struct i2c_client *client, ++ const struct i2c_device_id *dev_id) ++{ ++ int ret; ++ struct i2c_hid *ihid; ++ struct hid_device *hid; ++ __u16 hidRegister; ++ struct i2c_hid_platform_data *platform_data = client->dev.platform_data; ++ ++ dbg_hid("HID probe called for i2c 0x%02x\n", client->addr); ++ ++ ihid = kzalloc(sizeof(struct i2c_hid), GFP_KERNEL); ++ if (!ihid) ++ return -ENOMEM; ++ ++ if (client->dev.of_node) { ++ ret = i2c_hid_of_probe(client, &ihid->pdata); ++ if (ret) ++ goto err; ++ } else if (!platform_data) { ++ ret = i2c_hid_acpi_pdata(client, &ihid->pdata); ++ if (ret) { ++ dev_err(&client->dev, ++ "HID register address not provided\n"); ++ goto err; ++ } ++ } else { ++ ihid->pdata = *platform_data; ++ } ++ ++ if (client->irq > 0) { ++ ihid->irq = client->irq; ++ } else if (ACPI_COMPANION(&client->dev)) { ++ ihid->desc = gpiod_get(&client->dev, NULL, GPIOD_IN); ++ if (IS_ERR(ihid->desc)) { ++ dev_err(&client->dev, "Failed to get GPIO interrupt\n"); ++ return PTR_ERR(ihid->desc); ++ } ++ ++ ihid->irq = gpiod_to_irq(ihid->desc); ++ if (ihid->irq < 0) { ++ gpiod_put(ihid->desc); ++ dev_err(&client->dev, "Failed to convert GPIO to IRQ\n"); ++ return ihid->irq; ++ } ++ } ++ ++ i2c_set_clientdata(client, ihid); ++ ++ ihid->client = client; ++ ++ hidRegister = ihid->pdata.hid_descriptor_address; ++ ihid->wHIDDescRegister = cpu_to_le16(hidRegister); ++ ++ init_waitqueue_head(&ihid->wait); ++ mutex_init(&ihid->reset_lock); ++ ++ /* we need to allocate the command buffer without knowing the maximum ++ * size of the reports. Let's use HID_MIN_BUFFER_SIZE, then we do the ++ * real computation later. */ ++ ret = i2c_hid_alloc_buffers(ihid, HID_MIN_BUFFER_SIZE); ++ if (ret < 0) ++ goto err; ++ ++ i2c_hid_acpi_fix_up_power(&client->dev); ++ ++ pm_runtime_get_noresume(&client->dev); ++ pm_runtime_set_active(&client->dev); ++ pm_runtime_enable(&client->dev); ++ device_enable_async_suspend(&client->dev); ++ ++ /* Make sure there is something at this address */ ++ ret = i2c_smbus_read_byte(client); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "nothing at this address: %d\n", ret); ++ ret = -ENXIO; ++ goto err_pm; ++ } ++ ++ ret = i2c_hid_fetch_hid_descriptor(ihid); ++ if (ret < 0) ++ goto err_pm; ++ ++ ret = i2c_hid_init_irq(client); ++ if (ret < 0) ++ goto err_pm; ++ ++ hid = hid_allocate_device(); ++ if (IS_ERR(hid)) { ++ ret = PTR_ERR(hid); ++ goto err_irq; ++ } ++ ++ ihid->hid = hid; ++ ++ hid->driver_data = client; ++ hid->ll_driver = &i2c_hid_ll_driver; ++ hid->dev.parent = &client->dev; ++ hid->bus = BUS_I2C; ++ hid->version = le16_to_cpu(ihid->hdesc.bcdVersion); ++ hid->vendor = le16_to_cpu(ihid->hdesc.wVendorID); ++ hid->product = le16_to_cpu(ihid->hdesc.wProductID); ++ ++ snprintf(hid->name, sizeof(hid->name), "%s %04hX:%04hX", ++ client->name, hid->vendor, hid->product); ++ strlcpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys)); ++ ++ ihid->quirks = i2c_hid_lookup_quirk(hid->vendor, hid->product); ++ ++ ret = hid_add_device(hid); ++ if (ret) { ++ if (ret != -ENODEV) ++ hid_err(client, "can't add hid device: %d\n", ret); ++ goto err_mem_free; ++ } ++ ++ pm_runtime_put(&client->dev); ++ return 0; ++ ++err_mem_free: ++ hid_destroy_device(hid); ++ ++err_irq: ++ free_irq(ihid->irq, ihid); ++ ++err_pm: ++ pm_runtime_put_noidle(&client->dev); ++ pm_runtime_disable(&client->dev); ++ ++err: ++ if (ihid->desc) ++ gpiod_put(ihid->desc); ++ ++ i2c_hid_free_buffers(ihid); ++ kfree(ihid); ++ return ret; ++} ++ ++static int i2c_hid_remove(struct i2c_client *client) ++{ ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ struct hid_device *hid; ++ ++ pm_runtime_get_sync(&client->dev); ++ pm_runtime_disable(&client->dev); ++ pm_runtime_set_suspended(&client->dev); ++ pm_runtime_put_noidle(&client->dev); ++ ++ hid = ihid->hid; ++ hid_destroy_device(hid); ++ ++ free_irq(ihid->irq, ihid); ++ ++ if (ihid->bufsize) ++ i2c_hid_free_buffers(ihid); ++ ++ if (ihid->desc) ++ gpiod_put(ihid->desc); ++ ++ kfree(ihid); ++ ++ acpi_dev_remove_driver_gpios(ACPI_COMPANION(&client->dev)); ++ ++ return 0; ++} ++ ++static void i2c_hid_shutdown(struct i2c_client *client) ++{ ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ ++ i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); ++ free_irq(client->irq, ihid); ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int i2c_hid_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ struct hid_device *hid = ihid->hid; ++ int ret; ++ int wake_status; ++ ++ if (hid->driver && hid->driver->suspend) { ++ /* ++ * Wake up the device so that IO issues in ++ * HID driver's suspend code can succeed. ++ */ ++ ret = pm_runtime_resume(dev); ++ if (ret < 0) ++ return ret; ++ ++ ret = hid->driver->suspend(hid, PMSG_SUSPEND); ++ if (ret < 0) ++ return ret; ++ } ++ ++ if (!pm_runtime_suspended(dev)) { ++ /* Save some power */ ++ i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); ++ ++ disable_irq(ihid->irq); ++ } ++ ++ if (device_may_wakeup(&client->dev)) { ++ wake_status = enable_irq_wake(ihid->irq); ++ if (!wake_status) ++ ihid->irq_wake_enabled = true; ++ else ++ hid_warn(hid, "Failed to enable irq wake: %d\n", ++ wake_status); ++ } ++ ++ return 0; ++} ++ ++static int i2c_hid_resume(struct device *dev) ++{ ++ int ret; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ struct hid_device *hid = ihid->hid; ++ int wake_status; ++ ++ if (device_may_wakeup(&client->dev) && ihid->irq_wake_enabled) { ++ wake_status = disable_irq_wake(ihid->irq); ++ if (!wake_status) ++ ihid->irq_wake_enabled = false; ++ else ++ hid_warn(hid, "Failed to disable irq wake: %d\n", ++ wake_status); ++ } ++ ++ /* We'll resume to full power */ ++ pm_runtime_disable(dev); ++ pm_runtime_set_active(dev); ++ pm_runtime_enable(dev); ++ ++ enable_irq(ihid->irq); ++ ret = i2c_hid_hwreset(client); ++ if (ret) ++ return ret; ++ ++ if (hid->driver && hid->driver->reset_resume) { ++ ret = hid->driver->reset_resume(hid); ++ return ret; ++ } ++ ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_PM ++static int i2c_hid_runtime_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ ++ i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); ++ disable_irq(ihid->irq); ++ return 0; ++} ++ ++static int i2c_hid_runtime_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct i2c_hid *ihid = i2c_get_clientdata(client); ++ ++ enable_irq(ihid->irq); ++ i2c_hid_set_power(client, I2C_HID_PWR_ON); ++ return 0; ++} ++#endif ++ ++static const struct dev_pm_ops i2c_hid_pm = { ++ SET_SYSTEM_SLEEP_PM_OPS(i2c_hid_suspend, i2c_hid_resume) ++ SET_RUNTIME_PM_OPS(i2c_hid_runtime_suspend, i2c_hid_runtime_resume, ++ NULL) ++}; ++ ++static const struct i2c_device_id i2c_hid_id_table[] = { ++ { "hid", 0 }, ++ { "hid-over-i2c", 0 }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(i2c, i2c_hid_id_table); ++ ++ ++static struct i2c_driver i2c_hid_driver = { ++ .driver = { ++ .name = "i2c_hid", ++ .pm = &i2c_hid_pm, ++ .acpi_match_table = ACPI_PTR(i2c_hid_acpi_match), ++ .of_match_table = of_match_ptr(i2c_hid_of_match), ++ }, ++ ++ .probe = i2c_hid_probe, ++ .remove = i2c_hid_remove, ++ .shutdown = i2c_hid_shutdown, ++ .id_table = i2c_hid_id_table, ++}; ++ ++module_i2c_driver(i2c_hid_driver); ++ ++MODULE_DESCRIPTION("HID over I2C core driver"); ++MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoi...@gmail.com>"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c +new file mode 100644 +index 000000000000..1d645c9ab417 +--- /dev/null ++++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c +@@ -0,0 +1,376 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++ ++/* ++ * Quirks for I2C-HID devices that do not supply proper descriptors ++ * ++ * Copyright (c) 2018 Julian Sax <j...@gmx.de> ++ * ++ */ ++ ++#include <linux/types.h> ++#include <linux/dmi.h> ++#include <linux/mod_devicetable.h> ++ ++#include "i2c-hid.h" ++ ++ ++struct i2c_hid_desc_override { ++ union { ++ struct i2c_hid_desc *i2c_hid_desc; ++ uint8_t *i2c_hid_desc_buffer; ++ }; ++ uint8_t *hid_report_desc; ++ unsigned int hid_report_desc_size; ++ uint8_t *i2c_name; ++}; ++ ++ ++/* ++ * descriptors for the SIPODEV SP1064 touchpad ++ * ++ * This device does not supply any descriptors and on windows a filter ++ * driver operates between the i2c-hid layer and the device and injects ++ * these descriptors when the device is prompted. The descriptors were ++ * extracted by listening to the i2c-hid traffic that occurs between the ++ * windows filter driver and the windows i2c-hid driver. ++ */ ++ ++static const struct i2c_hid_desc_override sipodev_desc = { ++ .i2c_hid_desc_buffer = (uint8_t []) ++ {0x1e, 0x00, /* Length of descriptor */ ++ 0x00, 0x01, /* Version of descriptor */ ++ 0xdb, 0x01, /* Length of report descriptor */ ++ 0x21, 0x00, /* Location of report descriptor */ ++ 0x24, 0x00, /* Location of input report */ ++ 0x1b, 0x00, /* Max input report length */ ++ 0x25, 0x00, /* Location of output report */ ++ 0x11, 0x00, /* Max output report length */ ++ 0x22, 0x00, /* Location of command register */ ++ 0x23, 0x00, /* Location of data register */ ++ 0x11, 0x09, /* Vendor ID */ ++ 0x88, 0x52, /* Product ID */ ++ 0x06, 0x00, /* Version ID */ ++ 0x00, 0x00, 0x00, 0x00 /* Reserved */ ++ }, ++ ++ .hid_report_desc = (uint8_t []) ++ {0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x02, /* Usage (Mouse), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x01, /* Report ID (1), */ ++ 0x09, 0x01, /* Usage (Pointer), */ ++ 0xA1, 0x00, /* Collection (Physical), */ ++ 0x05, 0x09, /* Usage Page (Button), */ ++ 0x19, 0x01, /* Usage Minimum (01h), */ ++ 0x29, 0x02, /* Usage Maximum (02h), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x02, /* Report Count (2), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x06, /* Report Count (6), */ ++ 0x81, 0x01, /* Input (Constant), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x15, 0x81, /* Logical Minimum (-127), */ ++ 0x25, 0x7F, /* Logical Maximum (127), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x02, /* Report Count (2), */ ++ 0x81, 0x06, /* Input (Variable, Relative), */ ++ 0xC0, /* End Collection, */ ++ 0xC0, /* End Collection, */ ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x05, /* Usage (Touchpad), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x04, /* Report ID (4), */ ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x22, /* Usage (Finger), */ ++ 0xA1, 0x02, /* Collection (Logical), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x09, 0x47, /* Usage (Touch Valid), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x95, 0x02, /* Report Count (2), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x03, /* Report Size (3), */ ++ 0x25, 0x05, /* Logical Maximum (5), */ ++ 0x09, 0x51, /* Usage (Contact Identifier), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x03, /* Report Count (3), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x55, 0x0E, /* Unit Exponent (14), */ ++ 0x65, 0x11, /* Unit (Centimeter), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x46, 0xBC, 0x02, /* Physical Maximum (700), */ ++ 0x26, 0x34, 0x05, /* Logical Maximum (1332), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xC0, /* End Collection, */ ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x22, /* Usage (Finger), */ ++ 0xA1, 0x02, /* Collection (Logical), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x09, 0x47, /* Usage (Touch Valid), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x95, 0x02, /* Report Count (2), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x03, /* Report Size (3), */ ++ 0x25, 0x05, /* Logical Maximum (5), */ ++ 0x09, 0x51, /* Usage (Contact Identifier), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x03, /* Report Count (3), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x46, 0xBC, 0x02, /* Physical Maximum (700), */ ++ 0x26, 0x34, 0x05, /* Logical Maximum (1332), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xC0, /* End Collection, */ ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x22, /* Usage (Finger), */ ++ 0xA1, 0x02, /* Collection (Logical), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x09, 0x47, /* Usage (Touch Valid), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x95, 0x02, /* Report Count (2), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x03, /* Report Size (3), */ ++ 0x25, 0x05, /* Logical Maximum (5), */ ++ 0x09, 0x51, /* Usage (Contact Identifier), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x03, /* Report Count (3), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x46, 0xBC, 0x02, /* Physical Maximum (700), */ ++ 0x26, 0x34, 0x05, /* Logical Maximum (1332), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xC0, /* End Collection, */ ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x22, /* Usage (Finger), */ ++ 0xA1, 0x02, /* Collection (Logical), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x09, 0x47, /* Usage (Touch Valid), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x95, 0x02, /* Report Count (2), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x03, /* Report Size (3), */ ++ 0x25, 0x05, /* Logical Maximum (5), */ ++ 0x09, 0x51, /* Usage (Contact Identifier), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x03, /* Report Count (3), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x46, 0xBC, 0x02, /* Physical Maximum (700), */ ++ 0x26, 0x34, 0x05, /* Logical Maximum (1332), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xC0, /* End Collection, */ ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x55, 0x0C, /* Unit Exponent (12), */ ++ 0x66, 0x01, 0x10, /* Unit (Seconds), */ ++ 0x47, 0xFF, 0xFF, 0x00, 0x00,/* Physical Maximum (65535), */ ++ 0x27, 0xFF, 0xFF, 0x00, 0x00,/* Logical Maximum (65535), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x09, 0x56, /* Usage (Scan Time), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x54, /* Usage (Contact Count), */ ++ 0x25, 0x7F, /* Logical Maximum (127), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x05, 0x09, /* Usage Page (Button), */ ++ 0x09, 0x01, /* Usage (01h), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x07, /* Report Count (7), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x85, 0x02, /* Report ID (2), */ ++ 0x09, 0x55, /* Usage (Contact Count Maximum), */ ++ 0x09, 0x59, /* Usage (59h), */ ++ 0x75, 0x04, /* Report Size (4), */ ++ 0x95, 0x02, /* Report Count (2), */ ++ 0x25, 0x0F, /* Logical Maximum (15), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x85, 0x07, /* Report ID (7), */ ++ 0x09, 0x60, /* Usage (60h), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0x95, 0x07, /* Report Count (7), */ ++ 0xB1, 0x03, /* Feature (Constant, Variable), */ ++ 0x85, 0x06, /* Report ID (6), */ ++ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ ++ 0x09, 0xC5, /* Usage (C5h), */ ++ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x96, 0x00, 0x01, /* Report Count (256), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0xC0, /* End Collection, */ ++ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ ++ 0x09, 0x01, /* Usage (01h), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x0D, /* Report ID (13), */ ++ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ ++ 0x19, 0x01, /* Usage Minimum (01h), */ ++ 0x29, 0x02, /* Usage Maximum (02h), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x02, /* Report Count (2), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0xC0, /* End Collection, */ ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x0E, /* Usage (Configuration), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x03, /* Report ID (3), */ ++ 0x09, 0x22, /* Usage (Finger), */ ++ 0xA1, 0x02, /* Collection (Logical), */ ++ 0x09, 0x52, /* Usage (Device Mode), */ ++ 0x25, 0x0A, /* Logical Maximum (10), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0xC0, /* End Collection, */ ++ 0x09, 0x22, /* Usage (Finger), */ ++ 0xA1, 0x00, /* Collection (Physical), */ ++ 0x85, 0x05, /* Report ID (5), */ ++ 0x09, 0x57, /* Usage (57h), */ ++ 0x09, 0x58, /* Usage (58h), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x02, /* Report Count (2), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0x95, 0x06, /* Report Count (6), */ ++ 0xB1, 0x03, /* Feature (Constant, Variable),*/ ++ 0xC0, /* End Collection, */ ++ 0xC0 /* End Collection */ ++ }, ++ .hid_report_desc_size = 475, ++ .i2c_name = "SYNA3602:00" ++}; ++ ++ ++static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = { ++ { ++ .ident = "Teclast F6 Pro", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F6 Pro"), ++ }, ++ .driver_data = (void *)&sipodev_desc ++ }, ++ { ++ .ident = "Teclast F7", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F7"), ++ }, ++ .driver_data = (void *)&sipodev_desc ++ }, ++ { ++ .ident = "Trekstor Primebook C13", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C13"), ++ }, ++ .driver_data = (void *)&sipodev_desc ++ }, ++ { ++ .ident = "Trekstor Primebook C11", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C11"), ++ }, ++ .driver_data = (void *)&sipodev_desc ++ }, ++ { ++ .ident = "Direkt-Tek DTLAPY116-2", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Direkt-Tek"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "DTLAPY116-2"), ++ }, ++ .driver_data = (void *)&sipodev_desc ++ }, ++ { ++ .ident = "Mediacom Flexbook Edge 11", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MEDIACOM"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "FlexBook edge11 - M-FBE11"), ++ }, ++ .driver_data = (void *)&sipodev_desc ++ } ++}; ++ ++ ++struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name) ++{ ++ struct i2c_hid_desc_override *override; ++ const struct dmi_system_id *system_id; ++ ++ system_id = dmi_first_match(i2c_hid_dmi_desc_override_table); ++ if (!system_id) ++ return NULL; ++ ++ override = system_id->driver_data; ++ if (strcmp(override->i2c_name, i2c_name)) ++ return NULL; ++ ++ return override->i2c_hid_desc; ++} ++ ++char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, ++ unsigned int *size) ++{ ++ struct i2c_hid_desc_override *override; ++ const struct dmi_system_id *system_id; ++ ++ system_id = dmi_first_match(i2c_hid_dmi_desc_override_table); ++ if (!system_id) ++ return NULL; ++ ++ override = system_id->driver_data; ++ if (strcmp(override->i2c_name, i2c_name)) ++ return NULL; ++ ++ *size = override->hid_report_desc_size; ++ return override->hid_report_desc; ++} +diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c +deleted file mode 100644 +index ce2b80009c19..000000000000 +--- a/drivers/hid/i2c-hid/i2c-hid.c ++++ /dev/null +@@ -1,1339 +0,0 @@ +-/* +- * HID over I2C protocol implementation +- * +- * Copyright (c) 2012 Benjamin Tissoires <benjamin.tissoi...@gmail.com> +- * Copyright (c) 2012 Ecole Nationale de l'Aviation Civile, France +- * Copyright (c) 2012 Red Hat, Inc +- * +- * This code is partly based on "USB HID support for Linux": +- * +- * Copyright (c) 1999 Andreas Gal +- * Copyright (c) 2000-2005 Vojtech Pavlik <vojt...@suse.cz> +- * Copyright (c) 2005 Michael Haboustak <mi...@cinci.rr.com> for Concept2, Inc +- * Copyright (c) 2007-2008 Oliver Neukum +- * Copyright (c) 2006-2010 Jiri Kosina +- * +- * This file is subject to the terms and conditions of the GNU General Public +- * License. See the file COPYING in the main directory of this archive for +- * more details. +- */ +- +-#include <linux/module.h> +-#include <linux/i2c.h> +-#include <linux/interrupt.h> +-#include <linux/input.h> +-#include <linux/delay.h> +-#include <linux/slab.h> +-#include <linux/pm.h> +-#include <linux/pm_runtime.h> +-#include <linux/device.h> +-#include <linux/wait.h> +-#include <linux/err.h> +-#include <linux/string.h> +-#include <linux/list.h> +-#include <linux/jiffies.h> +-#include <linux/kernel.h> +-#include <linux/hid.h> +-#include <linux/mutex.h> +-#include <linux/acpi.h> +-#include <linux/of.h> +-#include <linux/gpio/consumer.h> +- +-#include <linux/i2c/i2c-hid.h> +- +-#include "../hid-ids.h" +- +-/* quirks to control the device */ +-#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0) +- +-/* flags */ +-#define I2C_HID_STARTED 0 +-#define I2C_HID_RESET_PENDING 1 +-#define I2C_HID_READ_PENDING 2 +- +-#define I2C_HID_PWR_ON 0x00 +-#define I2C_HID_PWR_SLEEP 0x01 +- +-/* debug option */ +-static bool debug; +-module_param(debug, bool, 0444); +-MODULE_PARM_DESC(debug, "print a lot of debug information"); +- +-#define i2c_hid_dbg(ihid, fmt, arg...) \ +-do { \ +- if (debug) \ +- dev_printk(KERN_DEBUG, &(ihid)->client->dev, fmt, ##arg); \ +-} while (0) +- +-struct i2c_hid_desc { +- __le16 wHIDDescLength; +- __le16 bcdVersion; +- __le16 wReportDescLength; +- __le16 wReportDescRegister; +- __le16 wInputRegister; +- __le16 wMaxInputLength; +- __le16 wOutputRegister; +- __le16 wMaxOutputLength; +- __le16 wCommandRegister; +- __le16 wDataRegister; +- __le16 wVendorID; +- __le16 wProductID; +- __le16 wVersionID; +- __le32 reserved; +-} __packed; +- +-struct i2c_hid_cmd { +- unsigned int registerIndex; +- __u8 opcode; +- unsigned int length; +- bool wait; +-}; +- +-union command { +- u8 data[0]; +- struct cmd { +- __le16 reg; +- __u8 reportTypeID; +- __u8 opcode; +- } __packed c; +-}; +- +-#define I2C_HID_CMD(opcode_) \ +- .opcode = opcode_, .length = 4, \ +- .registerIndex = offsetof(struct i2c_hid_desc, wCommandRegister) +- +-/* fetch HID descriptor */ +-static const struct i2c_hid_cmd hid_descr_cmd = { .length = 2 }; +-/* fetch report descriptors */ +-static const struct i2c_hid_cmd hid_report_descr_cmd = { +- .registerIndex = offsetof(struct i2c_hid_desc, +- wReportDescRegister), +- .opcode = 0x00, +- .length = 2 }; +-/* commands */ +-static const struct i2c_hid_cmd hid_reset_cmd = { I2C_HID_CMD(0x01), +- .wait = true }; +-static const struct i2c_hid_cmd hid_get_report_cmd = { I2C_HID_CMD(0x02) }; +-static const struct i2c_hid_cmd hid_set_report_cmd = { I2C_HID_CMD(0x03) }; +-static const struct i2c_hid_cmd hid_set_power_cmd = { I2C_HID_CMD(0x08) }; +-static const struct i2c_hid_cmd hid_no_cmd = { .length = 0 }; +- +-/* +- * These definitions are not used here, but are defined by the spec. +- * Keeping them here for documentation purposes. +- * +- * static const struct i2c_hid_cmd hid_get_idle_cmd = { I2C_HID_CMD(0x04) }; +- * static const struct i2c_hid_cmd hid_set_idle_cmd = { I2C_HID_CMD(0x05) }; +- * static const struct i2c_hid_cmd hid_get_protocol_cmd = { I2C_HID_CMD(0x06) }; +- * static const struct i2c_hid_cmd hid_set_protocol_cmd = { I2C_HID_CMD(0x07) }; +- */ +- +-static DEFINE_MUTEX(i2c_hid_open_mut); +- +-/* The main device structure */ +-struct i2c_hid { +- struct i2c_client *client; /* i2c client */ +- struct hid_device *hid; /* pointer to corresponding HID dev */ +- union { +- __u8 hdesc_buffer[sizeof(struct i2c_hid_desc)]; +- struct i2c_hid_desc hdesc; /* the HID Descriptor */ +- }; +- __le16 wHIDDescRegister; /* location of the i2c +- * register of the HID +- * descriptor. */ +- unsigned int bufsize; /* i2c buffer size */ +- u8 *inbuf; /* Input buffer */ +- u8 *rawbuf; /* Raw Input buffer */ +- u8 *cmdbuf; /* Command buffer */ +- u8 *argsbuf; /* Command arguments buffer */ +- +- unsigned long flags; /* device flags */ +- unsigned long quirks; /* Various quirks */ +- +- wait_queue_head_t wait; /* For waiting the interrupt */ +- struct gpio_desc *desc; +- int irq; +- +- struct i2c_hid_platform_data pdata; +- +- bool irq_wake_enabled; +- struct mutex reset_lock; +-}; +- +-static const struct i2c_hid_quirks { +- __u16 idVendor; +- __u16 idProduct; +- __u32 quirks; +-} i2c_hid_quirks[] = { +- { USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8752, +- I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV }, +- { USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8755, +- I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV }, +- { 0, 0 } +-}; +- +-/* +- * i2c_hid_lookup_quirk: return any quirks associated with a I2C HID device +- * @idVendor: the 16-bit vendor ID +- * @idProduct: the 16-bit product ID +- * +- * Returns: a u32 quirks value. +- */ +-static u32 i2c_hid_lookup_quirk(const u16 idVendor, const u16 idProduct) +-{ +- u32 quirks = 0; +- int n; +- +- for (n = 0; i2c_hid_quirks[n].idVendor; n++) +- if (i2c_hid_quirks[n].idVendor == idVendor && +- (i2c_hid_quirks[n].idProduct == (__u16)HID_ANY_ID || +- i2c_hid_quirks[n].idProduct == idProduct)) +- quirks = i2c_hid_quirks[n].quirks; +- +- return quirks; +-} +- +-static int __i2c_hid_command(struct i2c_client *client, +- const struct i2c_hid_cmd *command, u8 reportID, +- u8 reportType, u8 *args, int args_len, +- unsigned char *buf_recv, int data_len) +-{ +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- union command *cmd = (union command *)ihid->cmdbuf; +- int ret; +- struct i2c_msg msg[2]; +- int msg_num = 1; +- +- int length = command->length; +- bool wait = command->wait; +- unsigned int registerIndex = command->registerIndex; +- +- /* special case for hid_descr_cmd */ +- if (command == &hid_descr_cmd) { +- cmd->c.reg = ihid->wHIDDescRegister; +- } else { +- cmd->data[0] = ihid->hdesc_buffer[registerIndex]; +- cmd->data[1] = ihid->hdesc_buffer[registerIndex + 1]; +- } +- +- if (length > 2) { +- cmd->c.opcode = command->opcode; +- cmd->c.reportTypeID = reportID | reportType << 4; +- } +- +- memcpy(cmd->data + length, args, args_len); +- length += args_len; +- +- i2c_hid_dbg(ihid, "%s: cmd=%*ph\n", __func__, length, cmd->data); +- +- msg[0].addr = client->addr; +- msg[0].flags = client->flags & I2C_M_TEN; +- msg[0].len = length; +- msg[0].buf = cmd->data; +- if (data_len > 0) { +- msg[1].addr = client->addr; +- msg[1].flags = client->flags & I2C_M_TEN; +- msg[1].flags |= I2C_M_RD; +- msg[1].len = data_len; +- msg[1].buf = buf_recv; +- msg_num = 2; +- set_bit(I2C_HID_READ_PENDING, &ihid->flags); +- } +- +- if (wait) +- set_bit(I2C_HID_RESET_PENDING, &ihid->flags); +- +- ret = i2c_transfer(client->adapter, msg, msg_num); +- +- if (data_len > 0) +- clear_bit(I2C_HID_READ_PENDING, &ihid->flags); +- +- if (ret != msg_num) +- return ret < 0 ? ret : -EIO; +- +- ret = 0; +- +- if (wait) { +- i2c_hid_dbg(ihid, "%s: waiting...\n", __func__); +- if (!wait_event_timeout(ihid->wait, +- !test_bit(I2C_HID_RESET_PENDING, &ihid->flags), +- msecs_to_jiffies(5000))) +- ret = -ENODATA; +- i2c_hid_dbg(ihid, "%s: finished.\n", __func__); +- } +- +- return ret; +-} +- +-static int i2c_hid_command(struct i2c_client *client, +- const struct i2c_hid_cmd *command, +- unsigned char *buf_recv, int data_len) +-{ +- return __i2c_hid_command(client, command, 0, 0, NULL, 0, +- buf_recv, data_len); +-} +- +-static int i2c_hid_get_report(struct i2c_client *client, u8 reportType, +- u8 reportID, unsigned char *buf_recv, int data_len) +-{ +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- u8 args[3]; +- int ret; +- int args_len = 0; +- u16 readRegister = le16_to_cpu(ihid->hdesc.wDataRegister); +- +- i2c_hid_dbg(ihid, "%s\n", __func__); +- +- if (reportID >= 0x0F) { +- args[args_len++] = reportID; +- reportID = 0x0F; +- } +- +- args[args_len++] = readRegister & 0xFF; +- args[args_len++] = readRegister >> 8; +- +- ret = __i2c_hid_command(client, &hid_get_report_cmd, reportID, +- reportType, args, args_len, buf_recv, data_len); +- if (ret) { +- dev_err(&client->dev, +- "failed to retrieve report from device.\n"); +- return ret; +- } +- +- return 0; +-} +- +-/** +- * i2c_hid_set_or_send_report: forward an incoming report to the device +- * @client: the i2c_client of the device +- * @reportType: 0x03 for HID_FEATURE_REPORT ; 0x02 for HID_OUTPUT_REPORT +- * @reportID: the report ID +- * @buf: the actual data to transfer, without the report ID +- * @len: size of buf +- * @use_data: true: use SET_REPORT HID command, false: send plain OUTPUT report +- */ +-static int i2c_hid_set_or_send_report(struct i2c_client *client, u8 reportType, +- u8 reportID, unsigned char *buf, size_t data_len, bool use_data) +-{ +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- u8 *args = ihid->argsbuf; +- const struct i2c_hid_cmd *hidcmd; +- int ret; +- u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister); +- u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister); +- u16 maxOutputLength = le16_to_cpu(ihid->hdesc.wMaxOutputLength); +- u16 size; +- int args_len; +- int index = 0; +- +- i2c_hid_dbg(ihid, "%s\n", __func__); +- +- if (data_len > ihid->bufsize) +- return -EINVAL; +- +- size = 2 /* size */ + +- (reportID ? 1 : 0) /* reportID */ + +- data_len /* buf */; +- args_len = (reportID >= 0x0F ? 1 : 0) /* optional third byte */ + +- 2 /* dataRegister */ + +- size /* args */; +- +- if (!use_data && maxOutputLength == 0) +- return -ENOSYS; +- +- if (reportID >= 0x0F) { +- args[index++] = reportID; +- reportID = 0x0F; +- } +- +- /* +- * use the data register for feature reports or if the device does not +- * support the output register +- */ +- if (use_data) { +- args[index++] = dataRegister & 0xFF; +- args[index++] = dataRegister >> 8; +- hidcmd = &hid_set_report_cmd; +- } else { +- args[index++] = outputRegister & 0xFF; +- args[index++] = outputRegister >> 8; +- hidcmd = &hid_no_cmd; +- } +- +- args[index++] = size & 0xFF; +- args[index++] = size >> 8; +- +- if (reportID) +- args[index++] = reportID; +- +- memcpy(&args[index], buf, data_len); +- +- ret = __i2c_hid_command(client, hidcmd, reportID, +- reportType, args, args_len, NULL, 0); +- if (ret) { +- dev_err(&client->dev, "failed to set a report to device.\n"); +- return ret; +- } +- +- return data_len; +-} +- +-static int i2c_hid_set_power(struct i2c_client *client, int power_state) +-{ +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- int ret; +- +- i2c_hid_dbg(ihid, "%s\n", __func__); +- +- /* +- * Some devices require to send a command to wakeup before power on. +- * The call will get a return value (EREMOTEIO) but device will be +- * triggered and activated. After that, it goes like a normal device. +- */ +- if (power_state == I2C_HID_PWR_ON && +- ihid->quirks & I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV) { +- ret = i2c_hid_command(client, &hid_set_power_cmd, NULL, 0); +- +- /* Device was already activated */ +- if (!ret) +- goto set_pwr_exit; +- } +- +- ret = __i2c_hid_command(client, &hid_set_power_cmd, power_state, +- 0, NULL, 0, NULL, 0); +- +- if (ret) +- dev_err(&client->dev, "failed to change power setting.\n"); +- +-set_pwr_exit: +- return ret; +-} +- +-static int i2c_hid_hwreset(struct i2c_client *client) +-{ +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- int ret; +- +- i2c_hid_dbg(ihid, "%s\n", __func__); +- +- /* +- * This prevents sending feature reports while the device is +- * being reset. Otherwise we may lose the reset complete +- * interrupt. +- */ +- mutex_lock(&ihid->reset_lock); +- +- ret = i2c_hid_set_power(client, I2C_HID_PWR_ON); +- if (ret) +- goto out_unlock; +- +- /* +- * The HID over I2C specification states that if a DEVICE needs time +- * after the PWR_ON request, it should utilise CLOCK stretching. +- * However, it has been observered that the Windows driver provides a +- * 1ms sleep between the PWR_ON and RESET requests and that some devices +- * rely on this. +- */ +- usleep_range(1000, 5000); +- +- i2c_hid_dbg(ihid, "resetting...\n"); +- +- ret = i2c_hid_command(client, &hid_reset_cmd, NULL, 0); +- if (ret) { +- dev_err(&client->dev, "failed to reset device.\n"); +- i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); +- } +- +-out_unlock: +- mutex_unlock(&ihid->reset_lock); +- return ret; +-} +- +-static void i2c_hid_get_input(struct i2c_hid *ihid) +-{ +- int ret; +- u32 ret_size; +- int size = le16_to_cpu(ihid->hdesc.wMaxInputLength); +- +- if (size > ihid->bufsize) +- size = ihid->bufsize; +- +- ret = i2c_master_recv(ihid->client, ihid->inbuf, size); +- if (ret != size) { +- if (ret < 0) +- return; +- +- dev_err(&ihid->client->dev, "%s: got %d data instead of %d\n", +- __func__, ret, size); +- return; +- } +- +- ret_size = ihid->inbuf[0] | ihid->inbuf[1] << 8; +- +- if (!ret_size) { +- /* host or device initiated RESET completed */ +- if (test_and_clear_bit(I2C_HID_RESET_PENDING, &ihid->flags)) +- wake_up(&ihid->wait); +- return; +- } +- +- if ((ret_size > size) || (ret_size < 2)) { +- dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n", +- __func__, size, ret_size); +- return; +- } +- +- i2c_hid_dbg(ihid, "input: %*ph\n", ret_size, ihid->inbuf); +- +- if (test_bit(I2C_HID_STARTED, &ihid->flags)) +- hid_input_report(ihid->hid, HID_INPUT_REPORT, ihid->inbuf + 2, +- ret_size - 2, 1); +- +- return; +-} +- +-static irqreturn_t i2c_hid_irq(int irq, void *dev_id) +-{ +- struct i2c_hid *ihid = dev_id; +- +- if (test_bit(I2C_HID_READ_PENDING, &ihid->flags)) +- return IRQ_HANDLED; +- +- i2c_hid_get_input(ihid); +- +- return IRQ_HANDLED; +-} +- +-static int i2c_hid_get_report_length(struct hid_report *report) +-{ +- return ((report->size - 1) >> 3) + 1 + +- report->device->report_enum[report->type].numbered + 2; +-} +- +-static void i2c_hid_init_report(struct hid_report *report, u8 *buffer, +- size_t bufsize) +-{ +- struct hid_device *hid = report->device; +- struct i2c_client *client = hid->driver_data; +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- unsigned int size, ret_size; +- +- size = i2c_hid_get_report_length(report); +- if (i2c_hid_get_report(client, +- report->type == HID_FEATURE_REPORT ? 0x03 : 0x01, +- report->id, buffer, size)) +- return; +- +- i2c_hid_dbg(ihid, "report (len=%d): %*ph\n", size, size, buffer); +- +- ret_size = buffer[0] | (buffer[1] << 8); +- +- if (ret_size != size) { +- dev_err(&client->dev, "error in %s size:%d / ret_size:%d\n", +- __func__, size, ret_size); +- return; +- } +- +- /* hid->driver_lock is held as we are in probe function, +- * we just need to setup the input fields, so using +- * hid_report_raw_event is safe. */ +- hid_report_raw_event(hid, report->type, buffer + 2, size - 2, 1); +-} +- +-/* +- * Initialize all reports +- */ +-static void i2c_hid_init_reports(struct hid_device *hid) +-{ +- struct hid_report *report; +- struct i2c_client *client = hid->driver_data; +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- u8 *inbuf = kzalloc(ihid->bufsize, GFP_KERNEL); +- +- if (!inbuf) { +- dev_err(&client->dev, "can not retrieve initial reports\n"); +- return; +- } +- +- /* +- * The device must be powered on while we fetch initial reports +- * from it. +- */ +- pm_runtime_get_sync(&client->dev); +- +- list_for_each_entry(report, +- &hid->report_enum[HID_FEATURE_REPORT].report_list, list) +- i2c_hid_init_report(report, inbuf, ihid->bufsize); +- +- pm_runtime_put(&client->dev); +- +- kfree(inbuf); +-} +- +-/* +- * Traverse the supplied list of reports and find the longest +- */ +-static void i2c_hid_find_max_report(struct hid_device *hid, unsigned int type, +- unsigned int *max) +-{ +- struct hid_report *report; +- unsigned int size; +- +- /* We should not rely on wMaxInputLength, as some devices may set it to +- * a wrong length. */ +- list_for_each_entry(report, &hid->report_enum[type].report_list, list) { +- size = i2c_hid_get_report_length(report); +- if (*max < size) +- *max = size; +- } +-} +- +-static void i2c_hid_free_buffers(struct i2c_hid *ihid) +-{ +- kfree(ihid->inbuf); +- kfree(ihid->rawbuf); +- kfree(ihid->argsbuf); +- kfree(ihid->cmdbuf); +- ihid->inbuf = NULL; +- ihid->rawbuf = NULL; +- ihid->cmdbuf = NULL; +- ihid->argsbuf = NULL; +- ihid->bufsize = 0; +-} +- +-static int i2c_hid_alloc_buffers(struct i2c_hid *ihid, size_t report_size) +-{ +- /* the worst case is computed from the set_report command with a +- * reportID > 15 and the maximum report length */ +- int args_len = sizeof(__u8) + /* ReportID */ +- sizeof(__u8) + /* optional ReportID byte */ +- sizeof(__u16) + /* data register */ +- sizeof(__u16) + /* size of the report */ +- report_size; /* report */ +- +- ihid->inbuf = kzalloc(report_size, GFP_KERNEL); +- ihid->rawbuf = kzalloc(report_size, GFP_KERNEL); +- ihid->argsbuf = kzalloc(args_len, GFP_KERNEL); +- ihid->cmdbuf = kzalloc(sizeof(union command) + args_len, GFP_KERNEL); +- +- if (!ihid->inbuf || !ihid->rawbuf || !ihid->argsbuf || !ihid->cmdbuf) { +- i2c_hid_free_buffers(ihid); +- return -ENOMEM; +- } +- +- ihid->bufsize = report_size; +- +- return 0; +-} +- +-static int i2c_hid_get_raw_report(struct hid_device *hid, +- unsigned char report_number, __u8 *buf, size_t count, +- unsigned char report_type) +-{ +- struct i2c_client *client = hid->driver_data; +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- size_t ret_count, ask_count; +- int ret; +- +- if (report_type == HID_OUTPUT_REPORT) +- return -EINVAL; +- +- /* +2 bytes to include the size of the reply in the query buffer */ +- ask_count = min(count + 2, (size_t)ihid->bufsize); +- +- ret = i2c_hid_get_report(client, +- report_type == HID_FEATURE_REPORT ? 0x03 : 0x01, +- report_number, ihid->rawbuf, ask_count); +- +- if (ret < 0) +- return ret; +- +- ret_count = ihid->rawbuf[0] | (ihid->rawbuf[1] << 8); +- +- if (ret_count <= 2) +- return 0; +- +- ret_count = min(ret_count, ask_count); +- +- /* The query buffer contains the size, dropping it in the reply */ +- count = min(count, ret_count - 2); +- memcpy(buf, ihid->rawbuf + 2, count); +- +- return count; +-} +- +-static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, +- size_t count, unsigned char report_type, bool use_data) +-{ +- struct i2c_client *client = hid->driver_data; +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- int report_id = buf[0]; +- int ret; +- +- if (report_type == HID_INPUT_REPORT) +- return -EINVAL; +- +- mutex_lock(&ihid->reset_lock); +- +- if (report_id) { +- buf++; +- count--; +- } +- +- ret = i2c_hid_set_or_send_report(client, +- report_type == HID_FEATURE_REPORT ? 0x03 : 0x02, +- report_id, buf, count, use_data); +- +- if (report_id && ret >= 0) +- ret++; /* add report_id to the number of transfered bytes */ +- +- mutex_unlock(&ihid->reset_lock); +- +- return ret; +-} +- +-static int i2c_hid_output_report(struct hid_device *hid, __u8 *buf, +- size_t count) +-{ +- return i2c_hid_output_raw_report(hid, buf, count, HID_OUTPUT_REPORT, +- false); +-} +- +-static int i2c_hid_raw_request(struct hid_device *hid, unsigned char reportnum, +- __u8 *buf, size_t len, unsigned char rtype, +- int reqtype) +-{ +- switch (reqtype) { +- case HID_REQ_GET_REPORT: +- return i2c_hid_get_raw_report(hid, reportnum, buf, len, rtype); +- case HID_REQ_SET_REPORT: +- if (buf[0] != reportnum) +- return -EINVAL; +- return i2c_hid_output_raw_report(hid, buf, len, rtype, true); +- default: +- return -EIO; +- } +-} +- +-static int i2c_hid_parse(struct hid_device *hid) +-{ +- struct i2c_client *client = hid->driver_data; +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- struct i2c_hid_desc *hdesc = &ihid->hdesc; +- unsigned int rsize; +- char *rdesc; +- int ret; +- int tries = 3; +- +- i2c_hid_dbg(ihid, "entering %s\n", __func__); +- +- rsize = le16_to_cpu(hdesc->wReportDescLength); +- if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { +- dbg_hid("weird size of report descriptor (%u)\n", rsize); +- return -EINVAL; +- } +- +- do { +- ret = i2c_hid_hwreset(client); +- if (ret) +- msleep(1000); +- } while (tries-- > 0 && ret); +- +- if (ret) +- return ret; +- +- rdesc = kzalloc(rsize, GFP_KERNEL); +- +- if (!rdesc) { +- dbg_hid("couldn't allocate rdesc memory\n"); +- return -ENOMEM; +- } +- +- i2c_hid_dbg(ihid, "asking HID report descriptor\n"); +- +- ret = i2c_hid_command(client, &hid_report_descr_cmd, rdesc, rsize); +- if (ret) { +- hid_err(hid, "reading report descriptor failed\n"); +- kfree(rdesc); +- return -EIO; +- } +- +- i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc); +- +- ret = hid_parse_report(hid, rdesc, rsize); +- kfree(rdesc); +- if (ret) { +- dbg_hid("parsing report descriptor failed\n"); +- return ret; +- } +- +- return 0; +-} +- +-static int i2c_hid_start(struct hid_device *hid) +-{ +- struct i2c_client *client = hid->driver_data; +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- int ret; +- unsigned int bufsize = HID_MIN_BUFFER_SIZE; +- +- i2c_hid_find_max_report(hid, HID_INPUT_REPORT, &bufsize); +- i2c_hid_find_max_report(hid, HID_OUTPUT_REPORT, &bufsize); +- i2c_hid_find_max_report(hid, HID_FEATURE_REPORT, &bufsize); +- +- if (bufsize > ihid->bufsize) { +- i2c_hid_free_buffers(ihid); +- +- ret = i2c_hid_alloc_buffers(ihid, bufsize); +- +- if (ret) +- return ret; +- } +- +- if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS)) +- i2c_hid_init_reports(hid); +- +- return 0; +-} +- +-static void i2c_hid_stop(struct hid_device *hid) +-{ +- hid->claimed = 0; +-} +- +-static int i2c_hid_open(struct hid_device *hid) +-{ +- struct i2c_client *client = hid->driver_data; +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- int ret = 0; +- +- mutex_lock(&i2c_hid_open_mut); +- if (!hid->open++) { +- ret = pm_runtime_get_sync(&client->dev); +- if (ret < 0) { +- hid->open--; +- goto done; +- } +- set_bit(I2C_HID_STARTED, &ihid->flags); +- } +-done: +- mutex_unlock(&i2c_hid_open_mut); +- return ret < 0 ? ret : 0; +-} +- +-static void i2c_hid_close(struct hid_device *hid) +-{ +- struct i2c_client *client = hid->driver_data; +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- +- /* protecting hid->open to make sure we don't restart +- * data acquistion due to a resumption we no longer +- * care about +- */ +- mutex_lock(&i2c_hid_open_mut); +- if (!--hid->open) { +- clear_bit(I2C_HID_STARTED, &ihid->flags); +- +- /* Save some power */ +- pm_runtime_put(&client->dev); +- } +- mutex_unlock(&i2c_hid_open_mut); +-} +- +-static int i2c_hid_power(struct hid_device *hid, int lvl) +-{ +- struct i2c_client *client = hid->driver_data; +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- +- i2c_hid_dbg(ihid, "%s lvl:%d\n", __func__, lvl); +- +- switch (lvl) { +- case PM_HINT_FULLON: +- pm_runtime_get_sync(&client->dev); +- break; +- case PM_HINT_NORMAL: +- pm_runtime_put(&client->dev); +- break; +- } +- return 0; +-} +- +-static struct hid_ll_driver i2c_hid_ll_driver = { +- .parse = i2c_hid_parse, +- .start = i2c_hid_start, +- .stop = i2c_hid_stop, +- .open = i2c_hid_open, +- .close = i2c_hid_close, +- .power = i2c_hid_power, +- .output_report = i2c_hid_output_report, +- .raw_request = i2c_hid_raw_request, +-}; +- +-static int i2c_hid_init_irq(struct i2c_client *client) +-{ +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- int ret; +- +- dev_dbg(&client->dev, "Requesting IRQ: %d\n", ihid->irq); +- +- ret = request_threaded_irq(ihid->irq, NULL, i2c_hid_irq, +- IRQF_TRIGGER_LOW | IRQF_ONESHOT, +- client->name, ihid); +- if (ret < 0) { +- dev_warn(&client->dev, +- "Could not register for %s interrupt, irq = %d," +- " ret = %d\n", +- client->name, ihid->irq, ret); +- +- return ret; +- } +- +- return 0; +-} +- +-static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid) +-{ +- struct i2c_client *client = ihid->client; +- struct i2c_hid_desc *hdesc = &ihid->hdesc; +- unsigned int dsize; +- int ret; +- +- /* i2c hid fetch using a fixed descriptor size (30 bytes) */ +- i2c_hid_dbg(ihid, "Fetching the HID descriptor\n"); +- ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer, +- sizeof(struct i2c_hid_desc)); +- if (ret) { +- dev_err(&client->dev, "hid_descr_cmd failed\n"); +- return -ENODEV; +- } +- +- /* Validate the length of HID descriptor, the 4 first bytes: +- * bytes 0-1 -> length +- * bytes 2-3 -> bcdVersion (has to be 1.00) */ +- /* check bcdVersion == 1.0 */ +- if (le16_to_cpu(hdesc->bcdVersion) != 0x0100) { +- dev_err(&client->dev, +- "unexpected HID descriptor bcdVersion (0x%04hx)\n", +- le16_to_cpu(hdesc->bcdVersion)); +- return -ENODEV; +- } +- +- /* Descriptor length should be 30 bytes as per the specification */ +- dsize = le16_to_cpu(hdesc->wHIDDescLength); +- if (dsize != sizeof(struct i2c_hid_desc)) { +- dev_err(&client->dev, "weird size of HID descriptor (%u)\n", +- dsize); +- return -ENODEV; +- } +- i2c_hid_dbg(ihid, "HID Descriptor: %*ph\n", dsize, ihid->hdesc_buffer); +- return 0; +-} +- +-#ifdef CONFIG_ACPI +- +-/* Default GPIO mapping */ +-static const struct acpi_gpio_params i2c_hid_irq_gpio = { 0, 0, true }; +-static const struct acpi_gpio_mapping i2c_hid_acpi_gpios[] = { +- { "gpios", &i2c_hid_irq_gpio, 1 }, +- { }, +-}; +- +-static int i2c_hid_acpi_pdata(struct i2c_client *client, +- struct i2c_hid_platform_data *pdata) +-{ +- static u8 i2c_hid_guid[] = { +- 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45, +- 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE, +- }; +- union acpi_object *obj; +- struct acpi_device *adev; +- acpi_handle handle; +- int ret; +- +- handle = ACPI_HANDLE(&client->dev); +- if (!handle || acpi_bus_get_device(handle, &adev)) +- return -ENODEV; +- +- obj = acpi_evaluate_dsm_typed(handle, i2c_hid_guid, 1, 1, NULL, +- ACPI_TYPE_INTEGER); +- if (!obj) { +- dev_err(&client->dev, "device _DSM execution failed\n"); +- return -ENODEV; +- } +- +- pdata->hid_descriptor_address = obj->integer.value; +- ACPI_FREE(obj); +- +- /* GPIOs are optional */ +- ret = acpi_dev_add_driver_gpios(adev, i2c_hid_acpi_gpios); +- return ret < 0 && ret != -ENXIO ? ret : 0; +-} +- +-static void i2c_hid_acpi_fix_up_power(struct device *dev) +-{ +- acpi_handle handle = ACPI_HANDLE(dev); +- struct acpi_device *adev; +- +- if (handle && acpi_bus_get_device(handle, &adev) == 0) +- acpi_device_fix_up_power(adev); +-} +- +-static const struct acpi_device_id i2c_hid_acpi_match[] = { +- {"ACPI0C50", 0 }, +- {"PNP0C50", 0 }, +- { }, +-}; +-MODULE_DEVICE_TABLE(acpi, i2c_hid_acpi_match); +-#else +-static inline int i2c_hid_acpi_pdata(struct i2c_client *client, +- struct i2c_hid_platform_data *pdata) +-{ +- return -ENODEV; +-} +- +-static inline void i2c_hid_acpi_fix_up_power(struct device *dev) {} +-#endif +- +-#ifdef CONFIG_OF +-static int i2c_hid_of_probe(struct i2c_client *client, +- struct i2c_hid_platform_data *pdata) +-{ +- struct device *dev = &client->dev; +- u32 val; +- int ret; +- +- ret = of_property_read_u32(dev->of_node, "hid-descr-addr", &val); +- if (ret) { +- dev_err(&client->dev, "HID register address not provided\n"); +- return -ENODEV; +- } +- if (val >> 16) { +- dev_err(&client->dev, "Bad HID register address: 0x%08x\n", +- val); +- return -EINVAL; +- } +- pdata->hid_descriptor_address = val; +- +- return 0; +-} +- +-static const struct of_device_id i2c_hid_of_match[] = { +- { .compatible = "hid-over-i2c" }, +- {}, +-}; +-MODULE_DEVICE_TABLE(of, i2c_hid_of_match); +-#else +-static inline int i2c_hid_of_probe(struct i2c_client *client, +- struct i2c_hid_platform_data *pdata) +-{ +- return -ENODEV; +-} +-#endif +- +-static int i2c_hid_probe(struct i2c_client *client, +- const struct i2c_device_id *dev_id) +-{ +- int ret; +- struct i2c_hid *ihid; +- struct hid_device *hid; +- __u16 hidRegister; +- struct i2c_hid_platform_data *platform_data = client->dev.platform_data; +- +- dbg_hid("HID probe called for i2c 0x%02x\n", client->addr); +- +- ihid = kzalloc(sizeof(struct i2c_hid), GFP_KERNEL); +- if (!ihid) +- return -ENOMEM; +- +- if (client->dev.of_node) { +- ret = i2c_hid_of_probe(client, &ihid->pdata); +- if (ret) +- goto err; +- } else if (!platform_data) { +- ret = i2c_hid_acpi_pdata(client, &ihid->pdata); +- if (ret) { +- dev_err(&client->dev, +- "HID register address not provided\n"); +- goto err; +- } +- } else { +- ihid->pdata = *platform_data; +- } +- +- if (client->irq > 0) { +- ihid->irq = client->irq; +- } else if (ACPI_COMPANION(&client->dev)) { +- ihid->desc = gpiod_get(&client->dev, NULL, GPIOD_IN); +- if (IS_ERR(ihid->desc)) { +- dev_err(&client->dev, "Failed to get GPIO interrupt\n"); +- return PTR_ERR(ihid->desc); +- } +- +- ihid->irq = gpiod_to_irq(ihid->desc); +- if (ihid->irq < 0) { +- gpiod_put(ihid->desc); +- dev_err(&client->dev, "Failed to convert GPIO to IRQ\n"); +- return ihid->irq; +- } +- } +- +- i2c_set_clientdata(client, ihid); +- +- ihid->client = client; +- +- hidRegister = ihid->pdata.hid_descriptor_address; +- ihid->wHIDDescRegister = cpu_to_le16(hidRegister); +- +- init_waitqueue_head(&ihid->wait); +- mutex_init(&ihid->reset_lock); +- +- /* we need to allocate the command buffer without knowing the maximum +- * size of the reports. Let's use HID_MIN_BUFFER_SIZE, then we do the +- * real computation later. */ +- ret = i2c_hid_alloc_buffers(ihid, HID_MIN_BUFFER_SIZE); +- if (ret < 0) +- goto err; +- +- i2c_hid_acpi_fix_up_power(&client->dev); +- +- pm_runtime_get_noresume(&client->dev); +- pm_runtime_set_active(&client->dev); +- pm_runtime_enable(&client->dev); +- device_enable_async_suspend(&client->dev); +- +- /* Make sure there is something at this address */ +- ret = i2c_smbus_read_byte(client); +- if (ret < 0) { +- dev_dbg(&client->dev, "nothing at this address: %d\n", ret); +- ret = -ENXIO; +- goto err_pm; +- } +- +- ret = i2c_hid_fetch_hid_descriptor(ihid); +- if (ret < 0) +- goto err_pm; +- +- ret = i2c_hid_init_irq(client); +- if (ret < 0) +- goto err_pm; +- +- hid = hid_allocate_device(); +- if (IS_ERR(hid)) { +- ret = PTR_ERR(hid); +- goto err_irq; +- } +- +- ihid->hid = hid; +- +- hid->driver_data = client; +- hid->ll_driver = &i2c_hid_ll_driver; +- hid->dev.parent = &client->dev; +- hid->bus = BUS_I2C; +- hid->version = le16_to_cpu(ihid->hdesc.bcdVersion); +- hid->vendor = le16_to_cpu(ihid->hdesc.wVendorID); +- hid->product = le16_to_cpu(ihid->hdesc.wProductID); +- +- snprintf(hid->name, sizeof(hid->name), "%s %04hX:%04hX", +- client->name, hid->vendor, hid->product); +- strlcpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys)); +- +- ihid->quirks = i2c_hid_lookup_quirk(hid->vendor, hid->product); +- +- ret = hid_add_device(hid); +- if (ret) { +- if (ret != -ENODEV) +- hid_err(client, "can't add hid device: %d\n", ret); +- goto err_mem_free; +- } +- +- pm_runtime_put(&client->dev); +- return 0; +- +-err_mem_free: +- hid_destroy_device(hid); +- +-err_irq: +- free_irq(ihid->irq, ihid); +- +-err_pm: +- pm_runtime_put_noidle(&client->dev); +- pm_runtime_disable(&client->dev); +- +-err: +- if (ihid->desc) +- gpiod_put(ihid->desc); +- +- i2c_hid_free_buffers(ihid); +- kfree(ihid); +- return ret; +-} +- +-static int i2c_hid_remove(struct i2c_client *client) +-{ +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- struct hid_device *hid; +- +- pm_runtime_get_sync(&client->dev); +- pm_runtime_disable(&client->dev); +- pm_runtime_set_suspended(&client->dev); +- pm_runtime_put_noidle(&client->dev); +- +- hid = ihid->hid; +- hid_destroy_device(hid); +- +- free_irq(ihid->irq, ihid); +- +- if (ihid->bufsize) +- i2c_hid_free_buffers(ihid); +- +- if (ihid->desc) +- gpiod_put(ihid->desc); +- +- kfree(ihid); +- +- acpi_dev_remove_driver_gpios(ACPI_COMPANION(&client->dev)); +- +- return 0; +-} +- +-static void i2c_hid_shutdown(struct i2c_client *client) +-{ +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- +- i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); +- free_irq(client->irq, ihid); +-} +- +-#ifdef CONFIG_PM_SLEEP +-static int i2c_hid_suspend(struct device *dev) +-{ +- struct i2c_client *client = to_i2c_client(dev); +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- struct hid_device *hid = ihid->hid; +- int ret; +- int wake_status; +- +- if (hid->driver && hid->driver->suspend) { +- /* +- * Wake up the device so that IO issues in +- * HID driver's suspend code can succeed. +- */ +- ret = pm_runtime_resume(dev); +- if (ret < 0) +- return ret; +- +- ret = hid->driver->suspend(hid, PMSG_SUSPEND); +- if (ret < 0) +- return ret; +- } +- +- if (!pm_runtime_suspended(dev)) { +- /* Save some power */ +- i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); +- +- disable_irq(ihid->irq); +- } +- +- if (device_may_wakeup(&client->dev)) { +- wake_status = enable_irq_wake(ihid->irq); +- if (!wake_status) +- ihid->irq_wake_enabled = true; +- else +- hid_warn(hid, "Failed to enable irq wake: %d\n", +- wake_status); +- } +- +- return 0; +-} +- +-static int i2c_hid_resume(struct device *dev) +-{ +- int ret; +- struct i2c_client *client = to_i2c_client(dev); +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- struct hid_device *hid = ihid->hid; +- int wake_status; +- +- if (device_may_wakeup(&client->dev) && ihid->irq_wake_enabled) { +- wake_status = disable_irq_wake(ihid->irq); +- if (!wake_status) +- ihid->irq_wake_enabled = false; +- else +- hid_warn(hid, "Failed to disable irq wake: %d\n", +- wake_status); +- } +- +- /* We'll resume to full power */ +- pm_runtime_disable(dev); +- pm_runtime_set_active(dev); +- pm_runtime_enable(dev); +- +- enable_irq(ihid->irq); +- ret = i2c_hid_hwreset(client); +- if (ret) +- return ret; +- +- if (hid->driver && hid->driver->reset_resume) { +- ret = hid->driver->reset_resume(hid); +- return ret; +- } +- +- return 0; +-} +-#endif +- +-#ifdef CONFIG_PM +-static int i2c_hid_runtime_suspend(struct device *dev) +-{ +- struct i2c_client *client = to_i2c_client(dev); +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- +- i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); +- disable_irq(ihid->irq); +- return 0; +-} +- +-static int i2c_hid_runtime_resume(struct device *dev) +-{ +- struct i2c_client *client = to_i2c_client(dev); +- struct i2c_hid *ihid = i2c_get_clientdata(client); +- +- enable_irq(ihid->irq); +- i2c_hid_set_power(client, I2C_HID_PWR_ON); +- return 0; +-} +-#endif +- +-static const struct dev_pm_ops i2c_hid_pm = { +- SET_SYSTEM_SLEEP_PM_OPS(i2c_hid_suspend, i2c_hid_resume) +- SET_RUNTIME_PM_OPS(i2c_hid_runtime_suspend, i2c_hid_runtime_resume, +- NULL) +-}; +- +-static const struct i2c_device_id i2c_hid_id_table[] = { +- { "hid", 0 }, +- { "hid-over-i2c", 0 }, +- { }, +-}; +-MODULE_DEVICE_TABLE(i2c, i2c_hid_id_table); +- +- +-static struct i2c_driver i2c_hid_driver = { +- .driver = { +- .name = "i2c_hid", +- .pm = &i2c_hid_pm, +- .acpi_match_table = ACPI_PTR(i2c_hid_acpi_match), +- .of_match_table = of_match_ptr(i2c_hid_of_match), +- }, +- +- .probe = i2c_hid_probe, +- .remove = i2c_hid_remove, +- .shutdown = i2c_hid_shutdown, +- .id_table = i2c_hid_id_table, +-}; +- +-module_i2c_driver(i2c_hid_driver); +- +-MODULE_DESCRIPTION("HID over I2C core driver"); +-MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoi...@gmail.com>"); +-MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/i2c-hid/i2c-hid.h b/drivers/hid/i2c-hid/i2c-hid.h +new file mode 100644 +index 000000000000..a8c19aef5824 +--- /dev/null ++++ b/drivers/hid/i2c-hid/i2c-hid.h +@@ -0,0 +1,20 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++ ++#ifndef I2C_HID_H ++#define I2C_HID_H ++ ++ ++#ifdef CONFIG_DMI ++struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name); ++char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, ++ unsigned int *size); ++#else ++static inline struct i2c_hid_desc ++ *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name) ++{ return NULL; } ++static inline char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, ++ unsigned int *size) ++{ return NULL; } ++#endif ++ ++#endif +diff --git a/drivers/infiniband/hw/mlx4/alias_GUID.c b/drivers/infiniband/hw/mlx4/alias_GUID.c +index 5e9939045852..ec138845a474 100644 +--- a/drivers/infiniband/hw/mlx4/alias_GUID.c ++++ b/drivers/infiniband/hw/mlx4/alias_GUID.c +@@ -805,8 +805,8 @@ void mlx4_ib_destroy_alias_guid_service(struct mlx4_ib_dev *dev) + unsigned long flags; + + for (i = 0 ; i < dev->num_ports; i++) { +- cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work); + det = &sriov->alias_guid.ports_guid[i]; ++ cancel_delayed_work_sync(&det->alias_guid_work); + spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags); + while (!list_empty(&det->cb_list)) { + cb_ctx = list_entry(det->cb_list.next, +diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c +index 63110fbbb410..d51734e0c350 100644 +--- a/drivers/iommu/dmar.c ++++ b/drivers/iommu/dmar.c +@@ -143,7 +143,7 @@ dmar_alloc_pci_notify_info(struct pci_dev *dev, unsigned long event) + for (tmp = dev; tmp; tmp = tmp->bus->self) + level++; + +- size = sizeof(*info) + level * sizeof(struct acpi_dmar_pci_path); ++ size = sizeof(*info) + level * sizeof(info->path[0]); + if (size <= sizeof(dmar_pci_notify_info_buf)) { + info = (struct dmar_pci_notify_info *)dmar_pci_notify_info_buf; + } else { +diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c +index 86e349614e21..28feb1744710 100644 +--- a/drivers/iommu/intel-iommu.c ++++ b/drivers/iommu/intel-iommu.c +@@ -1636,6 +1636,9 @@ static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu) + u32 pmen; + unsigned long flags; + ++ if (!cap_plmr(iommu->cap) && !cap_phmr(iommu->cap)) ++ return; ++ + raw_spin_lock_irqsave(&iommu->register_lock, flags); + pmen = readl(iommu->reg + DMAR_PMEN_REG); + pmen &= ~DMA_PMEN_EPM; +diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c +index 05d87f60d929..406bfe618448 100644 +--- a/drivers/irqchip/irq-mbigen.c ++++ b/drivers/irqchip/irq-mbigen.c +@@ -160,6 +160,9 @@ static void mbigen_write_msg(struct msi_desc *desc, struct msi_msg *msg) + void __iomem *base = d->chip_data; + u32 val; + ++ if (!msg->address_lo && !msg->address_hi) ++ return; ++ + base += get_mbigen_vec_reg(d->hwirq); + val = readl_relaxed(base); + +diff --git a/drivers/misc/lkdtm.h b/drivers/misc/lkdtm.h +index fdf954c2107f..6abc97b245e4 100644 +--- a/drivers/misc/lkdtm.h ++++ b/drivers/misc/lkdtm.h +@@ -40,7 +40,9 @@ void lkdtm_EXEC_KMALLOC(void); + void lkdtm_EXEC_VMALLOC(void); + void lkdtm_EXEC_RODATA(void); + void lkdtm_EXEC_USERSPACE(void); ++void lkdtm_EXEC_NULL(void); + void lkdtm_ACCESS_USERSPACE(void); ++void lkdtm_ACCESS_NULL(void); + + /* lkdtm_rodata.c */ + void lkdtm_rodata_do_nothing(void); +diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c +index b2989f2d3126..035e51bea450 100644 +--- a/drivers/misc/lkdtm_core.c ++++ b/drivers/misc/lkdtm_core.c +@@ -214,7 +214,9 @@ struct crashtype crashtypes[] = { + CRASHTYPE(EXEC_VMALLOC), + CRASHTYPE(EXEC_RODATA), + CRASHTYPE(EXEC_USERSPACE), ++ CRASHTYPE(EXEC_NULL), + CRASHTYPE(ACCESS_USERSPACE), ++ CRASHTYPE(ACCESS_NULL), + CRASHTYPE(WRITE_RO), + CRASHTYPE(WRITE_RO_AFTER_INIT), + CRASHTYPE(WRITE_KERN), +diff --git a/drivers/misc/lkdtm_perms.c b/drivers/misc/lkdtm_perms.c +index 45f1c0f96612..1a9dcdaa95f0 100644 +--- a/drivers/misc/lkdtm_perms.c ++++ b/drivers/misc/lkdtm_perms.c +@@ -160,6 +160,11 @@ void lkdtm_EXEC_USERSPACE(void) + vm_munmap(user_addr, PAGE_SIZE); + } + ++void lkdtm_EXEC_NULL(void) ++{ ++ execute_location(NULL, CODE_AS_IS); ++} ++ + void lkdtm_ACCESS_USERSPACE(void) + { + unsigned long user_addr, tmp = 0; +@@ -191,6 +196,19 @@ void lkdtm_ACCESS_USERSPACE(void) + vm_munmap(user_addr, PAGE_SIZE); + } + ++void lkdtm_ACCESS_NULL(void) ++{ ++ unsigned long tmp; ++ unsigned long *ptr = (unsigned long *)NULL; ++ ++ pr_info("attempting bad read at %px\n", ptr); ++ tmp = *ptr; ++ tmp += 0xc0dec0de; ++ ++ pr_info("attempting bad write at %px\n", ptr); ++ *ptr = tmp; ++} ++ + void __init lkdtm_perms_init(void) + { + /* Make sure we can write to __ro_after_init values during __init */ +diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c +index 8fa478c3b0db..619457b90dc7 100644 +--- a/drivers/mmc/host/davinci_mmc.c ++++ b/drivers/mmc/host/davinci_mmc.c +@@ -1120,7 +1120,7 @@ static inline void mmc_davinci_cpufreq_deregister(struct mmc_davinci_host *host) + { + } + #endif +-static void __init init_mmcsd_host(struct mmc_davinci_host *host) ++static void init_mmcsd_host(struct mmc_davinci_host *host) + { + + mmc_davinci_reset_ctrl(host, 1); +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +index fc437d75ac76..b46b56ad7517 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -1747,11 +1747,6 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) + if (ret < 0) + pr_warn("%s: failed debugFS registration\n", __func__); + #endif +- /* Start the ball rolling... */ +- pr_debug("%s: DMA RX/TX processes started...\n", dev->name); +- priv->hw->dma->start_tx(priv->ioaddr); +- priv->hw->dma->start_rx(priv->ioaddr); +- + /* Dump DMA/MAC registers */ + if (netif_msg_hw(priv)) { + priv->hw->mac->dump_regs(priv->hw); +@@ -1779,6 +1774,11 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) + if (priv->tso) + priv->hw->dma->enable_tso(priv->ioaddr, 1, STMMAC_CHAN0); + ++ /* Start the ball rolling... */ ++ pr_debug("%s: DMA RX/TX processes started...\n", dev->name); ++ priv->hw->dma->start_tx(priv->ioaddr); ++ priv->hw->dma->start_rx(priv->ioaddr); ++ + return 0; + } + +diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h +index d3fbe33d2324..a13f08fd8690 100644 +--- a/drivers/net/wireless/rsi/rsi_common.h ++++ b/drivers/net/wireless/rsi/rsi_common.h +@@ -75,7 +75,6 @@ static inline int rsi_kill_thread(struct rsi_thread *handle) + atomic_inc(&handle->thread_done); + rsi_set_event(&handle->event); + +- wait_for_completion(&handle->completion); + return kthread_stop(handle->task); + } + +diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c +index 9685f9b8be07..a12710c917a1 100644 +--- a/drivers/soc/tegra/pmc.c ++++ b/drivers/soc/tegra/pmc.c +@@ -512,16 +512,10 @@ EXPORT_SYMBOL(tegra_powergate_power_off); + */ + int tegra_powergate_is_powered(unsigned int id) + { +- int status; +- + if (!tegra_powergate_is_valid(id)) + return -EINVAL; + +- mutex_lock(&pmc->powergates_lock); +- status = tegra_powergate_state(id); +- mutex_unlock(&pmc->powergates_lock); +- +- return status; ++ return tegra_powergate_state(id); + } + + /** +diff --git a/drivers/thermal/int340x_thermal/int3400_thermal.c b/drivers/thermal/int340x_thermal/int3400_thermal.c +index 5836e5554433..d4c374cc4f74 100644 +--- a/drivers/thermal/int340x_thermal/int3400_thermal.c ++++ b/drivers/thermal/int340x_thermal/int3400_thermal.c +@@ -20,6 +20,13 @@ enum int3400_thermal_uuid { + INT3400_THERMAL_PASSIVE_1, + INT3400_THERMAL_ACTIVE, + INT3400_THERMAL_CRITICAL, ++ INT3400_THERMAL_ADAPTIVE_PERFORMANCE, ++ INT3400_THERMAL_EMERGENCY_CALL_MODE, ++ INT3400_THERMAL_PASSIVE_2, ++ INT3400_THERMAL_POWER_BOSS, ++ INT3400_THERMAL_VIRTUAL_SENSOR, ++ INT3400_THERMAL_COOLING_MODE, ++ INT3400_THERMAL_HARDWARE_DUTY_CYCLING, + INT3400_THERMAL_MAXIMUM_UUID, + }; + +@@ -27,6 +34,13 @@ static u8 *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = { + "42A441D6-AE6A-462b-A84B-4A8CE79027D3", + "3A95C389-E4B8-4629-A526-C52C88626BAE", + "97C68AE7-15FA-499c-B8C9-5DA81D606E0A", ++ "63BE270F-1C11-48FD-A6F7-3AF253FF3E2D", ++ "5349962F-71E6-431D-9AE8-0A635B710AEE", ++ "9E04115A-AE87-4D1C-9500-0F3E340BFE75", ++ "F5A35014-C209-46A4-993A-EB56DE7530A1", ++ "6ED722A7-9240-48A5-B479-31EEF723D7CF", ++ "16CAF1B7-DD38-40ED-B1C1-1B8A1913D531", ++ "BE84BABF-C4D4-403D-B495-3128FD44dAC1", + }; + + struct int3400_thermal_priv { +@@ -271,10 +285,9 @@ static int int3400_thermal_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, priv); + +- if (priv->uuid_bitmap & 1 << INT3400_THERMAL_PASSIVE_1) { +- int3400_thermal_ops.get_mode = int3400_thermal_get_mode; +- int3400_thermal_ops.set_mode = int3400_thermal_set_mode; +- } ++ int3400_thermal_ops.get_mode = int3400_thermal_get_mode; ++ int3400_thermal_ops.set_mode = int3400_thermal_set_mode; ++ + priv->thermal = thermal_zone_device_register("INT3400 Thermal", 0, 0, + priv, &int3400_thermal_ops, + &int3400_thermal_params, 0, 0); +diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c +index ffb474c49f0f..eb61a07fcbbc 100644 +--- a/drivers/tty/serial/xilinx_uartps.c ++++ b/drivers/tty/serial/xilinx_uartps.c +@@ -1261,7 +1261,7 @@ static void cdns_uart_console_write(struct console *co, const char *s, + * + * Return: 0 on success, negative errno otherwise. + */ +-static int __init cdns_uart_console_setup(struct console *co, char *options) ++static int cdns_uart_console_setup(struct console *co, char *options) + { + struct uart_port *port = &cdns_uart_port[co->index]; + int baud = 9600; +diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c +index 072e7599583a..a8ff43068619 100644 +--- a/fs/9p/v9fs.c ++++ b/fs/9p/v9fs.c +@@ -59,6 +59,8 @@ enum { + Opt_cache_loose, Opt_fscache, Opt_mmap, + /* Access options */ + Opt_access, Opt_posixacl, ++ /* Lock timeout option */ ++ Opt_locktimeout, + /* Error token */ + Opt_err + }; +@@ -78,6 +80,7 @@ static const match_table_t tokens = { + {Opt_cachetag, "cachetag=%s"}, + {Opt_access, "access=%s"}, + {Opt_posixacl, "posixacl"}, ++ {Opt_locktimeout, "locktimeout=%u"}, + {Opt_err, NULL} + }; + +@@ -126,6 +129,7 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) + #ifdef CONFIG_9P_FSCACHE + v9ses->cachetag = NULL; + #endif ++ v9ses->session_lock_timeout = P9_LOCK_TIMEOUT; + + if (!opts) + return 0; +@@ -298,6 +302,23 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) + #endif + break; + ++ case Opt_locktimeout: ++ r = match_int(&args[0], &option); ++ if (r < 0) { ++ p9_debug(P9_DEBUG_ERROR, ++ "integer field, but no integer?\n"); ++ ret = r; ++ continue; ++ } ++ if (option < 1) { ++ p9_debug(P9_DEBUG_ERROR, ++ "locktimeout must be a greater than zero integer.\n"); ++ ret = -EINVAL; ++ continue; ++ } ++ v9ses->session_lock_timeout = (long)option * HZ; ++ break; ++ + default: + continue; + } +diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h +index 443d12e02043..ce6ca9f4f683 100644 +--- a/fs/9p/v9fs.h ++++ b/fs/9p/v9fs.h +@@ -116,6 +116,7 @@ struct v9fs_session_info { + struct list_head slist; /* list of sessions registered with v9fs */ + struct backing_dev_info bdi; + struct rw_semaphore rename_sem; ++ long session_lock_timeout; /* retry interval for blocking locks */ + }; + + /* cache_validity flags */ +diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c +index 48db9a9f13f9..cb6c4031af55 100644 +--- a/fs/9p/vfs_dir.c ++++ b/fs/9p/vfs_dir.c +@@ -105,7 +105,6 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx) + int err = 0; + struct p9_fid *fid; + int buflen; +- int reclen = 0; + struct p9_rdir *rdir; + struct kvec kvec; + +@@ -138,11 +137,10 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx) + while (rdir->head < rdir->tail) { + err = p9stat_read(fid->clnt, rdir->buf + rdir->head, + rdir->tail - rdir->head, &st); +- if (err) { ++ if (err <= 0) { + p9_debug(P9_DEBUG_VFS, "returned %d\n", err); + return -EIO; + } +- reclen = st.size+2; + + over = !dir_emit(ctx, st.name, strlen(st.name), + v9fs_qid2ino(&st.qid), dt_type(&st)); +@@ -150,8 +148,8 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx) + if (over) + return 0; + +- rdir->head += reclen; +- ctx->pos += reclen; ++ rdir->head += err; ++ ctx->pos += err; + } + } + } +diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c +index 2f035b15180e..79ff727254bb 100644 +--- a/fs/9p/vfs_file.c ++++ b/fs/9p/vfs_file.c +@@ -154,6 +154,7 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl) + uint8_t status = P9_LOCK_ERROR; + int res = 0; + unsigned char fl_type; ++ struct v9fs_session_info *v9ses; + + fid = filp->private_data; + BUG_ON(fid == NULL); +@@ -189,6 +190,8 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl) + if (IS_SETLKW(cmd)) + flock.flags = P9_LOCK_FLAGS_BLOCK; + ++ v9ses = v9fs_inode2v9ses(file_inode(filp)); ++ + /* + * if its a blocked request and we get P9_LOCK_BLOCKED as the status + * for lock request, keep on trying +@@ -202,7 +205,8 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl) + break; + if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd)) + break; +- if (schedule_timeout_interruptible(P9_LOCK_TIMEOUT) != 0) ++ if (schedule_timeout_interruptible(v9ses->session_lock_timeout) ++ != 0) + break; + /* + * p9_client_lock_dotl overwrites flock.client_id with the +diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c +index 57c938ffeb6e..a8a2fc9ae056 100644 +--- a/fs/cifs/inode.c ++++ b/fs/cifs/inode.c +@@ -771,43 +771,50 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, + } else if ((rc == -EACCES) && backup_cred(cifs_sb) && + (strcmp(server->vals->version_string, SMB1_VERSION_STRING) + == 0)) { +- /* +- * For SMB2 and later the backup intent flag is already +- * sent if needed on open and there is no path based +- * FindFirst operation to use to retry with +- */ ++ /* ++ * For SMB2 and later the backup intent flag is already ++ * sent if needed on open and there is no path based ++ * FindFirst operation to use to retry with ++ */ + +- srchinf = kzalloc(sizeof(struct cifs_search_info), +- GFP_KERNEL); +- if (srchinf == NULL) { +- rc = -ENOMEM; +- goto cgii_exit; +- } ++ srchinf = kzalloc(sizeof(struct cifs_search_info), ++ GFP_KERNEL); ++ if (srchinf == NULL) { ++ rc = -ENOMEM; ++ goto cgii_exit; ++ } + +- srchinf->endOfSearch = false; ++ srchinf->endOfSearch = false; ++ if (tcon->unix_ext) ++ srchinf->info_level = SMB_FIND_FILE_UNIX; ++ else if ((tcon->ses->capabilities & ++ tcon->ses->server->vals->cap_nt_find) == 0) ++ srchinf->info_level = SMB_FIND_FILE_INFO_STANDARD; ++ else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) + srchinf->info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; ++ else /* no srvino useful for fallback to some netapp */ ++ srchinf->info_level = SMB_FIND_FILE_DIRECTORY_INFO; + +- srchflgs = CIFS_SEARCH_CLOSE_ALWAYS | +- CIFS_SEARCH_CLOSE_AT_END | +- CIFS_SEARCH_BACKUP_SEARCH; ++ srchflgs = CIFS_SEARCH_CLOSE_ALWAYS | ++ CIFS_SEARCH_CLOSE_AT_END | ++ CIFS_SEARCH_BACKUP_SEARCH; + +- rc = CIFSFindFirst(xid, tcon, full_path, +- cifs_sb, NULL, srchflgs, srchinf, false); +- if (!rc) { +- data = +- (FILE_ALL_INFO *)srchinf->srch_entries_start; ++ rc = CIFSFindFirst(xid, tcon, full_path, ++ cifs_sb, NULL, srchflgs, srchinf, false); ++ if (!rc) { ++ data = (FILE_ALL_INFO *)srchinf->srch_entries_start; + +- cifs_dir_info_to_fattr(&fattr, +- (FILE_DIRECTORY_INFO *)data, cifs_sb); +- fattr.cf_uniqueid = le64_to_cpu( +- ((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId); +- validinum = true; ++ cifs_dir_info_to_fattr(&fattr, ++ (FILE_DIRECTORY_INFO *)data, cifs_sb); ++ fattr.cf_uniqueid = le64_to_cpu( ++ ((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId); ++ validinum = true; + +- cifs_buf_release(srchinf->ntwrk_buf_start); +- } +- kfree(srchinf); +- if (rc) +- goto cgii_exit; ++ cifs_buf_release(srchinf->ntwrk_buf_start); ++ } ++ kfree(srchinf); ++ if (rc) ++ goto cgii_exit; + } else + goto cgii_exit; + +diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c +index 98c25b969ab8..7e93d5706bf6 100644 +--- a/fs/cifs/smb2maperror.c ++++ b/fs/cifs/smb2maperror.c +@@ -1034,7 +1034,8 @@ static const struct status_to_posix_error smb2_error_map_table[] = { + {STATUS_UNFINISHED_CONTEXT_DELETED, -EIO, + "STATUS_UNFINISHED_CONTEXT_DELETED"}, + {STATUS_NO_TGT_REPLY, -EIO, "STATUS_NO_TGT_REPLY"}, +- {STATUS_OBJECTID_NOT_FOUND, -EIO, "STATUS_OBJECTID_NOT_FOUND"}, ++ /* Note that ENOATTTR and ENODATA are the same errno */ ++ {STATUS_OBJECTID_NOT_FOUND, -ENODATA, "STATUS_OBJECTID_NOT_FOUND"}, + {STATUS_NO_IP_ADDRESSES, -EIO, "STATUS_NO_IP_ADDRESSES"}, + {STATUS_WRONG_CREDENTIAL_HANDLE, -EIO, + "STATUS_WRONG_CREDENTIAL_HANDLE"}, +diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c +index 2880e017cd0a..2ce73287b53c 100644 +--- a/fs/ext4/ioctl.c ++++ b/fs/ext4/ioctl.c +@@ -749,6 +749,13 @@ resizefs_out: + if (!blk_queue_discard(q)) + return -EOPNOTSUPP; + ++ /* ++ * We haven't replayed the journal, so we cannot use our ++ * block-bitmap-guided storage zapping commands. ++ */ ++ if (test_opt(sb, NOLOAD) && ext4_has_feature_journal(sb)) ++ return -EROFS; ++ + if (copy_from_user(&range, (struct fstrim_range __user *)arg, + sizeof(range))) + return -EFAULT; +diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c +index 67b359629a66..aef2a24dc9f9 100644 +--- a/fs/ext4/resize.c ++++ b/fs/ext4/resize.c +@@ -907,11 +907,18 @@ static int add_new_gdb_meta_bg(struct super_block *sb, + memcpy(n_group_desc, o_group_desc, + EXT4_SB(sb)->s_gdb_count * sizeof(struct buffer_head *)); + n_group_desc[gdb_num] = gdb_bh; ++ ++ BUFFER_TRACE(gdb_bh, "get_write_access"); ++ err = ext4_journal_get_write_access(handle, gdb_bh); ++ if (err) { ++ kvfree(n_group_desc); ++ brelse(gdb_bh); ++ return err; ++ } ++ + EXT4_SB(sb)->s_group_desc = n_group_desc; + EXT4_SB(sb)->s_gdb_count++; + kvfree(o_group_desc); +- BUFFER_TRACE(gdb_bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, gdb_bh); + return err; + } + +@@ -2040,6 +2047,10 @@ out: + free_flex_gd(flex_gd); + if (resize_inode != NULL) + iput(resize_inode); +- ext4_msg(sb, KERN_INFO, "resized filesystem to %llu", n_blocks_count); ++ if (err) ++ ext4_warning(sb, "error (%d) occurred during " ++ "file system resize", err); ++ ext4_msg(sb, KERN_INFO, "resized filesystem to %llu", ++ ext4_blocks_count(es)); + return err; + } +diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c +index 83a96334dc07..4ebe69572475 100644 +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -1489,7 +1489,7 @@ int sanity_check_ckpt(struct f2fs_sb_info *sbi) + unsigned int segment_count_main; + unsigned int cp_pack_start_sum, cp_payload; + block_t user_block_count; +- int i; ++ int i, j; + + total = le32_to_cpu(raw_super->segment_count); + fsmeta = le32_to_cpu(raw_super->segment_count_ckpt); +@@ -1530,11 +1530,43 @@ int sanity_check_ckpt(struct f2fs_sb_info *sbi) + if (le32_to_cpu(ckpt->cur_node_segno[i]) >= main_segs || + le16_to_cpu(ckpt->cur_node_blkoff[i]) >= blocks_per_seg) + return 1; ++ for (j = i + 1; j < NR_CURSEG_NODE_TYPE; j++) { ++ if (le32_to_cpu(ckpt->cur_node_segno[i]) == ++ le32_to_cpu(ckpt->cur_node_segno[j])) { ++ f2fs_msg(sbi->sb, KERN_ERR, ++ "Node segment (%u, %u) has the same " ++ "segno: %u", i, j, ++ le32_to_cpu(ckpt->cur_node_segno[i])); ++ return 1; ++ } ++ } + } + for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) { + if (le32_to_cpu(ckpt->cur_data_segno[i]) >= main_segs || + le16_to_cpu(ckpt->cur_data_blkoff[i]) >= blocks_per_seg) + return 1; ++ for (j = i + 1; j < NR_CURSEG_DATA_TYPE; j++) { ++ if (le32_to_cpu(ckpt->cur_data_segno[i]) == ++ le32_to_cpu(ckpt->cur_data_segno[j])) { ++ f2fs_msg(sbi->sb, KERN_ERR, ++ "Data segment (%u, %u) has the same " ++ "segno: %u", i, j, ++ le32_to_cpu(ckpt->cur_data_segno[i])); ++ return 1; ++ } ++ } ++ } ++ for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) { ++ for (j = i; j < NR_CURSEG_DATA_TYPE; j++) { ++ if (le32_to_cpu(ckpt->cur_node_segno[i]) == ++ le32_to_cpu(ckpt->cur_data_segno[j])) { ++ f2fs_msg(sbi->sb, KERN_ERR, ++ "Data segment (%u) and Data segment (%u)" ++ " has the same segno: %u", i, j, ++ le32_to_cpu(ckpt->cur_node_segno[i])); ++ return 1; ++ } ++ } + } + + sit_bitmap_size = le32_to_cpu(ckpt->sit_ver_bitmap_bytesize); +diff --git a/include/linux/atalk.h b/include/linux/atalk.h +index 73fd8b7e9534..af43ed404ff4 100644 +--- a/include/linux/atalk.h ++++ b/include/linux/atalk.h +@@ -150,19 +150,29 @@ extern int sysctl_aarp_retransmit_limit; + extern int sysctl_aarp_resolve_time; + + #ifdef CONFIG_SYSCTL +-extern void atalk_register_sysctl(void); ++extern int atalk_register_sysctl(void); + extern void atalk_unregister_sysctl(void); + #else +-#define atalk_register_sysctl() do { } while(0) +-#define atalk_unregister_sysctl() do { } while(0) ++static inline int atalk_register_sysctl(void) ++{ ++ return 0; ++} ++static inline void atalk_unregister_sysctl(void) ++{ ++} + #endif + + #ifdef CONFIG_PROC_FS + extern int atalk_proc_init(void); + extern void atalk_proc_exit(void); + #else +-#define atalk_proc_init() ({ 0; }) +-#define atalk_proc_exit() do { } while(0) ++static inline int atalk_proc_init(void) ++{ ++ return 0; ++} ++static inline void atalk_proc_exit(void) ++{ ++} + #endif /* CONFIG_PROC_FS */ + + #endif /* __LINUX_ATALK_H__ */ +diff --git a/include/linux/swap.h b/include/linux/swap.h +index 55ff5593c193..2228907d08ff 100644 +--- a/include/linux/swap.h ++++ b/include/linux/swap.h +@@ -135,9 +135,9 @@ struct swap_extent { + /* + * Max bad pages in the new format.. + */ +-#define __swapoffset(x) ((unsigned long)&((union swap_header *)0)->x) + #define MAX_SWAP_BADPAGES \ +- ((__swapoffset(magic.magic) - __swapoffset(info.badpages)) / sizeof(int)) ++ ((offsetof(union swap_header, magic.magic) - \ ++ offsetof(union swap_header, info.badpages)) / sizeof(int)) + + enum { + SWP_USED = (1 << 0), /* is slot in swap_info[] used? */ +diff --git a/kernel/events/core.c b/kernel/events/core.c +index 5cbb2eda80b5..7929526e96e2 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -6616,6 +6616,7 @@ static void perf_event_mmap_output(struct perf_event *event, + struct perf_output_handle handle; + struct perf_sample_data sample; + int size = mmap_event->event_id.header.size; ++ u32 type = mmap_event->event_id.header.type; + int ret; + + if (!perf_event_mmap_match(event, data)) +@@ -6659,6 +6660,7 @@ static void perf_event_mmap_output(struct perf_event *event, + perf_output_end(&handle); + out: + mmap_event->event_id.header.size = size; ++ mmap_event->event_id.header.type = type; + } + + static void perf_event_mmap_event(struct perf_mmap_event *mmap_event) +diff --git a/kernel/hung_task.c b/kernel/hung_task.c +index fd781a468f32..fb00cf30abd1 100644 +--- a/kernel/hung_task.c ++++ b/kernel/hung_task.c +@@ -15,6 +15,7 @@ + #include <linux/lockdep.h> + #include <linux/export.h> + #include <linux/sysctl.h> ++#include <linux/suspend.h> + #include <linux/utsname.h> + #include <trace/events/sched.h> + +@@ -221,6 +222,28 @@ void reset_hung_task_detector(void) + } + EXPORT_SYMBOL_GPL(reset_hung_task_detector); + ++static bool hung_detector_suspended; ++ ++static int hungtask_pm_notify(struct notifier_block *self, ++ unsigned long action, void *hcpu) ++{ ++ switch (action) { ++ case PM_SUSPEND_PREPARE: ++ case PM_HIBERNATION_PREPARE: ++ case PM_RESTORE_PREPARE: ++ hung_detector_suspended = true; ++ break; ++ case PM_POST_SUSPEND: ++ case PM_POST_HIBERNATION: ++ case PM_POST_RESTORE: ++ hung_detector_suspended = false; ++ break; ++ default: ++ break; ++ } ++ return NOTIFY_OK; ++} ++ + /* + * kthread which checks for tasks stuck in D state + */ +@@ -235,7 +258,8 @@ static int watchdog(void *dummy) + long t = hung_timeout_jiffies(hung_last_checked, timeout); + + if (t <= 0) { +- if (!atomic_xchg(&reset_hung_task, 0)) ++ if (!atomic_xchg(&reset_hung_task, 0) && ++ !hung_detector_suspended) + check_hung_uninterruptible_tasks(timeout); + hung_last_checked = jiffies; + continue; +@@ -249,6 +273,10 @@ static int watchdog(void *dummy) + static int __init hung_task_init(void) + { + atomic_notifier_chain_register(&panic_notifier_list, &panic_block); ++ ++ /* Disable hung task detector on suspend */ ++ pm_notifier(hungtask_pm_notify, 0); ++ + watchdog_task = kthread_run(watchdog, NULL, "khungtaskd"); + + return 0; +diff --git a/lib/div64.c b/lib/div64.c +index 7f345259c32f..c1c1a4c36dd5 100644 +--- a/lib/div64.c ++++ b/lib/div64.c +@@ -102,7 +102,7 @@ u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder) + quot = div_u64_rem(dividend, divisor, &rem32); + *remainder = rem32; + } else { +- int n = 1 + fls(high); ++ int n = fls(high); + quot = div_u64(dividend >> n, divisor >> n); + + if (quot != 0) +@@ -140,7 +140,7 @@ u64 div64_u64(u64 dividend, u64 divisor) + if (high == 0) { + quot = div_u64(dividend, divisor); + } else { +- int n = 1 + fls(high); ++ int n = fls(high); + quot = div_u64(dividend >> n, divisor >> n); + + if (quot != 0) +diff --git a/net/9p/protocol.c b/net/9p/protocol.c +index 145f80518064..7f1b45c082c9 100644 +--- a/net/9p/protocol.c ++++ b/net/9p/protocol.c +@@ -570,9 +570,10 @@ int p9stat_read(struct p9_client *clnt, char *buf, int len, struct p9_wstat *st) + if (ret) { + p9_debug(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); + trace_9p_protocol_dump(clnt, &fake_pdu); ++ return ret; + } + +- return ret; ++ return fake_pdu.offset; + } + EXPORT_SYMBOL(p9stat_read); + +diff --git a/net/appletalk/atalk_proc.c b/net/appletalk/atalk_proc.c +index af46bc49e1e9..b5f84f428aa6 100644 +--- a/net/appletalk/atalk_proc.c ++++ b/net/appletalk/atalk_proc.c +@@ -293,7 +293,7 @@ out_interface: + goto out; + } + +-void __exit atalk_proc_exit(void) ++void atalk_proc_exit(void) + { + remove_proc_entry("interface", atalk_proc_dir); + remove_proc_entry("route", atalk_proc_dir); +diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c +index 10d2bdce686e..e206d98b3b82 100644 +--- a/net/appletalk/ddp.c ++++ b/net/appletalk/ddp.c +@@ -1912,12 +1912,16 @@ static const char atalk_err_snap[] __initconst = + /* Called by proto.c on kernel start up */ + static int __init atalk_init(void) + { +- int rc = proto_register(&ddp_proto, 0); ++ int rc; + +- if (rc != 0) ++ rc = proto_register(&ddp_proto, 0); ++ if (rc) + goto out; + +- (void)sock_register(&atalk_family_ops); ++ rc = sock_register(&atalk_family_ops); ++ if (rc) ++ goto out_proto; ++ + ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv); + if (!ddp_dl) + printk(atalk_err_snap); +@@ -1925,12 +1929,33 @@ static int __init atalk_init(void) + dev_add_pack(<alk_packet_type); + dev_add_pack(&ppptalk_packet_type); + +- register_netdevice_notifier(&ddp_notifier); ++ rc = register_netdevice_notifier(&ddp_notifier); ++ if (rc) ++ goto out_sock; ++ + aarp_proto_init(); +- atalk_proc_init(); +- atalk_register_sysctl(); ++ rc = atalk_proc_init(); ++ if (rc) ++ goto out_aarp; ++ ++ rc = atalk_register_sysctl(); ++ if (rc) ++ goto out_proc; + out: + return rc; ++out_proc: ++ atalk_proc_exit(); ++out_aarp: ++ aarp_cleanup_module(); ++ unregister_netdevice_notifier(&ddp_notifier); ++out_sock: ++ dev_remove_pack(&ppptalk_packet_type); ++ dev_remove_pack(<alk_packet_type); ++ unregister_snap_client(ddp_dl); ++ sock_unregister(PF_APPLETALK); ++out_proto: ++ proto_unregister(&ddp_proto); ++ goto out; + } + module_init(atalk_init); + +diff --git a/net/appletalk/sysctl_net_atalk.c b/net/appletalk/sysctl_net_atalk.c +index ebb864361f7a..4e6042e0fcac 100644 +--- a/net/appletalk/sysctl_net_atalk.c ++++ b/net/appletalk/sysctl_net_atalk.c +@@ -44,9 +44,12 @@ static struct ctl_table atalk_table[] = { + + static struct ctl_table_header *atalk_table_header; + +-void atalk_register_sysctl(void) ++int __init atalk_register_sysctl(void) + { + atalk_table_header = register_net_sysctl(&init_net, "net/appletalk", atalk_table); ++ if (!atalk_table_header) ++ return -ENOMEM; ++ return 0; + } + + void atalk_unregister_sysctl(void) +diff --git a/sound/drivers/opl3/opl3_voice.h b/sound/drivers/opl3/opl3_voice.h +index a371c075ac87..e26702559f61 100644 +--- a/sound/drivers/opl3/opl3_voice.h ++++ b/sound/drivers/opl3/opl3_voice.h +@@ -41,7 +41,7 @@ void snd_opl3_timer_func(unsigned long data); + + /* Prototypes for opl3_drums.c */ + void snd_opl3_load_drums(struct snd_opl3 *opl3); +-void snd_opl3_drum_switch(struct snd_opl3 *opl3, int note, int on_off, int vel, struct snd_midi_channel *chan); ++void snd_opl3_drum_switch(struct snd_opl3 *opl3, int note, int vel, int on_off, struct snd_midi_channel *chan); + + /* Prototypes for opl3_oss.c */ + #ifdef CONFIG_SND_SEQUENCER_OSS +diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c +index ad42d2364199..e75bfc511e3e 100644 +--- a/sound/isa/sb/sb8.c ++++ b/sound/isa/sb/sb8.c +@@ -111,6 +111,10 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev) + + /* block the 0x388 port to avoid PnP conflicts */ + acard->fm_res = request_region(0x388, 4, "SoundBlaster FM"); ++ if (!acard->fm_res) { ++ err = -EBUSY; ++ goto _err; ++ } + + if (port[dev] != SNDRV_AUTO_PORT) { + if ((err = snd_sbdsp_create(card, port[dev], irq[dev], +diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c +index 286f5e3686a3..d73ee11a32bd 100644 +--- a/sound/pci/echoaudio/echoaudio.c ++++ b/sound/pci/echoaudio/echoaudio.c +@@ -1953,6 +1953,11 @@ static int snd_echo_create(struct snd_card *card, + } + chip->dsp_registers = (volatile u32 __iomem *) + ioremap_nocache(chip->dsp_registers_phys, sz); ++ if (!chip->dsp_registers) { ++ dev_err(chip->card->dev, "ioremap failed\n"); ++ snd_echo_free(chip); ++ return -ENOMEM; ++ } + + if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED, + KBUILD_MODNAME, chip)) { +diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt +index cb081ac59fd1..bd359a04cb94 100644 +--- a/tools/perf/Documentation/perf-config.txt ++++ b/tools/perf/Documentation/perf-config.txt +@@ -112,7 +112,7 @@ Given a $HOME/.perfconfig like this: + + [report] + # Defaults +- sort-order = comm,dso,symbol ++ sort_order = comm,dso,symbol + percent-limit = 0 + queue-size = 0 + children = true +diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c +index e68c866ae798..cd2900ac473f 100644 +--- a/tools/perf/builtin-top.c ++++ b/tools/perf/builtin-top.c +@@ -1323,8 +1323,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) + goto out_delete_evlist; + + symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); +- if (symbol__init(NULL) < 0) +- return -1; ++ status = symbol__init(NULL); ++ if (status < 0) ++ goto out_delete_evlist; + + sort__setup_elide(stdout); + +diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c +index ea772d41e472..b5d0be524655 100644 +--- a/tools/perf/tests/evsel-tp-sched.c ++++ b/tools/perf/tests/evsel-tp-sched.c +@@ -84,5 +84,6 @@ int test__perf_evsel__tp_sched_test(int subtest __maybe_unused) + if (perf_evsel__test_field(evsel, "target_cpu", 4, true)) + ret = -1; + ++ perf_evsel__delete(evsel); + return ret; + } +diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c +index c8d9592eb142..75d504e9eeaf 100644 +--- a/tools/perf/tests/openat-syscall-all-cpus.c ++++ b/tools/perf/tests/openat-syscall-all-cpus.c +@@ -38,7 +38,7 @@ int test__openat_syscall_event_on_all_cpus(int subtest __maybe_unused) + if (IS_ERR(evsel)) { + tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "syscalls", "sys_enter_openat"); + pr_debug("%s\n", errbuf); +- goto out_thread_map_delete; ++ goto out_cpu_map_delete; + } + + if (perf_evsel__open(evsel, cpus, threads) < 0) { +@@ -112,6 +112,8 @@ out_close_fd: + perf_evsel__close_fd(evsel, 1, threads->nr); + out_evsel_delete: + perf_evsel__delete(evsel); ++out_cpu_map_delete: ++ cpu_map__put(cpus); + out_thread_map_delete: + thread_map__put(threads); + return err; +diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c +index 993ef2762508..32aab95e1459 100644 +--- a/tools/perf/util/build-id.c ++++ b/tools/perf/util/build-id.c +@@ -176,6 +176,7 @@ char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size) + return bf; + } + ++/* The caller is responsible to free the returned buffer. */ + char *build_id_cache__origname(const char *sbuild_id) + { + char *linkname; +diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c +index 18dae745034f..1d66f8eab9f9 100644 +--- a/tools/perf/util/config.c ++++ b/tools/perf/util/config.c +@@ -595,11 +595,10 @@ static int collect_config(const char *var, const char *value, + } + + ret = set_value(item, value); +- return ret; + + out_free: + free(key); +- return -1; ++ return ret; + } + + static int perf_config_set__init(struct perf_config_set *set) +diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c +index f7128c2a6386..a62f79558146 100644 +--- a/tools/perf/util/evsel.c ++++ b/tools/perf/util/evsel.c +@@ -1167,6 +1167,7 @@ void perf_evsel__exit(struct perf_evsel *evsel) + { + assert(list_empty(&evsel->node)); + assert(evsel->evlist == NULL); ++ perf_evsel__free_counts(evsel); + perf_evsel__free_fd(evsel); + perf_evsel__free_id(evsel); + perf_evsel__free_config_terms(evsel); +diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c +index ad613ea51434..82833ceba339 100644 +--- a/tools/perf/util/hist.c ++++ b/tools/perf/util/hist.c +@@ -1027,8 +1027,10 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, + + err = sample__resolve_callchain(iter->sample, &callchain_cursor, &iter->parent, + iter->evsel, al, max_stack_depth); +- if (err) ++ if (err) { ++ map__put(alm); + return err; ++ } + + err = iter->ops->prepare_entry(iter, al); + if (err) +diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c +index 14f111a10650..6193be6d7639 100644 +--- a/tools/perf/util/parse-events.c ++++ b/tools/perf/util/parse-events.c +@@ -2104,6 +2104,7 @@ void print_sdt_events(const char *subsys_glob, const char *event_glob, + printf(" %-50s [%s]\n", buf, "SDT event"); + free(buf); + } ++ free(path); + } else + printf(" %-50s [%s]\n", nd->s, "SDT event"); + if (nd2) { +diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c +index 5ec2de8f49b4..b4c5d96e54c1 100644 +--- a/tools/power/x86/turbostat/turbostat.c ++++ b/tools/power/x86/turbostat/turbostat.c +@@ -3691,6 +3691,9 @@ int fork_it(char **argv) + signal(SIGQUIT, SIG_IGN); + if (waitpid(child_pid, &status, 0) == -1) + err(status, "waitpid"); ++ ++ if (WIFEXITED(status)) ++ status = WEXITSTATUS(status); + } + /* + * n.b. fork_it() does not check for errors from for_all_cpus()