Merge 00e4db5125
("Merge tag 'perf-tools-2020-08-10' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux") into android-mainline
Tiny steps on the way to 5.9-rc1. Fixes conflicts in: fs/f2fs/inline.c Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I16d863ae44a51156499458e8c3486587cbe2babe
This commit is contained in:
15
Documentation/ABI/testing/sysfs-driver-input-exc3000
Normal file
15
Documentation/ABI/testing/sysfs-driver-input-exc3000
Normal file
@@ -0,0 +1,15 @@
|
||||
What: /sys/bus/i2c/devices/xxx/fw_version
|
||||
Date: Aug 2020
|
||||
Contact: linux-input@vger.kernel.org
|
||||
Description: Reports the firmware version provided by the touchscreen, for example "00_T6" on a EXC80H60
|
||||
|
||||
Access: Read
|
||||
Valid values: Represented as string
|
||||
|
||||
What: /sys/bus/i2c/devices/xxx/model
|
||||
Date: Aug 2020
|
||||
Contact: linux-input@vger.kernel.org
|
||||
Description: Reports the model identification provided by the touchscreen, for example "Orion_1320" on a EXC80H60
|
||||
|
||||
Access: Read
|
||||
Valid values: Represented as string
|
@@ -229,7 +229,9 @@ Date: August 2017
|
||||
Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
|
||||
Description: Do background GC agressively when set. When gc_urgent = 1,
|
||||
background thread starts to do GC by given gc_urgent_sleep_time
|
||||
interval. It is set to 0 by default.
|
||||
interval. When gc_urgent = 2, F2FS will lower the bar of
|
||||
checking idle in order to process outstanding discard commands
|
||||
and GC a little bit aggressively. It is set to 0 by default.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/gc_urgent_sleep_time
|
||||
Date: August 2017
|
||||
|
@@ -0,0 +1,58 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/input/touchscreen/eeti,exc3000.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: EETI EXC3000 series touchscreen controller
|
||||
|
||||
maintainers:
|
||||
- Dmitry Torokhov <dmitry.torokhov@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: touchscreen.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- eeti,exc3000
|
||||
- eeti,exc80h60
|
||||
- eeti,exc80h84
|
||||
reg:
|
||||
const: 0x2a
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
touchscreen-size-x: true
|
||||
touchscreen-size-y: true
|
||||
touchscreen-inverted-x: true
|
||||
touchscreen-inverted-y: true
|
||||
touchscreen-swapped-x-y: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- touchscreen-size-x
|
||||
- touchscreen-size-y
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include "dt-bindings/interrupt-controller/irq.h"
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
touchscreen@2a {
|
||||
compatible = "eeti,exc3000";
|
||||
reg = <0x2a>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <9 IRQ_TYPE_LEVEL_LOW>;
|
||||
touchscreen-size-x = <4096>;
|
||||
touchscreen-size-y = <4096>;
|
||||
touchscreen-inverted-x;
|
||||
touchscreen-swapped-x-y;
|
||||
};
|
||||
};
|
@@ -1,26 +0,0 @@
|
||||
* EETI EXC3000 Multiple Touch Controller
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "eeti,exc3000"
|
||||
- reg: i2c slave address
|
||||
- interrupts: touch controller interrupt
|
||||
- touchscreen-size-x: See touchscreen.txt
|
||||
- touchscreen-size-y: See touchscreen.txt
|
||||
|
||||
Optional properties:
|
||||
- touchscreen-inverted-x: See touchscreen.txt
|
||||
- touchscreen-inverted-y: See touchscreen.txt
|
||||
- touchscreen-swapped-x-y: See touchscreen.txt
|
||||
|
||||
Example:
|
||||
|
||||
touchscreen@2a {
|
||||
compatible = "eeti,exc3000";
|
||||
reg = <0x2a>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <9 IRQ_TYPE_LEVEL_LOW>;
|
||||
touchscreen-size-x = <4096>;
|
||||
touchscreen-size-y = <4096>;
|
||||
touchscreen-inverted-x;
|
||||
touchscreen-swapped-x-y;
|
||||
};
|
@@ -258,6 +258,8 @@ compress_extension=%s Support adding specified extension, so that f2fs can enab
|
||||
on compression extension list and enable compression on
|
||||
these file by default rather than to enable it via ioctl.
|
||||
For other files, we can still enable compression via ioctl.
|
||||
Note that, there is one reserved special extension '*', it
|
||||
can be set to enable compression for all files.
|
||||
inlinecrypt When possible, encrypt/decrypt the contents of encrypted
|
||||
files using the blk-crypto framework rather than
|
||||
filesystem-layer encryption. This allows the use of
|
||||
@@ -743,8 +745,8 @@ Compression implementation
|
||||
|
||||
- In order to eliminate write amplification during overwrite, F2FS only
|
||||
support compression on write-once file, data can be compressed only when
|
||||
all logical blocks in file are valid and cluster compress ratio is lower
|
||||
than specified threshold.
|
||||
all logical blocks in cluster contain valid data and compress ratio of
|
||||
cluster data is lower than specified threshold.
|
||||
|
||||
- To enable compression on regular inode, there are three ways:
|
||||
|
||||
|
@@ -99,7 +99,7 @@ the sake of simplicity.
|
||||
|
||||
/*
|
||||
* Give userspace some time to read the events before we destroy the
|
||||
* device with UI_DEV_DESTOY.
|
||||
* device with UI_DEV_DESTROY.
|
||||
*/
|
||||
sleep(1);
|
||||
|
||||
@@ -164,7 +164,7 @@ mouse.
|
||||
|
||||
/*
|
||||
* Give userspace some time to read the events before we destroy the
|
||||
* device with UI_DEV_DESTOY.
|
||||
* device with UI_DEV_DESTROY.
|
||||
*/
|
||||
sleep(1);
|
||||
|
||||
@@ -233,7 +233,7 @@ but interact with uinput via ioctl calls, or use libevdev.
|
||||
|
||||
/*
|
||||
* Give userspace some time to read the events before we destroy the
|
||||
* device with UI_DEV_DESTOY.
|
||||
* device with UI_DEV_DESTROY.
|
||||
*/
|
||||
sleep(1);
|
||||
|
||||
|
@@ -87,6 +87,58 @@ Read path::
|
||||
} while (read_seqcount_retry(&foo_seqcount, seq));
|
||||
|
||||
|
||||
.. _seqcount_locktype_t:
|
||||
|
||||
Sequence counters with associated locks (``seqcount_LOCKTYPE_t``)
|
||||
-----------------------------------------------------------------
|
||||
|
||||
As discussed at :ref:`seqcount_t`, sequence count write side critical
|
||||
sections must be serialized and non-preemptible. This variant of
|
||||
sequence counters associate the lock used for writer serialization at
|
||||
initialization time, which enables lockdep to validate that the write
|
||||
side critical sections are properly serialized.
|
||||
|
||||
This lock association is a NOOP if lockdep is disabled and has neither
|
||||
storage nor runtime overhead. If lockdep is enabled, the lock pointer is
|
||||
stored in struct seqcount and lockdep's "lock is held" assertions are
|
||||
injected at the beginning of the write side critical section to validate
|
||||
that it is properly protected.
|
||||
|
||||
For lock types which do not implicitly disable preemption, preemption
|
||||
protection is enforced in the write side function.
|
||||
|
||||
The following sequence counters with associated locks are defined:
|
||||
|
||||
- ``seqcount_spinlock_t``
|
||||
- ``seqcount_raw_spinlock_t``
|
||||
- ``seqcount_rwlock_t``
|
||||
- ``seqcount_mutex_t``
|
||||
- ``seqcount_ww_mutex_t``
|
||||
|
||||
The plain seqcount read and write APIs branch out to the specific
|
||||
seqcount_LOCKTYPE_t implementation at compile-time. This avoids kernel
|
||||
API explosion per each new seqcount LOCKTYPE.
|
||||
|
||||
Initialization (replace "LOCKTYPE" with one of the supported locks)::
|
||||
|
||||
/* dynamic */
|
||||
seqcount_LOCKTYPE_t foo_seqcount;
|
||||
seqcount_LOCKTYPE_init(&foo_seqcount, &lock);
|
||||
|
||||
/* static */
|
||||
static seqcount_LOCKTYPE_t foo_seqcount =
|
||||
SEQCNT_LOCKTYPE_ZERO(foo_seqcount, &lock);
|
||||
|
||||
/* C99 struct init */
|
||||
struct {
|
||||
.seq = SEQCNT_LOCKTYPE_ZERO(foo.seq, &lock),
|
||||
} foo;
|
||||
|
||||
Write path: same as in :ref:`seqcount_t`, while running from a context
|
||||
with the associated LOCKTYPE lock acquired.
|
||||
|
||||
Read path: same as in :ref:`seqcount_t`.
|
||||
|
||||
.. _seqlock_t:
|
||||
|
||||
Sequential locks (``seqlock_t``)
|
||||
|
@@ -18,7 +18,6 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/irqreturn.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/param.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/ptrace.h>
|
||||
@@ -44,11 +43,6 @@ ia64_get_lid (void)
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
#define XTP_OFFSET 0x1e0008
|
||||
|
||||
#define SMP_IRQ_REDIRECTION (1 << 0)
|
||||
#define SMP_IPI_REDIRECTION (1 << 1)
|
||||
|
||||
#define raw_smp_processor_id() (current_thread_info()->cpu)
|
||||
|
||||
extern struct smp_boot_data {
|
||||
@@ -62,7 +56,6 @@ extern cpumask_t cpu_core_map[NR_CPUS];
|
||||
DECLARE_PER_CPU_SHARED_ALIGNED(cpumask_t, cpu_sibling_map);
|
||||
extern int smp_num_siblings;
|
||||
extern void __iomem *ipi_base_addr;
|
||||
extern unsigned char smp_int_redirect;
|
||||
|
||||
extern volatile int ia64_cpu_to_sapicid[];
|
||||
#define cpu_physical_id(i) ia64_cpu_to_sapicid[i]
|
||||
@@ -84,34 +77,6 @@ cpu_logical_id (int cpuid)
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* XTP control functions:
|
||||
* min_xtp : route all interrupts to this CPU
|
||||
* normal_xtp: nominal XTP value
|
||||
* max_xtp : never deliver interrupts to this CPU.
|
||||
*/
|
||||
|
||||
static inline void
|
||||
min_xtp (void)
|
||||
{
|
||||
if (smp_int_redirect & SMP_IRQ_REDIRECTION)
|
||||
writeb(0x00, ipi_base_addr + XTP_OFFSET); /* XTP to min */
|
||||
}
|
||||
|
||||
static inline void
|
||||
normal_xtp (void)
|
||||
{
|
||||
if (smp_int_redirect & SMP_IRQ_REDIRECTION)
|
||||
writeb(0x08, ipi_base_addr + XTP_OFFSET); /* XTP normal */
|
||||
}
|
||||
|
||||
static inline void
|
||||
max_xtp (void)
|
||||
{
|
||||
if (smp_int_redirect & SMP_IRQ_REDIRECTION)
|
||||
writeb(0x0f, ipi_base_addr + XTP_OFFSET); /* Set XTP to max */
|
||||
}
|
||||
|
||||
/* Upping and downing of CPUs */
|
||||
extern int __cpu_disable (void);
|
||||
extern void __cpu_die (unsigned int cpu);
|
||||
|
46
arch/ia64/include/asm/xtp.h
Normal file
46
arch/ia64/include/asm/xtp.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_IA64_XTP_H
|
||||
#define _ASM_IA64_XTP_H
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
#define XTP_OFFSET 0x1e0008
|
||||
|
||||
#define SMP_IRQ_REDIRECTION (1 << 0)
|
||||
#define SMP_IPI_REDIRECTION (1 << 1)
|
||||
|
||||
extern unsigned char smp_int_redirect;
|
||||
|
||||
/*
|
||||
* XTP control functions:
|
||||
* min_xtp : route all interrupts to this CPU
|
||||
* normal_xtp: nominal XTP value
|
||||
* max_xtp : never deliver interrupts to this CPU.
|
||||
*/
|
||||
|
||||
static inline void
|
||||
min_xtp (void)
|
||||
{
|
||||
if (smp_int_redirect & SMP_IRQ_REDIRECTION)
|
||||
writeb(0x00, ipi_base_addr + XTP_OFFSET); /* XTP to min */
|
||||
}
|
||||
|
||||
static inline void
|
||||
normal_xtp (void)
|
||||
{
|
||||
if (smp_int_redirect & SMP_IRQ_REDIRECTION)
|
||||
writeb(0x08, ipi_base_addr + XTP_OFFSET); /* XTP normal */
|
||||
}
|
||||
|
||||
static inline void
|
||||
max_xtp (void)
|
||||
{
|
||||
if (smp_int_redirect & SMP_IRQ_REDIRECTION)
|
||||
writeb(0x0f, ipi_base_addr + XTP_OFFSET); /* Set XTP to max */
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
#endif /* _ASM_IA64_XTP_Hy */
|
@@ -95,6 +95,7 @@
|
||||
#include <asm/iosapic.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/xtp.h>
|
||||
|
||||
#undef DEBUG_INTERRUPT_ROUTING
|
||||
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include <linux/kernel_stat.h>
|
||||
|
||||
#include <asm/mca.h>
|
||||
#include <asm/xtp.h>
|
||||
|
||||
/*
|
||||
* 'what should we do if we get a hw irq event on an illegal vector'.
|
||||
|
@@ -47,6 +47,7 @@
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/unwind.h>
|
||||
#include <asm/user.h>
|
||||
#include <asm/xtp.h>
|
||||
|
||||
#include "entry.h"
|
||||
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include <asm/page.h>
|
||||
#include <asm/sal.h>
|
||||
#include <asm/pal.h>
|
||||
#include <asm/xtp.h>
|
||||
|
||||
__cacheline_aligned DEFINE_SPINLOCK(sal_lock);
|
||||
unsigned long sal_platform_features;
|
||||
|
@@ -65,6 +65,7 @@
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/unistd.h>
|
||||
#include <asm/uv/uv.h>
|
||||
#include <asm/xtp.h>
|
||||
|
||||
#if defined(CONFIG_SMP) && (IA64_CPU_SIZE > PAGE_SIZE)
|
||||
# error "struct cpuinfo_ia64 too big!"
|
||||
|
@@ -45,6 +45,7 @@
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/unistd.h>
|
||||
#include <asm/mca.h>
|
||||
#include <asm/xtp.h>
|
||||
|
||||
/*
|
||||
* Note: alignment of 4 entries/cacheline was empirically determined
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#ifndef _ASMPARISC_TIMEX_H
|
||||
#define _ASMPARISC_TIMEX_H
|
||||
|
||||
#include <asm/special_insns.h>
|
||||
|
||||
#define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
|
||||
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include <asm/cache.h>
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/machvec.h>
|
||||
#include <asm/page.h>
|
||||
#include <linux/pgtable.h>
|
||||
#include <asm-generic/iomap.h>
|
||||
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#include <asm/setup.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
#define MV_NAME_SIZE 32
|
||||
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#ifndef _SPARC64_TIMER_H
|
||||
#define _SPARC64_TIMER_H
|
||||
|
||||
#include <uapi/asm/asi.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
|
@@ -6,7 +6,8 @@
|
||||
#define _ASM_SPARC_VVAR_DATA_H
|
||||
|
||||
#include <asm/clocksource.h>
|
||||
#include <linux/seqlock.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/barrier.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
|
@@ -7,7 +7,6 @@
|
||||
* a different vsyscall implementation for Linux/IA32 and for the name.
|
||||
*/
|
||||
|
||||
#include <linux/seqlock.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/timekeeper_internal.h>
|
||||
|
||||
|
@@ -26,9 +26,9 @@
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/acpi.h>
|
||||
#include <asm/apicdef.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable_types.h>
|
||||
#ifdef CONFIG_X86_32
|
||||
#include <linux/threads.h>
|
||||
#include <asm/kmap_types.h>
|
||||
|
@@ -5,16 +5,6 @@
|
||||
#include <linux/cpumask.h>
|
||||
#include <asm/percpu.h>
|
||||
|
||||
/*
|
||||
* We need the APIC definitions automatically as part of 'smp.h'
|
||||
*/
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
# include <asm/mpspec.h>
|
||||
# include <asm/apic.h>
|
||||
# ifdef CONFIG_X86_IO_APIC
|
||||
# include <asm/io_apic.h>
|
||||
# endif
|
||||
#endif
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/cpumask.h>
|
||||
|
||||
|
@@ -6,6 +6,7 @@
|
||||
#define _ASM_X86_TSC_H
|
||||
|
||||
#include <asm/processor.h>
|
||||
#include <asm/cpufeature.h>
|
||||
|
||||
/*
|
||||
* Standard way to access the cycle counter.
|
||||
|
@@ -46,6 +46,7 @@
|
||||
#include <asm/proto.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/acpi.h>
|
||||
#include <asm/io_apic.h>
|
||||
#include <asm/desc.h>
|
||||
#include <asm/hpet.h>
|
||||
|
@@ -10,6 +10,7 @@
|
||||
* like self-ipi, etc...
|
||||
*/
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/thread_info.h>
|
||||
|
||||
#include <asm/apic.h>
|
||||
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include <asm/apic.h>
|
||||
#include <asm/io_apic.h>
|
||||
|
||||
#include "local.h"
|
||||
|
||||
|
@@ -9,6 +9,7 @@
|
||||
* Bits copied from original nmi.c file
|
||||
*
|
||||
*/
|
||||
#include <linux/thread_info.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/nmi.h>
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/smp.h>
|
||||
#include <asm/io_apic.h>
|
||||
|
||||
#include "local.h"
|
||||
|
||||
|
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <linux/jump_label.h>
|
||||
|
||||
#include <asm/irq_vectors.h>
|
||||
#include <asm/apic.h>
|
||||
|
||||
/* APIC flat 64 */
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include <asm/io_apic.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/acpi.h>
|
||||
|
||||
|
@@ -8,6 +8,7 @@
|
||||
* Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
|
||||
* James Cleverdon.
|
||||
*/
|
||||
#include <linux/thread_info.h>
|
||||
#include <asm/apic.h>
|
||||
|
||||
#include "local.h"
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/spec-ctrl.h>
|
||||
#include <asm/smp.h>
|
||||
#include <asm/numa.h>
|
||||
#include <asm/pci-direct.h>
|
||||
#include <asm/delay.h>
|
||||
#include <asm/debugreg.h>
|
||||
|
@@ -45,6 +45,7 @@
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/hwcap2.h>
|
||||
#include <linux/numa.h>
|
||||
#include <asm/numa.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/bugs.h>
|
||||
#include <asm/cpu.h>
|
||||
|
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/smp.h>
|
||||
#include <asm/numa.h>
|
||||
#include <asm/cacheinfo.h>
|
||||
#include <asm/spec-ctrl.h>
|
||||
#include <asm/delay.h>
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include <asm/cmdline.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/resctrl.h>
|
||||
#include <asm/numa.h>
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
#include <linux/topology.h>
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include <asm/irqdomain.h>
|
||||
#include <asm/hpet.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/io_apic.h>
|
||||
#include <asm/pci_x86.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/i8259.h>
|
||||
|
@@ -22,6 +22,8 @@
|
||||
#include <asm/timer.h>
|
||||
#include <asm/hw_irq.h>
|
||||
#include <asm/desc.h>
|
||||
#include <asm/io_apic.h>
|
||||
#include <asm/acpi.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/i8259.h>
|
||||
|
@@ -13,6 +13,8 @@
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/io_apic.h>
|
||||
#include <asm/acpi.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/hypervisor.h>
|
||||
#include <asm/i8259.h>
|
||||
|
@@ -19,6 +19,8 @@
|
||||
#include <linux/smp.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <asm/io_apic.h>
|
||||
#include <asm/acpi.h>
|
||||
#include <asm/irqdomain.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/mpspec.h>
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include <xen/xen.h>
|
||||
|
||||
#include <asm/apic.h>
|
||||
#include <asm/numa.h>
|
||||
#include <asm/bios_ebda.h>
|
||||
#include <asm/bugs.h>
|
||||
#include <asm/cpu.h>
|
||||
|
@@ -31,6 +31,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/irq.h>
|
||||
#include <asm/io_apic.h>
|
||||
#include <asm/cpu.h>
|
||||
|
||||
static DEFINE_PER_CPU(struct x86_cpu, cpu_devices);
|
||||
|
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/thread_info.h>
|
||||
|
||||
#include <asm/apic.h>
|
||||
#include <asm/cpu_device_id.h>
|
||||
|
@@ -52,6 +52,7 @@
|
||||
#include <asm/cpu_entry_area.h>
|
||||
#include <asm/init.h>
|
||||
#include <asm/pgtable_areas.h>
|
||||
#include <asm/numa.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
|
||||
|
@@ -1,8 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/init.h>
|
||||
#include <linux/thread_info.h>
|
||||
|
||||
#include <asm/x86_init.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/io_apic.h>
|
||||
#include <asm/xen/hypercall.h>
|
||||
|
||||
#include <xen/xen.h>
|
||||
|
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/smp.h>
|
||||
#include <asm/io_apic.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/idtentry.h>
|
||||
|
@@ -1,4 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/thread_info.h>
|
||||
#include <asm/smp.h>
|
||||
|
||||
#include <xen/events.h>
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include <asm/idtentry.h>
|
||||
#include <asm/desc.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/io_apic.h>
|
||||
|
||||
#include <xen/interface/xen.h>
|
||||
#include <xen/interface/vcpu.h>
|
||||
|
@@ -1,11 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/fixmap.h>
|
||||
|
||||
#include <asm/xen/hypercall.h>
|
||||
#include <asm/xen/page.h>
|
||||
|
||||
#include <asm/fixmap.h>
|
||||
|
||||
#include "xen-ops.h"
|
||||
|
||||
void xen_pv_pre_suspend(void)
|
||||
|
@@ -406,7 +406,7 @@ struct ioc {
|
||||
enum ioc_running running;
|
||||
atomic64_t vtime_rate;
|
||||
|
||||
seqcount_t period_seqcount;
|
||||
seqcount_spinlock_t period_seqcount;
|
||||
u32 period_at; /* wallclock starttime */
|
||||
u64 period_at_vtime; /* vtime starttime */
|
||||
|
||||
@@ -873,7 +873,6 @@ static void ioc_now(struct ioc *ioc, struct ioc_now *now)
|
||||
|
||||
static void ioc_start_period(struct ioc *ioc, struct ioc_now *now)
|
||||
{
|
||||
lockdep_assert_held(&ioc->lock);
|
||||
WARN_ON_ONCE(ioc->running != IOC_RUNNING);
|
||||
|
||||
write_seqcount_begin(&ioc->period_seqcount);
|
||||
@@ -2001,7 +2000,7 @@ static int blk_iocost_init(struct request_queue *q)
|
||||
|
||||
ioc->running = IOC_IDLE;
|
||||
atomic64_set(&ioc->vtime_rate, VTIME_PER_USEC);
|
||||
seqcount_init(&ioc->period_seqcount);
|
||||
seqcount_spinlock_init(&ioc->period_seqcount, &ioc->lock);
|
||||
ioc->period_at = ktime_to_us(ktime_get());
|
||||
atomic64_set(&ioc->cur_period, 0);
|
||||
atomic_set(&ioc->hweight_gen, 0);
|
||||
|
@@ -52,12 +52,6 @@
|
||||
DEFINE_WD_CLASS(reservation_ww_class);
|
||||
EXPORT_SYMBOL(reservation_ww_class);
|
||||
|
||||
struct lock_class_key reservation_seqcount_class;
|
||||
EXPORT_SYMBOL(reservation_seqcount_class);
|
||||
|
||||
const char reservation_seqcount_string[] = "reservation_seqcount";
|
||||
EXPORT_SYMBOL(reservation_seqcount_string);
|
||||
|
||||
/**
|
||||
* dma_resv_list_alloc - allocate fence list
|
||||
* @shared_max: number of fences we need space for
|
||||
@@ -143,9 +137,8 @@ subsys_initcall(dma_resv_lockdep);
|
||||
void dma_resv_init(struct dma_resv *obj)
|
||||
{
|
||||
ww_mutex_init(&obj->lock, &reservation_ww_class);
|
||||
seqcount_ww_mutex_init(&obj->seq, &obj->lock);
|
||||
|
||||
__seqcount_init(&obj->seq, reservation_seqcount_string,
|
||||
&reservation_seqcount_class);
|
||||
RCU_INIT_POINTER(obj->fence, NULL);
|
||||
RCU_INIT_POINTER(obj->fence_excl, NULL);
|
||||
}
|
||||
@@ -275,7 +268,6 @@ void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence)
|
||||
fobj = dma_resv_get_list(obj);
|
||||
count = fobj->shared_count;
|
||||
|
||||
preempt_disable();
|
||||
write_seqcount_begin(&obj->seq);
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
@@ -297,7 +289,6 @@ replace:
|
||||
smp_store_mb(fobj->shared_count, count);
|
||||
|
||||
write_seqcount_end(&obj->seq);
|
||||
preempt_enable();
|
||||
dma_fence_put(old);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_resv_add_shared_fence);
|
||||
@@ -324,14 +315,12 @@ void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence)
|
||||
if (fence)
|
||||
dma_fence_get(fence);
|
||||
|
||||
preempt_disable();
|
||||
write_seqcount_begin(&obj->seq);
|
||||
/* write_seqcount_begin provides the necessary memory barrier */
|
||||
RCU_INIT_POINTER(obj->fence_excl, fence);
|
||||
if (old)
|
||||
old->shared_count = 0;
|
||||
write_seqcount_end(&obj->seq);
|
||||
preempt_enable();
|
||||
|
||||
/* inplace update, no shared fences */
|
||||
while (i--)
|
||||
@@ -409,13 +398,11 @@ retry:
|
||||
src_list = dma_resv_get_list(dst);
|
||||
old = dma_resv_get_excl(dst);
|
||||
|
||||
preempt_disable();
|
||||
write_seqcount_begin(&dst->seq);
|
||||
/* write_seqcount_begin provides the necessary memory barrier */
|
||||
RCU_INIT_POINTER(dst->fence_excl, new);
|
||||
RCU_INIT_POINTER(dst->fence, dst_list);
|
||||
write_seqcount_end(&dst->seq);
|
||||
preempt_enable();
|
||||
|
||||
dma_resv_list_free(src_list);
|
||||
dma_fence_put(old);
|
||||
|
@@ -258,11 +258,9 @@ static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo,
|
||||
new->shared_count = k;
|
||||
|
||||
/* Install the new fence list, seqcount provides the barriers */
|
||||
preempt_disable();
|
||||
write_seqcount_begin(&resv->seq);
|
||||
RCU_INIT_POINTER(resv->fence, new);
|
||||
write_seqcount_end(&resv->seq);
|
||||
preempt_enable();
|
||||
|
||||
/* Drop the references to the removed fences or move them to ef_list */
|
||||
for (i = j, k = 0; i < old->shared_count; ++i) {
|
||||
|
@@ -20,7 +20,7 @@ config HID
|
||||
removed from the HID bus by the transport-layer drivers, such as
|
||||
usbhid (USB_HID) and hidp (BT_HIDP).
|
||||
|
||||
For docs and specs, see http://www.usb.org/developers/hidpage/
|
||||
For docs and specs, see https://www.usb.org/developers/hidpage/
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
|
@@ -11,7 +11,7 @@
|
||||
* host communicates with the CP2112 via raw HID reports.
|
||||
*
|
||||
* Data Sheet:
|
||||
* http://www.silabs.com/Support%20Documents/TechnicalDocs/CP2112.pdf
|
||||
* https://www.silabs.com/Support%20Documents/TechnicalDocs/CP2112.pdf
|
||||
* Programming Interface Specification:
|
||||
* https://www.silabs.com/documents/public/application-notes/an495-cp2112-interface-specification.pdf
|
||||
*/
|
||||
|
@@ -724,6 +724,7 @@
|
||||
#define USB_DEVICE_ID_LENOVO_CUSBKBD 0x6047
|
||||
#define USB_DEVICE_ID_LENOVO_CBTKBD 0x6048
|
||||
#define USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL 0x6049
|
||||
#define USB_DEVICE_ID_LENOVO_TP10UBKBD 0x6062
|
||||
#define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067
|
||||
#define USB_DEVICE_ID_LENOVO_X1_COVER 0x6085
|
||||
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D 0x608d
|
||||
@@ -773,6 +774,7 @@
|
||||
#define USB_DEVICE_ID_LOGITECH_G27_WHEEL 0xc29b
|
||||
#define USB_DEVICE_ID_LOGITECH_WII_WHEEL 0xc29c
|
||||
#define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a
|
||||
#define USB_DEVICE_ID_LOGITECH_GROUP_AUDIO 0x0882
|
||||
#define USB_DEVICE_ID_S510_RECEIVER 0xc50c
|
||||
#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517
|
||||
#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512
|
||||
|
@@ -350,13 +350,13 @@ static int hidinput_query_battery_capacity(struct hid_device *dev)
|
||||
u8 *buf;
|
||||
int ret;
|
||||
|
||||
buf = kmalloc(2, GFP_KERNEL);
|
||||
buf = kmalloc(4, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 2,
|
||||
ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 4,
|
||||
dev->battery_report_type, HID_REQ_GET_REPORT);
|
||||
if (ret != 2) {
|
||||
if (ret < 2) {
|
||||
kfree(buf);
|
||||
return -ENODATA;
|
||||
}
|
||||
@@ -1560,21 +1560,12 @@ static bool __hidinput_change_resolution_multipliers(struct hid_device *hid,
|
||||
{
|
||||
struct hid_usage *usage;
|
||||
bool update_needed = false;
|
||||
bool get_report_completed = false;
|
||||
int i, j;
|
||||
|
||||
if (report->maxfield == 0)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* If we have more than one feature within this report we
|
||||
* need to fill in the bits from the others before we can
|
||||
* overwrite the ones for the Resolution Multiplier.
|
||||
*/
|
||||
if (report->maxfield > 1) {
|
||||
hid_hw_request(hid, report, HID_REQ_GET_REPORT);
|
||||
hid_hw_wait(hid);
|
||||
}
|
||||
|
||||
for (i = 0; i < report->maxfield; i++) {
|
||||
__s32 value = use_logical_max ?
|
||||
report->field[i]->logical_maximum :
|
||||
@@ -1593,6 +1584,25 @@ static bool __hidinput_change_resolution_multipliers(struct hid_device *hid,
|
||||
if (usage->hid != HID_GD_RESOLUTION_MULTIPLIER)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If we have more than one feature within this
|
||||
* report we need to fill in the bits from the
|
||||
* others before we can overwrite the ones for the
|
||||
* Resolution Multiplier.
|
||||
*
|
||||
* But if we're not allowed to read from the device,
|
||||
* we just bail. Such a device should not exist
|
||||
* anyway.
|
||||
*/
|
||||
if (!get_report_completed && report->maxfield > 1) {
|
||||
if (hid->quirks & HID_QUIRK_NO_INIT_REPORTS)
|
||||
return update_needed;
|
||||
|
||||
hid_hw_request(hid, report, HID_REQ_GET_REPORT);
|
||||
hid_hw_wait(hid);
|
||||
get_report_completed = true;
|
||||
}
|
||||
|
||||
report->field[i]->value[j] = value;
|
||||
update_needed = true;
|
||||
}
|
||||
|
@@ -29,29 +29,67 @@
|
||||
#include <linux/hid.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
struct lenovo_drvdata_tpkbd {
|
||||
struct lenovo_drvdata {
|
||||
u8 led_report[3]; /* Must be first for proper alignment */
|
||||
int led_state;
|
||||
struct mutex led_report_mutex;
|
||||
struct led_classdev led_mute;
|
||||
struct led_classdev led_micmute;
|
||||
struct work_struct fn_lock_sync_work;
|
||||
struct hid_device *hdev;
|
||||
int press_to_select;
|
||||
int dragging;
|
||||
int release_to_select;
|
||||
int select_right;
|
||||
int sensitivity;
|
||||
int press_speed;
|
||||
};
|
||||
|
||||
struct lenovo_drvdata_cptkbd {
|
||||
u8 middlebutton_state; /* 0:Up, 1:Down (undecided), 2:Scrolling */
|
||||
bool fn_lock;
|
||||
int sensitivity;
|
||||
};
|
||||
|
||||
#define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
|
||||
|
||||
#define TP10UBKBD_LED_OUTPUT_REPORT 9
|
||||
|
||||
#define TP10UBKBD_FN_LOCK_LED 0x54
|
||||
#define TP10UBKBD_MUTE_LED 0x64
|
||||
#define TP10UBKBD_MICMUTE_LED 0x74
|
||||
|
||||
#define TP10UBKBD_LED_OFF 1
|
||||
#define TP10UBKBD_LED_ON 2
|
||||
|
||||
static void lenovo_led_set_tp10ubkbd(struct hid_device *hdev, u8 led_code,
|
||||
enum led_brightness value)
|
||||
{
|
||||
struct lenovo_drvdata *data = hid_get_drvdata(hdev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->led_report_mutex);
|
||||
|
||||
data->led_report[0] = TP10UBKBD_LED_OUTPUT_REPORT;
|
||||
data->led_report[1] = led_code;
|
||||
data->led_report[2] = value ? TP10UBKBD_LED_ON : TP10UBKBD_LED_OFF;
|
||||
ret = hid_hw_raw_request(hdev, data->led_report[0], data->led_report, 3,
|
||||
HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
|
||||
if (ret)
|
||||
hid_err(hdev, "Set LED output report error: %d\n", ret);
|
||||
|
||||
mutex_unlock(&data->led_report_mutex);
|
||||
}
|
||||
|
||||
static void lenovo_tp10ubkbd_sync_fn_lock(struct work_struct *work)
|
||||
{
|
||||
struct lenovo_drvdata *data =
|
||||
container_of(work, struct lenovo_drvdata, fn_lock_sync_work);
|
||||
|
||||
lenovo_led_set_tp10ubkbd(data->hdev, TP10UBKBD_FN_LOCK_LED,
|
||||
data->fn_lock);
|
||||
}
|
||||
|
||||
static const __u8 lenovo_pro_dock_need_fixup_collection[] = {
|
||||
0x05, 0x88, /* Usage Page (Vendor Usage Page 0x88) */
|
||||
0x09, 0x01, /* Usage (Vendor Usage 0x01) */
|
||||
@@ -179,6 +217,44 @@ static int lenovo_input_mapping_scrollpoint(struct hid_device *hdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lenovo_input_mapping_tp10_ultrabook_kbd(struct hid_device *hdev,
|
||||
struct hid_input *hi, struct hid_field *field,
|
||||
struct hid_usage *usage, unsigned long **bit, int *max)
|
||||
{
|
||||
/*
|
||||
* The ThinkPad 10 Ultrabook Keyboard uses 0x000c0001 usage for
|
||||
* a bunch of keys which have no standard consumer page code.
|
||||
*/
|
||||
if (usage->hid == 0x000c0001) {
|
||||
switch (usage->usage_index) {
|
||||
case 8: /* Fn-Esc: Fn-lock toggle */
|
||||
map_key_clear(KEY_FN_ESC);
|
||||
return 1;
|
||||
case 9: /* Fn-F4: Mic mute */
|
||||
map_key_clear(KEY_MICMUTE);
|
||||
return 1;
|
||||
case 10: /* Fn-F7: Control panel */
|
||||
map_key_clear(KEY_CONFIG);
|
||||
return 1;
|
||||
case 11: /* Fn-F8: Search (magnifier glass) */
|
||||
map_key_clear(KEY_SEARCH);
|
||||
return 1;
|
||||
case 12: /* Fn-F10: Open My computer (6 boxes) */
|
||||
map_key_clear(KEY_FILE);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The Ultrabook Keyboard sends a spurious F23 key-press when resuming
|
||||
* from suspend and it does not actually have a F23 key, ignore it.
|
||||
*/
|
||||
if (usage->hid == 0x00070072)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lenovo_input_mapping(struct hid_device *hdev,
|
||||
struct hid_input *hi, struct hid_field *field,
|
||||
struct hid_usage *usage, unsigned long **bit, int *max)
|
||||
@@ -199,6 +275,9 @@ static int lenovo_input_mapping(struct hid_device *hdev,
|
||||
case USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL:
|
||||
return lenovo_input_mapping_scrollpoint(hdev, hi, field,
|
||||
usage, bit, max);
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
return lenovo_input_mapping_tp10_ultrabook_kbd(hdev, hi, field,
|
||||
usage, bit, max);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -242,7 +321,7 @@ static int lenovo_send_cmd_cptkbd(struct hid_device *hdev,
|
||||
static void lenovo_features_set_cptkbd(struct hid_device *hdev)
|
||||
{
|
||||
int ret;
|
||||
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
|
||||
|
||||
ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock);
|
||||
if (ret)
|
||||
@@ -253,23 +332,23 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev)
|
||||
hid_err(hdev, "Sensitivity setting failed: %d\n", ret);
|
||||
}
|
||||
|
||||
static ssize_t attr_fn_lock_show_cptkbd(struct device *dev,
|
||||
static ssize_t attr_fn_lock_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *data = hid_get_drvdata(hdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", cptkbd_data->fn_lock);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", data->fn_lock);
|
||||
}
|
||||
|
||||
static ssize_t attr_fn_lock_store_cptkbd(struct device *dev,
|
||||
static ssize_t attr_fn_lock_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *data = hid_get_drvdata(hdev);
|
||||
int value;
|
||||
|
||||
if (kstrtoint(buf, 10, &value))
|
||||
@@ -277,8 +356,17 @@ static ssize_t attr_fn_lock_store_cptkbd(struct device *dev,
|
||||
if (value < 0 || value > 1)
|
||||
return -EINVAL;
|
||||
|
||||
cptkbd_data->fn_lock = !!value;
|
||||
lenovo_features_set_cptkbd(hdev);
|
||||
data->fn_lock = !!value;
|
||||
|
||||
switch (hdev->product) {
|
||||
case USB_DEVICE_ID_LENOVO_CUSBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
||||
lenovo_features_set_cptkbd(hdev);
|
||||
break;
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
lenovo_led_set_tp10ubkbd(hdev, TP10UBKBD_FN_LOCK_LED, value);
|
||||
break;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
@@ -288,7 +376,7 @@ static ssize_t attr_sensitivity_show_cptkbd(struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n",
|
||||
cptkbd_data->sensitivity);
|
||||
@@ -300,7 +388,7 @@ static ssize_t attr_sensitivity_store_cptkbd(struct device *dev,
|
||||
size_t count)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
|
||||
int value;
|
||||
|
||||
if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
|
||||
@@ -313,10 +401,10 @@ static ssize_t attr_sensitivity_store_cptkbd(struct device *dev,
|
||||
}
|
||||
|
||||
|
||||
static struct device_attribute dev_attr_fn_lock_cptkbd =
|
||||
static struct device_attribute dev_attr_fn_lock =
|
||||
__ATTR(fn_lock, S_IWUSR | S_IRUGO,
|
||||
attr_fn_lock_show_cptkbd,
|
||||
attr_fn_lock_store_cptkbd);
|
||||
attr_fn_lock_show,
|
||||
attr_fn_lock_store);
|
||||
|
||||
static struct device_attribute dev_attr_sensitivity_cptkbd =
|
||||
__ATTR(sensitivity, S_IWUSR | S_IRUGO,
|
||||
@@ -325,7 +413,7 @@ static struct device_attribute dev_attr_sensitivity_cptkbd =
|
||||
|
||||
|
||||
static struct attribute *lenovo_attributes_cptkbd[] = {
|
||||
&dev_attr_fn_lock_cptkbd.attr,
|
||||
&dev_attr_fn_lock.attr,
|
||||
&dev_attr_sensitivity_cptkbd.attr,
|
||||
NULL
|
||||
};
|
||||
@@ -354,10 +442,28 @@ static int lenovo_raw_event(struct hid_device *hdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lenovo_event_tp10ubkbd(struct hid_device *hdev,
|
||||
struct hid_field *field, struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
struct lenovo_drvdata *data = hid_get_drvdata(hdev);
|
||||
|
||||
if (usage->type == EV_KEY && usage->code == KEY_FN_ESC && value == 1) {
|
||||
/*
|
||||
* The user has toggled the Fn-lock state. Toggle our own
|
||||
* cached value of it and sync our value to the keyboard to
|
||||
* ensure things are in sync (the sycning should be a no-op).
|
||||
*/
|
||||
data->fn_lock = !data->fn_lock;
|
||||
schedule_work(&data->fn_lock_sync_work);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lenovo_event_cptkbd(struct hid_device *hdev,
|
||||
struct hid_field *field, struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
|
||||
|
||||
/* "wheel" scroll events */
|
||||
if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
|
||||
@@ -396,6 +502,8 @@ static int lenovo_event(struct hid_device *hdev, struct hid_field *field,
|
||||
case USB_DEVICE_ID_LENOVO_CUSBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
||||
return lenovo_event_cptkbd(hdev, field, usage, value);
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
return lenovo_event_tp10ubkbd(hdev, field, usage, value);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -404,7 +512,7 @@ static int lenovo_event(struct hid_device *hdev, struct hid_field *field,
|
||||
static int lenovo_features_set_tpkbd(struct hid_device *hdev)
|
||||
{
|
||||
struct hid_report *report;
|
||||
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
|
||||
report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4];
|
||||
|
||||
@@ -425,7 +533,7 @@ static ssize_t attr_press_to_select_show_tpkbd(struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->press_to_select);
|
||||
}
|
||||
@@ -436,7 +544,7 @@ static ssize_t attr_press_to_select_store_tpkbd(struct device *dev,
|
||||
size_t count)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
int value;
|
||||
|
||||
if (kstrtoint(buf, 10, &value))
|
||||
@@ -455,7 +563,7 @@ static ssize_t attr_dragging_show_tpkbd(struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->dragging);
|
||||
}
|
||||
@@ -466,7 +574,7 @@ static ssize_t attr_dragging_store_tpkbd(struct device *dev,
|
||||
size_t count)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
int value;
|
||||
|
||||
if (kstrtoint(buf, 10, &value))
|
||||
@@ -485,7 +593,7 @@ static ssize_t attr_release_to_select_show_tpkbd(struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->release_to_select);
|
||||
}
|
||||
@@ -496,7 +604,7 @@ static ssize_t attr_release_to_select_store_tpkbd(struct device *dev,
|
||||
size_t count)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
int value;
|
||||
|
||||
if (kstrtoint(buf, 10, &value))
|
||||
@@ -515,7 +623,7 @@ static ssize_t attr_select_right_show_tpkbd(struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->select_right);
|
||||
}
|
||||
@@ -526,7 +634,7 @@ static ssize_t attr_select_right_store_tpkbd(struct device *dev,
|
||||
size_t count)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
int value;
|
||||
|
||||
if (kstrtoint(buf, 10, &value))
|
||||
@@ -545,7 +653,7 @@ static ssize_t attr_sensitivity_show_tpkbd(struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n",
|
||||
data_pointer->sensitivity);
|
||||
@@ -557,7 +665,7 @@ static ssize_t attr_sensitivity_store_tpkbd(struct device *dev,
|
||||
size_t count)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
int value;
|
||||
|
||||
if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
|
||||
@@ -574,7 +682,7 @@ static ssize_t attr_press_speed_show_tpkbd(struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n",
|
||||
data_pointer->press_speed);
|
||||
@@ -586,7 +694,7 @@ static ssize_t attr_press_speed_store_tpkbd(struct device *dev,
|
||||
size_t count)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
int value;
|
||||
|
||||
if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
|
||||
@@ -642,12 +750,23 @@ static const struct attribute_group lenovo_attr_group_tpkbd = {
|
||||
.attrs = lenovo_attributes_tpkbd,
|
||||
};
|
||||
|
||||
static enum led_brightness lenovo_led_brightness_get_tpkbd(
|
||||
static void lenovo_led_set_tpkbd(struct hid_device *hdev)
|
||||
{
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
struct hid_report *report;
|
||||
|
||||
report = hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[3];
|
||||
report->field[0]->value[0] = (data_pointer->led_state >> 0) & 1;
|
||||
report->field[0]->value[1] = (data_pointer->led_state >> 1) & 1;
|
||||
hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
|
||||
}
|
||||
|
||||
static enum led_brightness lenovo_led_brightness_get(
|
||||
struct led_classdev *led_cdev)
|
||||
{
|
||||
struct device *dev = led_cdev->dev->parent;
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
int led_nr = 0;
|
||||
|
||||
if (led_cdev == &data_pointer->led_micmute)
|
||||
@@ -658,13 +777,13 @@ static enum led_brightness lenovo_led_brightness_get_tpkbd(
|
||||
: LED_OFF;
|
||||
}
|
||||
|
||||
static void lenovo_led_brightness_set_tpkbd(struct led_classdev *led_cdev,
|
||||
static void lenovo_led_brightness_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
{
|
||||
struct device *dev = led_cdev->dev->parent;
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
|
||||
struct hid_report *report;
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
u8 tp10ubkbd_led[] = { TP10UBKBD_MUTE_LED, TP10UBKBD_MICMUTE_LED };
|
||||
int led_nr = 0;
|
||||
|
||||
if (led_cdev == &data_pointer->led_micmute)
|
||||
@@ -675,20 +794,57 @@ static void lenovo_led_brightness_set_tpkbd(struct led_classdev *led_cdev,
|
||||
else
|
||||
data_pointer->led_state |= 1 << led_nr;
|
||||
|
||||
report = hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[3];
|
||||
report->field[0]->value[0] = (data_pointer->led_state >> 0) & 1;
|
||||
report->field[0]->value[1] = (data_pointer->led_state >> 1) & 1;
|
||||
hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
|
||||
switch (hdev->product) {
|
||||
case USB_DEVICE_ID_LENOVO_TPKBD:
|
||||
lenovo_led_set_tpkbd(hdev);
|
||||
break;
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
lenovo_led_set_tp10ubkbd(hdev, tp10ubkbd_led[led_nr], value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int lenovo_register_leds(struct hid_device *hdev)
|
||||
{
|
||||
struct lenovo_drvdata *data = hid_get_drvdata(hdev);
|
||||
size_t name_sz = strlen(dev_name(&hdev->dev)) + 16;
|
||||
char *name_mute, *name_micm;
|
||||
int ret;
|
||||
|
||||
name_mute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL);
|
||||
name_micm = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL);
|
||||
if (name_mute == NULL || name_micm == NULL) {
|
||||
hid_err(hdev, "Could not allocate memory for led data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
snprintf(name_mute, name_sz, "%s:amber:mute", dev_name(&hdev->dev));
|
||||
snprintf(name_micm, name_sz, "%s:amber:micmute", dev_name(&hdev->dev));
|
||||
|
||||
data->led_mute.name = name_mute;
|
||||
data->led_mute.brightness_get = lenovo_led_brightness_get;
|
||||
data->led_mute.brightness_set = lenovo_led_brightness_set;
|
||||
data->led_mute.dev = &hdev->dev;
|
||||
ret = led_classdev_register(&hdev->dev, &data->led_mute);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->led_micmute.name = name_micm;
|
||||
data->led_micmute.brightness_get = lenovo_led_brightness_get;
|
||||
data->led_micmute.brightness_set = lenovo_led_brightness_set;
|
||||
data->led_micmute.dev = &hdev->dev;
|
||||
ret = led_classdev_register(&hdev->dev, &data->led_micmute);
|
||||
if (ret < 0) {
|
||||
led_classdev_unregister(&data->led_mute);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lenovo_probe_tpkbd(struct hid_device *hdev)
|
||||
{
|
||||
struct device *dev = &hdev->dev;
|
||||
struct lenovo_drvdata_tpkbd *data_pointer;
|
||||
size_t name_sz = strlen(dev_name(dev)) + 16;
|
||||
char *name_mute, *name_micmute;
|
||||
int i;
|
||||
int ret;
|
||||
struct lenovo_drvdata *data_pointer;
|
||||
int i, ret;
|
||||
|
||||
/*
|
||||
* Only register extra settings against subdevice where input_mapping
|
||||
@@ -712,7 +868,7 @@ static int lenovo_probe_tpkbd(struct hid_device *hdev)
|
||||
hid_warn(hdev, "Could not create sysfs group: %d\n", ret);
|
||||
|
||||
data_pointer = devm_kzalloc(&hdev->dev,
|
||||
sizeof(struct lenovo_drvdata_tpkbd),
|
||||
sizeof(struct lenovo_drvdata),
|
||||
GFP_KERNEL);
|
||||
if (data_pointer == NULL) {
|
||||
hid_err(hdev, "Could not allocate memory for driver data\n");
|
||||
@@ -724,38 +880,12 @@ static int lenovo_probe_tpkbd(struct hid_device *hdev)
|
||||
data_pointer->sensitivity = 0xa0;
|
||||
data_pointer->press_speed = 0x38;
|
||||
|
||||
name_mute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL);
|
||||
name_micmute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL);
|
||||
if (name_mute == NULL || name_micmute == NULL) {
|
||||
hid_err(hdev, "Could not allocate memory for led data\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
snprintf(name_mute, name_sz, "%s:amber:mute", dev_name(dev));
|
||||
snprintf(name_micmute, name_sz, "%s:amber:micmute", dev_name(dev));
|
||||
|
||||
hid_set_drvdata(hdev, data_pointer);
|
||||
|
||||
data_pointer->led_mute.name = name_mute;
|
||||
data_pointer->led_mute.brightness_get = lenovo_led_brightness_get_tpkbd;
|
||||
data_pointer->led_mute.brightness_set = lenovo_led_brightness_set_tpkbd;
|
||||
data_pointer->led_mute.dev = dev;
|
||||
ret = led_classdev_register(dev, &data_pointer->led_mute);
|
||||
if (ret < 0)
|
||||
ret = lenovo_register_leds(hdev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
data_pointer->led_micmute.name = name_micmute;
|
||||
data_pointer->led_micmute.brightness_get =
|
||||
lenovo_led_brightness_get_tpkbd;
|
||||
data_pointer->led_micmute.brightness_set =
|
||||
lenovo_led_brightness_set_tpkbd;
|
||||
data_pointer->led_micmute.dev = dev;
|
||||
ret = led_classdev_register(dev, &data_pointer->led_micmute);
|
||||
if (ret < 0) {
|
||||
led_classdev_unregister(&data_pointer->led_mute);
|
||||
goto err;
|
||||
}
|
||||
|
||||
lenovo_features_set_tpkbd(hdev);
|
||||
|
||||
return 0;
|
||||
@@ -767,7 +897,7 @@ err:
|
||||
static int lenovo_probe_cptkbd(struct hid_device *hdev)
|
||||
{
|
||||
int ret;
|
||||
struct lenovo_drvdata_cptkbd *cptkbd_data;
|
||||
struct lenovo_drvdata *cptkbd_data;
|
||||
|
||||
/* All the custom action happens on the USBMOUSE device for USB */
|
||||
if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD
|
||||
@@ -811,6 +941,57 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct attribute *lenovo_attributes_tp10ubkbd[] = {
|
||||
&dev_attr_fn_lock.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lenovo_attr_group_tp10ubkbd = {
|
||||
.attrs = lenovo_attributes_tp10ubkbd,
|
||||
};
|
||||
|
||||
static int lenovo_probe_tp10ubkbd(struct hid_device *hdev)
|
||||
{
|
||||
struct lenovo_drvdata *data;
|
||||
int ret;
|
||||
|
||||
/* All the custom action happens on the USBMOUSE device for USB */
|
||||
if (hdev->type != HID_TYPE_USBMOUSE)
|
||||
return 0;
|
||||
|
||||
data = devm_kzalloc(&hdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&data->led_report_mutex);
|
||||
INIT_WORK(&data->fn_lock_sync_work, lenovo_tp10ubkbd_sync_fn_lock);
|
||||
data->hdev = hdev;
|
||||
|
||||
hid_set_drvdata(hdev, data);
|
||||
|
||||
/*
|
||||
* The Thinkpad 10 ultrabook USB kbd dock's Fn-lock defaults to on.
|
||||
* We cannot read the state, only set it, so we force it to on here
|
||||
* (which should be a no-op) to make sure that our state matches the
|
||||
* keyboard's FN-lock state. This is the same as what Windows does.
|
||||
*/
|
||||
data->fn_lock = true;
|
||||
lenovo_led_set_tp10ubkbd(hdev, TP10UBKBD_FN_LOCK_LED, data->fn_lock);
|
||||
|
||||
ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_tp10ubkbd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = lenovo_register_leds(hdev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
sysfs_remove_group(&hdev->dev.kobj, &lenovo_attr_group_tp10ubkbd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lenovo_probe(struct hid_device *hdev,
|
||||
const struct hid_device_id *id)
|
||||
{
|
||||
@@ -836,6 +1017,9 @@ static int lenovo_probe(struct hid_device *hdev,
|
||||
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
||||
ret = lenovo_probe_cptkbd(hdev);
|
||||
break;
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
ret = lenovo_probe_tp10ubkbd(hdev);
|
||||
break;
|
||||
default:
|
||||
ret = 0;
|
||||
break;
|
||||
@@ -852,7 +1036,7 @@ err:
|
||||
|
||||
static void lenovo_remove_tpkbd(struct hid_device *hdev)
|
||||
{
|
||||
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
|
||||
/*
|
||||
* Only the trackpoint half of the keyboard has drvdata and stuff that
|
||||
@@ -874,6 +1058,20 @@ static void lenovo_remove_cptkbd(struct hid_device *hdev)
|
||||
&lenovo_attr_group_cptkbd);
|
||||
}
|
||||
|
||||
static void lenovo_remove_tp10ubkbd(struct hid_device *hdev)
|
||||
{
|
||||
struct lenovo_drvdata *data = hid_get_drvdata(hdev);
|
||||
|
||||
if (data == NULL)
|
||||
return;
|
||||
|
||||
led_classdev_unregister(&data->led_micmute);
|
||||
led_classdev_unregister(&data->led_mute);
|
||||
|
||||
sysfs_remove_group(&hdev->dev.kobj, &lenovo_attr_group_tp10ubkbd);
|
||||
cancel_work_sync(&data->fn_lock_sync_work);
|
||||
}
|
||||
|
||||
static void lenovo_remove(struct hid_device *hdev)
|
||||
{
|
||||
switch (hdev->product) {
|
||||
@@ -884,6 +1082,9 @@ static void lenovo_remove(struct hid_device *hdev)
|
||||
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
||||
lenovo_remove_cptkbd(hdev);
|
||||
break;
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
lenovo_remove_tp10ubkbd(hdev);
|
||||
break;
|
||||
}
|
||||
|
||||
hid_hw_stop(hdev);
|
||||
@@ -920,6 +1121,7 @@ static const struct hid_device_id lenovo_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL_PRO) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TP10UBKBD) },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* Copyright (c) 2020, Rishi Gupta <gupt21@gmail.com>
|
||||
*
|
||||
* Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/20005565B.pdf
|
||||
* Datasheet: https://ww1.microchip.com/downloads/en/DeviceDoc/20005565B.pdf
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@@ -179,6 +179,7 @@ static const struct hid_device_id hid_quirks[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE), HID_QUIRK_MULTI_INPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_GROUP_AUDIO), HID_QUIRK_NOGET },
|
||||
|
||||
{ 0 }
|
||||
};
|
||||
|
@@ -16,7 +16,7 @@ MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* Protocol information from:
|
||||
* http://brandonw.net/udraw/
|
||||
* https://brandonw.net/udraw/
|
||||
* and the source code of:
|
||||
* https://vvvv.org/contribution/udraw-hid
|
||||
*/
|
||||
|
@@ -1870,6 +1870,11 @@ static const struct hid_device_id wiimote_hid_devices[] = {
|
||||
USB_DEVICE_ID_NINTENDO_WIIMOTE2) },
|
||||
{ }
|
||||
};
|
||||
|
||||
bool wiimote_dpad_as_analog = false;
|
||||
module_param_named(dpad_as_analog, wiimote_dpad_as_analog, bool, 0644);
|
||||
MODULE_PARM_DESC(dpad_as_analog, "Use D-Pad as main analog input");
|
||||
|
||||
MODULE_DEVICE_TABLE(hid, wiimote_hid_devices);
|
||||
|
||||
static struct hid_driver wiimote_hid_driver = {
|
||||
|
@@ -1088,12 +1088,28 @@ static void wiimod_classic_in_ext(struct wiimote_data *wdata, const __u8 *ext)
|
||||
* is the same as before.
|
||||
*/
|
||||
|
||||
static const s8 digital_to_analog[3] = {0x20, 0, -0x20};
|
||||
|
||||
if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) {
|
||||
lx = ext[0] & 0x3e;
|
||||
ly = ext[1] & 0x3e;
|
||||
if (wiimote_dpad_as_analog) {
|
||||
lx = digital_to_analog[1 - !(ext[4] & 0x80)
|
||||
+ !(ext[1] & 0x01)];
|
||||
ly = digital_to_analog[1 - !(ext[4] & 0x40)
|
||||
+ !(ext[0] & 0x01)];
|
||||
} else {
|
||||
lx = (ext[0] & 0x3e) - 0x20;
|
||||
ly = (ext[1] & 0x3e) - 0x20;
|
||||
}
|
||||
} else {
|
||||
lx = ext[0] & 0x3f;
|
||||
ly = ext[1] & 0x3f;
|
||||
if (wiimote_dpad_as_analog) {
|
||||
lx = digital_to_analog[1 - !(ext[4] & 0x80)
|
||||
+ !(ext[5] & 0x02)];
|
||||
ly = digital_to_analog[1 - !(ext[4] & 0x40)
|
||||
+ !(ext[5] & 0x01)];
|
||||
} else {
|
||||
lx = (ext[0] & 0x3f) - 0x20;
|
||||
ly = (ext[1] & 0x3f) - 0x20;
|
||||
}
|
||||
}
|
||||
|
||||
rx = (ext[0] >> 3) & 0x18;
|
||||
@@ -1110,19 +1126,13 @@ static void wiimod_classic_in_ext(struct wiimote_data *wdata, const __u8 *ext)
|
||||
rt <<= 1;
|
||||
lt <<= 1;
|
||||
|
||||
input_report_abs(wdata->extension.input, ABS_HAT1X, lx - 0x20);
|
||||
input_report_abs(wdata->extension.input, ABS_HAT1Y, ly - 0x20);
|
||||
input_report_abs(wdata->extension.input, ABS_HAT1X, lx);
|
||||
input_report_abs(wdata->extension.input, ABS_HAT1Y, ly);
|
||||
input_report_abs(wdata->extension.input, ABS_HAT2X, rx - 0x20);
|
||||
input_report_abs(wdata->extension.input, ABS_HAT2Y, ry - 0x20);
|
||||
input_report_abs(wdata->extension.input, ABS_HAT3X, rt);
|
||||
input_report_abs(wdata->extension.input, ABS_HAT3Y, lt);
|
||||
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_classic_map[WIIMOD_CLASSIC_KEY_RIGHT],
|
||||
!(ext[4] & 0x80));
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_classic_map[WIIMOD_CLASSIC_KEY_DOWN],
|
||||
!(ext[4] & 0x40));
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_classic_map[WIIMOD_CLASSIC_KEY_LT],
|
||||
!(ext[4] & 0x20));
|
||||
@@ -1157,20 +1167,29 @@ static void wiimod_classic_in_ext(struct wiimote_data *wdata, const __u8 *ext)
|
||||
wiimod_classic_map[WIIMOD_CLASSIC_KEY_ZR],
|
||||
!(ext[5] & 0x04));
|
||||
|
||||
if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) {
|
||||
if (!wiimote_dpad_as_analog) {
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_classic_map[WIIMOD_CLASSIC_KEY_LEFT],
|
||||
!(ext[1] & 0x01));
|
||||
wiimod_classic_map[WIIMOD_CLASSIC_KEY_RIGHT],
|
||||
!(ext[4] & 0x80));
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_classic_map[WIIMOD_CLASSIC_KEY_UP],
|
||||
!(ext[0] & 0x01));
|
||||
} else {
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_classic_map[WIIMOD_CLASSIC_KEY_LEFT],
|
||||
!(ext[5] & 0x02));
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_classic_map[WIIMOD_CLASSIC_KEY_UP],
|
||||
!(ext[5] & 0x01));
|
||||
wiimod_classic_map[WIIMOD_CLASSIC_KEY_DOWN],
|
||||
!(ext[4] & 0x40));
|
||||
|
||||
if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) {
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_classic_map[WIIMOD_CLASSIC_KEY_LEFT],
|
||||
!(ext[1] & 0x01));
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_classic_map[WIIMOD_CLASSIC_KEY_UP],
|
||||
!(ext[0] & 0x01));
|
||||
} else {
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_classic_map[WIIMOD_CLASSIC_KEY_LEFT],
|
||||
!(ext[5] & 0x02));
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_classic_map[WIIMOD_CLASSIC_KEY_UP],
|
||||
!(ext[5] & 0x01));
|
||||
}
|
||||
}
|
||||
|
||||
input_sync(wdata->extension.input);
|
||||
|
@@ -162,6 +162,8 @@ struct wiimote_data {
|
||||
struct work_struct init_worker;
|
||||
};
|
||||
|
||||
extern bool wiimote_dpad_as_analog;
|
||||
|
||||
/* wiimote modules */
|
||||
|
||||
enum wiimod_module {
|
||||
|
@@ -106,6 +106,11 @@ static inline bool ish_should_enter_d0i3(struct pci_dev *pdev)
|
||||
return !pm_suspend_via_firmware() || pdev->device == CHV_DEVICE_ID;
|
||||
}
|
||||
|
||||
static inline bool ish_should_leave_d0i3(struct pci_dev *pdev)
|
||||
{
|
||||
return !pm_resume_via_firmware() || pdev->device == CHV_DEVICE_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* ish_probe() - PCI driver probe callback
|
||||
* @pdev: pci device
|
||||
@@ -215,9 +220,7 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work)
|
||||
struct ishtp_device *dev = pci_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
/* Check the NO_D3 flag to distinguish the resume paths */
|
||||
if (pdev->dev_flags & PCI_DEV_FLAGS_NO_D3) {
|
||||
pdev->dev_flags &= ~PCI_DEV_FLAGS_NO_D3;
|
||||
if (ish_should_leave_d0i3(pdev) && !dev->suspend_flag) {
|
||||
disable_irq_wake(pdev->irq);
|
||||
|
||||
ishtp_send_resume(dev);
|
||||
@@ -281,8 +284,11 @@ static int __maybe_unused ish_suspend(struct device *device)
|
||||
*/
|
||||
ish_disable_dma(dev);
|
||||
} else {
|
||||
/* Set the NO_D3 flag, the ISH would enter D0i3 */
|
||||
pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
|
||||
/*
|
||||
* Save state so PCI core will keep the device at D0,
|
||||
* the ISH would enter D0i3
|
||||
*/
|
||||
pci_save_state(pdev);
|
||||
|
||||
enable_irq_wake(pdev->irq);
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include <linux/wait.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/timekeeping.h>
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
@@ -95,6 +96,18 @@ static int hid_start_in(struct hid_device *hid)
|
||||
set_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
|
||||
} else {
|
||||
clear_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
|
||||
|
||||
if (test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
|
||||
/*
|
||||
* In case events are generated while nobody was
|
||||
* listening, some are released when the device
|
||||
* is re-opened. Wait 50 msec for the queue to
|
||||
* empty before allowing events to go through
|
||||
* hid.
|
||||
*/
|
||||
usbhid->input_start_time =
|
||||
ktime_add_ms(ktime_get_coarse(), 50);
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&usbhid->lock, flags);
|
||||
@@ -280,20 +293,23 @@ static void hid_irq_in(struct urb *urb)
|
||||
if (!test_bit(HID_OPENED, &usbhid->iofl))
|
||||
break;
|
||||
usbhid_mark_busy(usbhid);
|
||||
if (!test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
|
||||
hid_input_report(urb->context, HID_INPUT_REPORT,
|
||||
urb->transfer_buffer,
|
||||
urb->actual_length, 1);
|
||||
/*
|
||||
* autosuspend refused while keys are pressed
|
||||
* because most keyboards don't wake up when
|
||||
* a key is released
|
||||
*/
|
||||
if (hid_check_keys_pressed(hid))
|
||||
set_bit(HID_KEYS_PRESSED, &usbhid->iofl);
|
||||
else
|
||||
clear_bit(HID_KEYS_PRESSED, &usbhid->iofl);
|
||||
if (test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
|
||||
if (ktime_before(ktime_get_coarse(),
|
||||
usbhid->input_start_time))
|
||||
break;
|
||||
clear_bit(HID_RESUME_RUNNING, &usbhid->iofl);
|
||||
}
|
||||
hid_input_report(urb->context, HID_INPUT_REPORT,
|
||||
urb->transfer_buffer, urb->actual_length, 1);
|
||||
/*
|
||||
* autosuspend refused while keys are pressed
|
||||
* because most keyboards don't wake up when
|
||||
* a key is released
|
||||
*/
|
||||
if (hid_check_keys_pressed(hid))
|
||||
set_bit(HID_KEYS_PRESSED, &usbhid->iofl);
|
||||
else
|
||||
clear_bit(HID_KEYS_PRESSED, &usbhid->iofl);
|
||||
break;
|
||||
case -EPIPE: /* stall */
|
||||
usbhid_mark_busy(usbhid);
|
||||
@@ -720,17 +736,6 @@ static int usbhid_open(struct hid_device *hid)
|
||||
|
||||
usb_autopm_put_interface(usbhid->intf);
|
||||
|
||||
/*
|
||||
* In case events are generated while nobody was listening,
|
||||
* some are released when the device is re-opened.
|
||||
* Wait 50 msec for the queue to empty before allowing events
|
||||
* to go through hid.
|
||||
*/
|
||||
if (res == 0)
|
||||
msleep(50);
|
||||
|
||||
clear_bit(HID_RESUME_RUNNING, &usbhid->iofl);
|
||||
|
||||
Done:
|
||||
mutex_unlock(&usbhid->mutex);
|
||||
return res;
|
||||
@@ -1667,7 +1672,7 @@ struct usb_interface *usbhid_find_interface(int minor)
|
||||
|
||||
static int __init hid_init(void)
|
||||
{
|
||||
int retval = -ENOMEM;
|
||||
int retval;
|
||||
|
||||
retval = hid_quirks_init(quirks_param, BUS_USB, MAX_USBHID_BOOT_QUIRKS);
|
||||
if (retval)
|
||||
|
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/timer.h>
|
||||
@@ -83,6 +84,7 @@ struct usbhid_device {
|
||||
struct mutex mutex; /* start/stop/open/close */
|
||||
spinlock_t lock; /* fifo spinlock */
|
||||
unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
|
||||
ktime_t input_start_time; /* When to start handling input */
|
||||
struct timer_list io_retry; /* Retry timer */
|
||||
unsigned long stop_retry; /* Time to give up, in jiffies */
|
||||
unsigned int retry_delay; /* Delay length in ms */
|
||||
|
@@ -16,7 +16,7 @@ static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src)
|
||||
if (dev->absinfo && test_bit(src, dev->absbit)) {
|
||||
dev->absinfo[dst] = dev->absinfo[src];
|
||||
dev->absinfo[dst].fuzz = 0;
|
||||
dev->absbit[BIT_WORD(dst)] |= BIT_MASK(dst);
|
||||
__set_bit(dst, dev->absbit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -247,7 +247,7 @@ static unsigned char db9_saturn_read_packet(struct parport *port, unsigned char
|
||||
db9_saturn_write_sub(port, type, 3, powered, 0);
|
||||
return data[0] = 0xe3;
|
||||
}
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
default:
|
||||
return data[0];
|
||||
}
|
||||
@@ -267,14 +267,14 @@ static int db9_saturn_report(unsigned char id, unsigned char data[60], struct in
|
||||
switch (data[j]) {
|
||||
case 0x16: /* multi controller (analog 4 axis) */
|
||||
input_report_abs(dev, db9_abs[5], data[j + 6]);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 0x15: /* mission stick (analog 3 axis) */
|
||||
input_report_abs(dev, db9_abs[3], data[j + 4]);
|
||||
input_report_abs(dev, db9_abs[4], data[j + 5]);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 0x13: /* racing controller (analog 1 axis) */
|
||||
input_report_abs(dev, db9_abs[2], data[j + 3]);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 0x34: /* saturn keyboard (udlr ZXC ASD QE Esc) */
|
||||
case 0x02: /* digital pad (digital 2 axis + buttons) */
|
||||
input_report_abs(dev, db9_abs[0], !(data[j + 1] & 128) - !(data[j + 1] & 64));
|
||||
@@ -368,7 +368,7 @@ static void db9_timer(struct timer_list *t)
|
||||
input_report_abs(dev2, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
|
||||
input_report_abs(dev2, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
|
||||
input_report_key(dev2, BTN_TRIGGER, ~data & DB9_FIRE1);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case DB9_MULTI_0802:
|
||||
|
||||
|
@@ -485,7 +485,7 @@ static void gc_multi_process_packet(struct gc *gc)
|
||||
switch (pad->type) {
|
||||
case GC_MULTI2:
|
||||
input_report_key(dev, BTN_THUMB, s & data[5]);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case GC_MULTI:
|
||||
input_report_abs(dev, ABS_X,
|
||||
@@ -638,7 +638,7 @@ static void gc_psx_report_one(struct gc_pad *pad, unsigned char psx_type,
|
||||
|
||||
input_report_key(dev, BTN_THUMBL, ~data[0] & 0x04);
|
||||
input_report_key(dev, BTN_THUMBR, ~data[0] & 0x02);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case GC_PSX_NEGCON:
|
||||
case GC_PSX_ANALOG:
|
||||
@@ -872,7 +872,8 @@ static int gc_setup_pad(struct gc *gc, int idx, int pad_type)
|
||||
case GC_SNES:
|
||||
for (i = 4; i < 8; i++)
|
||||
input_set_capability(input_dev, EV_KEY, gc_snes_btn[i]);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case GC_NES:
|
||||
for (i = 0; i < 4; i++)
|
||||
input_set_capability(input_dev, EV_KEY, gc_snes_btn[i]);
|
||||
@@ -880,7 +881,8 @@ static int gc_setup_pad(struct gc *gc, int idx, int pad_type)
|
||||
|
||||
case GC_MULTI2:
|
||||
input_set_capability(input_dev, EV_KEY, BTN_THUMB);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case GC_MULTI:
|
||||
input_set_capability(input_dev, EV_KEY, BTN_TRIGGER);
|
||||
/* fall through */
|
||||
|
@@ -656,16 +656,19 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
|
||||
|
||||
switch (i * m) {
|
||||
case 60:
|
||||
sw->number++; /* fall through */
|
||||
sw->number++;
|
||||
fallthrough;
|
||||
case 45: /* Ambiguous packet length */
|
||||
if (j <= 40) { /* ID length less or eq 40 -> FSP */
|
||||
case 43:
|
||||
sw->type = SW_ID_FSP;
|
||||
break;
|
||||
}
|
||||
sw->number++; /* fall through */
|
||||
sw->number++;
|
||||
fallthrough;
|
||||
case 30:
|
||||
sw->number++; /* fall through */
|
||||
sw->number++;
|
||||
fallthrough;
|
||||
case 15:
|
||||
sw->type = SW_ID_GP;
|
||||
break;
|
||||
@@ -681,9 +684,11 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
|
||||
sw->type = SW_ID_PP;
|
||||
break;
|
||||
case 66:
|
||||
sw->bits = 3; /* fall through */
|
||||
sw->bits = 3;
|
||||
fallthrough;
|
||||
case 198:
|
||||
sw->length = 22; /* fall through */
|
||||
sw->length = 22;
|
||||
fallthrough;
|
||||
case 64:
|
||||
sw->type = SW_ID_3DP;
|
||||
if (j == 160)
|
||||
|
@@ -146,7 +146,7 @@ static irqreturn_t spaceball_interrupt(struct serio *serio,
|
||||
break;
|
||||
}
|
||||
spaceball->escape = 0;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 'M':
|
||||
case 'Q':
|
||||
case 'S':
|
||||
@@ -154,7 +154,7 @@ static irqreturn_t spaceball_interrupt(struct serio *serio,
|
||||
spaceball->escape = 0;
|
||||
data &= 0x1f;
|
||||
}
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
default:
|
||||
if (spaceball->escape)
|
||||
spaceball->escape = 0;
|
||||
@@ -220,13 +220,13 @@ static int spaceball_connect(struct serio *serio, struct serio_driver *drv)
|
||||
input_dev->keybit[BIT_WORD(BTN_A)] |= BIT_MASK(BTN_A) |
|
||||
BIT_MASK(BTN_B) | BIT_MASK(BTN_C) |
|
||||
BIT_MASK(BTN_MODE);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
default:
|
||||
input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_2) |
|
||||
BIT_MASK(BTN_3) | BIT_MASK(BTN_4) |
|
||||
BIT_MASK(BTN_5) | BIT_MASK(BTN_6) |
|
||||
BIT_MASK(BTN_7) | BIT_MASK(BTN_8);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case SPACEBALL_3003C:
|
||||
input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_1) |
|
||||
BIT_MASK(BTN_8);
|
||||
|
@@ -1016,7 +1016,7 @@ static int adp5589_probe(struct i2c_client *client,
|
||||
switch (id->driver_data) {
|
||||
case ADP5585_02:
|
||||
kpad->support_row5 = true;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case ADP5585_01:
|
||||
kpad->is_adp5585 = true;
|
||||
kpad->var = &const_adp5585;
|
||||
|
@@ -1241,7 +1241,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
|
||||
|
||||
case SERIO_8042_XL:
|
||||
atkbd->translated = true;
|
||||
/* Fall through */
|
||||
fallthrough;
|
||||
|
||||
case SERIO_8042:
|
||||
if (serio->write)
|
||||
|
@@ -574,7 +574,6 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
|
||||
IRQ_TYPE_EDGE_RISING : IRQ_TYPE_EDGE_FALLING;
|
||||
break;
|
||||
case EV_ACT_ANY:
|
||||
/* fall through */
|
||||
default:
|
||||
/*
|
||||
* For other cases, we are OK letting suspend/resume
|
||||
|
@@ -68,7 +68,7 @@ static int ati_remote2_get_channel_mask(char *buffer,
|
||||
{
|
||||
pr_debug("%s()\n", __func__);
|
||||
|
||||
return sprintf(buffer, "0x%04x", *(unsigned int *)kp->arg);
|
||||
return sprintf(buffer, "0x%04x\n", *(unsigned int *)kp->arg);
|
||||
}
|
||||
|
||||
static int ati_remote2_set_mode_mask(const char *val,
|
||||
@@ -84,7 +84,7 @@ static int ati_remote2_get_mode_mask(char *buffer,
|
||||
{
|
||||
pr_debug("%s()\n", __func__);
|
||||
|
||||
return sprintf(buffer, "0x%02x", *(unsigned int *)kp->arg);
|
||||
return sprintf(buffer, "0x%02x\n", *(unsigned int *)kp->arg);
|
||||
}
|
||||
|
||||
static unsigned int channel_mask = ATI_REMOTE2_MAX_CHANNEL_MASK;
|
||||
|
@@ -663,12 +663,8 @@ static const struct usb_device_id cm109_usb_table[] = {
|
||||
static void cm109_usb_cleanup(struct cm109_dev *dev)
|
||||
{
|
||||
kfree(dev->ctl_req);
|
||||
if (dev->ctl_data)
|
||||
usb_free_coherent(dev->udev, USB_PKT_LEN,
|
||||
dev->ctl_data, dev->ctl_dma);
|
||||
if (dev->irq_data)
|
||||
usb_free_coherent(dev->udev, USB_PKT_LEN,
|
||||
dev->irq_data, dev->irq_dma);
|
||||
usb_free_coherent(dev->udev, USB_PKT_LEN, dev->ctl_data, dev->ctl_dma);
|
||||
usb_free_coherent(dev->udev, USB_PKT_LEN, dev->irq_data, dev->irq_dma);
|
||||
|
||||
usb_free_urb(dev->urb_irq); /* parameter validation in core/urb */
|
||||
usb_free_urb(dev->urb_ctl); /* parameter validation in core/urb */
|
||||
|
@@ -335,7 +335,7 @@ static int ims_pcu_setup_gamepad(struct ims_pcu *pcu)
|
||||
err_free_mem:
|
||||
input_free_device(input);
|
||||
kfree(gamepad);
|
||||
return -ENOMEM;
|
||||
return error;
|
||||
}
|
||||
|
||||
static void ims_pcu_destroy_gamepad(struct ims_pcu *pcu)
|
||||
|
@@ -575,8 +575,7 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269,
|
||||
|
||||
case IQS269_LOCAL_CAP_SIZE_GLOBAL_0pF5:
|
||||
engine_a |= IQS269_CHx_ENG_A_LOCAL_CAP_SIZE;
|
||||
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case IQS269_LOCAL_CAP_SIZE_GLOBAL_ONLY:
|
||||
engine_b |= IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE;
|
||||
@@ -731,14 +730,12 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269,
|
||||
iqs269->switches[i].code = val;
|
||||
iqs269->switches[i].enabled = true;
|
||||
}
|
||||
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case IQS269_CHx_HALL_INACTIVE:
|
||||
if (iqs269->hall_enable)
|
||||
break;
|
||||
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
default:
|
||||
iqs269->keycode[i * IQS269_NUM_CH + reg] = val;
|
||||
@@ -1143,14 +1140,12 @@ static int iqs269_input_init(struct iqs269_private *iqs269)
|
||||
sw_code,
|
||||
state & BIT(j));
|
||||
}
|
||||
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case IQS269_CHx_HALL_INACTIVE:
|
||||
if (iqs269->hall_enable)
|
||||
continue;
|
||||
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
default:
|
||||
if (keycode != KEY_RESERVED)
|
||||
@@ -1273,14 +1268,12 @@ static int iqs269_report(struct iqs269_private *iqs269)
|
||||
input_report_switch(iqs269->keypad,
|
||||
sw_code,
|
||||
state & BIT(j));
|
||||
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case IQS269_CHx_HALL_INACTIVE:
|
||||
if (iqs269->hall_enable)
|
||||
continue;
|
||||
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
default:
|
||||
input_report_key(iqs269->keypad, keycode,
|
||||
|
@@ -190,7 +190,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev)
|
||||
|
||||
default:
|
||||
dev_err(&pdev->dev, "Failed to request direction pwm: %d", err);
|
||||
/* Fall through */
|
||||
fallthrough;
|
||||
|
||||
case -EPROBE_DEFER:
|
||||
return err;
|
||||
|
@@ -124,7 +124,7 @@ static void xenkbd_handle_mt_event(struct xenkbd_info *info,
|
||||
switch (mtouch->event_type) {
|
||||
case XENKBD_MT_EV_DOWN:
|
||||
input_mt_report_slot_state(info->mtouch, MT_TOOL_FINGER, true);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case XENKBD_MT_EV_MOTION:
|
||||
input_report_abs(info->mtouch, ABS_MT_POSITION_X,
|
||||
@@ -524,7 +524,7 @@ static void xenkbd_backend_changed(struct xenbus_device *dev,
|
||||
case XenbusStateClosed:
|
||||
if (dev->state == XenbusStateClosed)
|
||||
break;
|
||||
/* fall through - Missed the backend's CLOSING state */
|
||||
fallthrough; /* Missed the backend's CLOSING state */
|
||||
case XenbusStateClosing:
|
||||
xenbus_frontend_closed(dev);
|
||||
break;
|
||||
|
@@ -1929,7 +1929,7 @@ static int alps_monitor_mode(struct psmouse *psmouse, bool enable)
|
||||
static int alps_absolute_mode_v6(struct psmouse *psmouse)
|
||||
{
|
||||
u16 reg_val = 0x181;
|
||||
int ret = -1;
|
||||
int ret;
|
||||
|
||||
/* enter monitor mode, to write the register */
|
||||
if (alps_monitor_mode(psmouse, true))
|
||||
|
@@ -458,7 +458,7 @@ static int atp_status_check(struct urb *urb)
|
||||
dev->info->datalen, dev->urb->actual_length);
|
||||
dev->overflow_warned = true;
|
||||
}
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case -ECONNRESET:
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
|
@@ -1067,7 +1067,7 @@ static int cyapa_gen3_do_operational_check(struct cyapa *cyapa)
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Fall through */
|
||||
fallthrough;
|
||||
case CYAPA_STATE_BL_IDLE:
|
||||
/* Try to get firmware version in bootloader mode. */
|
||||
cyapa_gen3_bl_query_data(cyapa);
|
||||
@@ -1078,7 +1078,7 @@ static int cyapa_gen3_do_operational_check(struct cyapa *cyapa)
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Fall through */
|
||||
fallthrough;
|
||||
case CYAPA_STATE_OP:
|
||||
/*
|
||||
* Reading query data before going back to the full mode
|
||||
|
@@ -2554,7 +2554,7 @@ static int cyapa_gen5_do_operational_check(struct cyapa *cyapa)
|
||||
}
|
||||
|
||||
cyapa->state = CYAPA_STATE_GEN5_APP;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case CYAPA_STATE_GEN5_APP:
|
||||
/*
|
||||
|
@@ -680,7 +680,7 @@ static int cyapa_gen6_operational_check(struct cyapa *cyapa)
|
||||
}
|
||||
|
||||
cyapa->state = CYAPA_STATE_GEN6_APP;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case CYAPA_STATE_GEN6_APP:
|
||||
/*
|
||||
|
@@ -26,6 +26,8 @@
|
||||
|
||||
#define ETP_CALIBRATE_MAX_LEN 3
|
||||
|
||||
#define ETP_FEATURE_REPORT_MK BIT(0)
|
||||
|
||||
/* IAP Firmware handling */
|
||||
#define ETP_PRODUCT_ID_FORMAT_STRING "%d.0"
|
||||
#define ETP_FW_NAME "elan_i2c_" ETP_PRODUCT_ID_FORMAT_STRING ".bin"
|
||||
@@ -33,6 +35,8 @@
|
||||
#define ETP_FW_IAP_PAGE_ERR (1 << 5)
|
||||
#define ETP_FW_IAP_INTF_ERR (1 << 4)
|
||||
#define ETP_FW_PAGE_SIZE 64
|
||||
#define ETP_FW_PAGE_SIZE_128 128
|
||||
#define ETP_FW_PAGE_SIZE_512 512
|
||||
#define ETP_FW_SIGNATURE_SIZE 6
|
||||
|
||||
struct i2c_client;
|
||||
@@ -55,8 +59,9 @@ struct elan_transport_ops {
|
||||
int (*get_baseline_data)(struct i2c_client *client,
|
||||
bool max_baseliune, u8 *value);
|
||||
|
||||
int (*get_version)(struct i2c_client *client, bool iap, u8 *version);
|
||||
int (*get_sm_version)(struct i2c_client *client,
|
||||
int (*get_version)(struct i2c_client *client, u8 pattern, bool iap,
|
||||
u8 *version);
|
||||
int (*get_sm_version)(struct i2c_client *client, u8 pattern,
|
||||
u16 *ic_type, u8 *version, u8 *clickpad);
|
||||
int (*get_checksum)(struct i2c_client *client, bool iap, u16 *csum);
|
||||
int (*get_product_id)(struct i2c_client *client, u16 *id);
|
||||
@@ -72,13 +77,18 @@ struct elan_transport_ops {
|
||||
int (*iap_get_mode)(struct i2c_client *client, enum tp_mode *mode);
|
||||
int (*iap_reset)(struct i2c_client *client);
|
||||
|
||||
int (*prepare_fw_update)(struct i2c_client *client);
|
||||
int (*write_fw_block)(struct i2c_client *client,
|
||||
int (*prepare_fw_update)(struct i2c_client *client, u16 ic_type,
|
||||
u8 iap_version);
|
||||
int (*write_fw_block)(struct i2c_client *client, u16 fw_page_size,
|
||||
const u8 *page, u16 checksum, int idx);
|
||||
int (*finish_fw_update)(struct i2c_client *client,
|
||||
struct completion *reset_done);
|
||||
|
||||
int (*get_report)(struct i2c_client *client, u8 *report);
|
||||
int (*get_report_features)(struct i2c_client *client, u8 pattern,
|
||||
unsigned int *features,
|
||||
unsigned int *report_len);
|
||||
int (*get_report)(struct i2c_client *client, u8 *report,
|
||||
unsigned int report_len);
|
||||
int (*get_pressure_adjustment)(struct i2c_client *client,
|
||||
int *adjustment);
|
||||
int (*get_pattern)(struct i2c_client *client, u8 *pattern);
|
||||
|
@@ -50,12 +50,14 @@
|
||||
#define ETP_MAX_FINGERS 5
|
||||
#define ETP_FINGER_DATA_LEN 5
|
||||
#define ETP_REPORT_ID 0x5D
|
||||
#define ETP_REPORT_ID2 0x60 /* High precision report */
|
||||
#define ETP_TP_REPORT_ID 0x5E
|
||||
#define ETP_REPORT_ID_OFFSET 2
|
||||
#define ETP_TOUCH_INFO_OFFSET 3
|
||||
#define ETP_FINGER_DATA_OFFSET 4
|
||||
#define ETP_HOVER_INFO_OFFSET 30
|
||||
#define ETP_MAX_REPORT_LEN 34
|
||||
#define ETP_MK_DATA_OFFSET 33 /* For high precision reports */
|
||||
#define ETP_MAX_REPORT_LEN 39
|
||||
|
||||
/* The main device structure */
|
||||
struct elan_tp_data {
|
||||
@@ -85,11 +87,14 @@ struct elan_tp_data {
|
||||
u8 sm_version;
|
||||
u8 iap_version;
|
||||
u16 fw_checksum;
|
||||
unsigned int report_features;
|
||||
unsigned int report_len;
|
||||
int pressure_adjustment;
|
||||
u8 mode;
|
||||
u16 ic_type;
|
||||
u16 fw_validpage_count;
|
||||
u16 fw_signature_address;
|
||||
u16 fw_page_size;
|
||||
u32 fw_signature_address;
|
||||
|
||||
bool irq_wake;
|
||||
|
||||
@@ -100,8 +105,8 @@ struct elan_tp_data {
|
||||
bool middle_button;
|
||||
};
|
||||
|
||||
static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count,
|
||||
u16 *signature_address)
|
||||
static int elan_get_fwinfo(u16 ic_type, u8 iap_version, u16 *validpage_count,
|
||||
u32 *signature_address, u16 *page_size)
|
||||
{
|
||||
switch (ic_type) {
|
||||
case 0x00:
|
||||
@@ -126,16 +131,37 @@ static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count,
|
||||
case 0x10:
|
||||
*validpage_count = 1024;
|
||||
break;
|
||||
case 0x11:
|
||||
*validpage_count = 1280;
|
||||
break;
|
||||
case 0x13:
|
||||
*validpage_count = 2048;
|
||||
break;
|
||||
case 0x14:
|
||||
case 0x15:
|
||||
*validpage_count = 1024;
|
||||
break;
|
||||
default:
|
||||
/* unknown ic type clear value */
|
||||
*validpage_count = 0;
|
||||
*signature_address = 0;
|
||||
*page_size = 0;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
*signature_address =
|
||||
(*validpage_count * ETP_FW_PAGE_SIZE) - ETP_FW_SIGNATURE_SIZE;
|
||||
|
||||
if ((ic_type == 0x14 || ic_type == 0x15) && iap_version >= 2) {
|
||||
*validpage_count /= 8;
|
||||
*page_size = ETP_FW_PAGE_SIZE_512;
|
||||
} else if (ic_type >= 0x0D && iap_version >= 1) {
|
||||
*validpage_count /= 2;
|
||||
*page_size = ETP_FW_PAGE_SIZE_128;
|
||||
} else {
|
||||
*page_size = ETP_FW_PAGE_SIZE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -215,8 +241,13 @@ static int elan_query_product(struct elan_tp_data *data)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = data->ops->get_sm_version(data->client, &data->ic_type,
|
||||
&data->sm_version, &data->clickpad);
|
||||
error = data->ops->get_pattern(data->client, &data->pattern);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = data->ops->get_sm_version(data->client, data->pattern,
|
||||
&data->ic_type, &data->sm_version,
|
||||
&data->clickpad);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@@ -312,9 +343,9 @@ static int elan_initialize(struct elan_tp_data *data)
|
||||
static int elan_query_device_info(struct elan_tp_data *data)
|
||||
{
|
||||
int error;
|
||||
u16 ic_type;
|
||||
|
||||
error = data->ops->get_version(data->client, false, &data->fw_version);
|
||||
error = data->ops->get_version(data->client, data->pattern, false,
|
||||
&data->fw_version);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@@ -323,7 +354,8 @@ static int elan_query_device_info(struct elan_tp_data *data)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = data->ops->get_version(data->client, true, &data->iap_version);
|
||||
error = data->ops->get_version(data->client, data->pattern,
|
||||
true, &data->iap_version);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@@ -332,17 +364,16 @@ static int elan_query_device_info(struct elan_tp_data *data)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = data->ops->get_pattern(data->client, &data->pattern);
|
||||
error = data->ops->get_report_features(data->client, data->pattern,
|
||||
&data->report_features,
|
||||
&data->report_len);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (data->pattern == 0x01)
|
||||
ic_type = data->ic_type;
|
||||
else
|
||||
ic_type = data->iap_version;
|
||||
|
||||
error = elan_get_fwinfo(ic_type, &data->fw_validpage_count,
|
||||
&data->fw_signature_address);
|
||||
error = elan_get_fwinfo(data->ic_type, data->iap_version,
|
||||
&data->fw_validpage_count,
|
||||
&data->fw_signature_address,
|
||||
&data->fw_page_size);
|
||||
if (error)
|
||||
dev_warn(&data->client->dev,
|
||||
"unexpected iap version %#04x (ic type: %#04x), firmware update will not work\n",
|
||||
@@ -351,16 +382,21 @@ static int elan_query_device_info(struct elan_tp_data *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int elan_convert_resolution(u8 val)
|
||||
static unsigned int elan_convert_resolution(u8 val, u8 pattern)
|
||||
{
|
||||
/*
|
||||
* (value from firmware) * 10 + 790 = dpi
|
||||
*
|
||||
* pattern <= 0x01:
|
||||
* (value from firmware) * 10 + 790 = dpi
|
||||
* else
|
||||
* ((value from firmware) + 3) * 100 = dpi
|
||||
*/
|
||||
int res = pattern <= 0x01 ?
|
||||
(int)(char)val * 10 + 790 : ((int)(char)val + 3) * 100;
|
||||
/*
|
||||
* We also have to convert dpi to dots/mm (*10/254 to avoid floating
|
||||
* point).
|
||||
*/
|
||||
|
||||
return ((int)(char)val * 10 + 790) * 10 / 254;
|
||||
return res * 10 / 254;
|
||||
}
|
||||
|
||||
static int elan_query_device_parameters(struct elan_tp_data *data)
|
||||
@@ -409,8 +445,8 @@ static int elan_query_device_parameters(struct elan_tp_data *data)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
data->x_res = elan_convert_resolution(hw_x_res);
|
||||
data->y_res = elan_convert_resolution(hw_y_res);
|
||||
data->x_res = elan_convert_resolution(hw_x_res, data->pattern);
|
||||
data->y_res = elan_convert_resolution(hw_y_res, data->pattern);
|
||||
} else {
|
||||
data->x_res = (data->max_x + 1) / x_mm;
|
||||
data->y_res = (data->max_y + 1) / y_mm;
|
||||
@@ -430,14 +466,14 @@ static int elan_query_device_parameters(struct elan_tp_data *data)
|
||||
* IAP firmware updater related routines
|
||||
**********************************************************
|
||||
*/
|
||||
static int elan_write_fw_block(struct elan_tp_data *data,
|
||||
static int elan_write_fw_block(struct elan_tp_data *data, u16 page_size,
|
||||
const u8 *page, u16 checksum, int idx)
|
||||
{
|
||||
int retry = ETP_RETRY_COUNT;
|
||||
int error;
|
||||
|
||||
do {
|
||||
error = data->ops->write_fw_block(data->client,
|
||||
error = data->ops->write_fw_block(data->client, page_size,
|
||||
page, checksum, idx);
|
||||
if (!error)
|
||||
return 0;
|
||||
@@ -460,21 +496,23 @@ static int __elan_update_firmware(struct elan_tp_data *data,
|
||||
u16 boot_page_count;
|
||||
u16 sw_checksum = 0, fw_checksum = 0;
|
||||
|
||||
error = data->ops->prepare_fw_update(client);
|
||||
error = data->ops->prepare_fw_update(client, data->ic_type,
|
||||
data->iap_version);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]);
|
||||
|
||||
boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE;
|
||||
boot_page_count = (iap_start_addr * 2) / data->fw_page_size;
|
||||
for (i = boot_page_count; i < data->fw_validpage_count; i++) {
|
||||
u16 checksum = 0;
|
||||
const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE];
|
||||
const u8 *page = &fw->data[i * data->fw_page_size];
|
||||
|
||||
for (j = 0; j < ETP_FW_PAGE_SIZE; j += 2)
|
||||
for (j = 0; j < data->fw_page_size; j += 2)
|
||||
checksum += ((page[j + 1] << 8) | page[j]);
|
||||
|
||||
error = elan_write_fw_block(data, page, checksum, i);
|
||||
error = elan_write_fw_block(data, data->fw_page_size,
|
||||
page, checksum, i);
|
||||
if (error) {
|
||||
dev_err(dev, "write page %d fail: %d\n", i, error);
|
||||
return error;
|
||||
@@ -886,24 +924,22 @@ static const struct attribute_group *elan_sysfs_groups[] = {
|
||||
* Elan isr functions
|
||||
******************************************************************
|
||||
*/
|
||||
static void elan_report_contact(struct elan_tp_data *data,
|
||||
int contact_num, bool contact_valid,
|
||||
u8 *finger_data)
|
||||
static void elan_report_contact(struct elan_tp_data *data, int contact_num,
|
||||
bool contact_valid, bool high_precision,
|
||||
u8 *packet, u8 *finger_data)
|
||||
{
|
||||
struct input_dev *input = data->input;
|
||||
unsigned int pos_x, pos_y;
|
||||
unsigned int pressure, mk_x, mk_y;
|
||||
unsigned int area_x, area_y, major, minor;
|
||||
unsigned int scaled_pressure;
|
||||
unsigned int pressure, scaled_pressure;
|
||||
|
||||
if (contact_valid) {
|
||||
pos_x = ((finger_data[0] & 0xf0) << 4) |
|
||||
finger_data[1];
|
||||
pos_y = ((finger_data[0] & 0x0f) << 8) |
|
||||
finger_data[2];
|
||||
mk_x = (finger_data[3] & 0x0f);
|
||||
mk_y = (finger_data[3] >> 4);
|
||||
pressure = finger_data[4];
|
||||
if (high_precision) {
|
||||
pos_x = get_unaligned_be16(&finger_data[0]);
|
||||
pos_y = get_unaligned_be16(&finger_data[2]);
|
||||
} else {
|
||||
pos_x = ((finger_data[0] & 0xf0) << 4) | finger_data[1];
|
||||
pos_y = ((finger_data[0] & 0x0f) << 8) | finger_data[2];
|
||||
}
|
||||
|
||||
if (pos_x > data->max_x || pos_y > data->max_y) {
|
||||
dev_dbg(input->dev.parent,
|
||||
@@ -913,18 +949,8 @@ static void elan_report_contact(struct elan_tp_data *data,
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* To avoid treating large finger as palm, let's reduce the
|
||||
* width x and y per trace.
|
||||
*/
|
||||
area_x = mk_x * (data->width_x - ETP_FWIDTH_REDUCE);
|
||||
area_y = mk_y * (data->width_y - ETP_FWIDTH_REDUCE);
|
||||
|
||||
major = max(area_x, area_y);
|
||||
minor = min(area_x, area_y);
|
||||
|
||||
pressure = finger_data[4];
|
||||
scaled_pressure = pressure + data->pressure_adjustment;
|
||||
|
||||
if (scaled_pressure > ETP_MAX_PRESSURE)
|
||||
scaled_pressure = ETP_MAX_PRESSURE;
|
||||
|
||||
@@ -933,16 +959,37 @@ static void elan_report_contact(struct elan_tp_data *data,
|
||||
input_report_abs(input, ABS_MT_POSITION_X, pos_x);
|
||||
input_report_abs(input, ABS_MT_POSITION_Y, data->max_y - pos_y);
|
||||
input_report_abs(input, ABS_MT_PRESSURE, scaled_pressure);
|
||||
input_report_abs(input, ABS_TOOL_WIDTH, mk_x);
|
||||
input_report_abs(input, ABS_MT_TOUCH_MAJOR, major);
|
||||
input_report_abs(input, ABS_MT_TOUCH_MINOR, minor);
|
||||
|
||||
if (data->report_features & ETP_FEATURE_REPORT_MK) {
|
||||
unsigned int mk_x, mk_y, area_x, area_y;
|
||||
u8 mk_data = high_precision ?
|
||||
packet[ETP_MK_DATA_OFFSET + contact_num] :
|
||||
finger_data[3];
|
||||
|
||||
mk_x = mk_data & 0x0f;
|
||||
mk_y = mk_data >> 4;
|
||||
|
||||
/*
|
||||
* To avoid treating large finger as palm, let's reduce
|
||||
* the width x and y per trace.
|
||||
*/
|
||||
area_x = mk_x * (data->width_x - ETP_FWIDTH_REDUCE);
|
||||
area_y = mk_y * (data->width_y - ETP_FWIDTH_REDUCE);
|
||||
|
||||
input_report_abs(input, ABS_TOOL_WIDTH, mk_x);
|
||||
input_report_abs(input, ABS_MT_TOUCH_MAJOR,
|
||||
max(area_x, area_y));
|
||||
input_report_abs(input, ABS_MT_TOUCH_MINOR,
|
||||
min(area_x, area_y));
|
||||
}
|
||||
} else {
|
||||
input_mt_slot(input, contact_num);
|
||||
input_mt_report_slot_inactive(input);
|
||||
}
|
||||
}
|
||||
|
||||
static void elan_report_absolute(struct elan_tp_data *data, u8 *packet)
|
||||
static void elan_report_absolute(struct elan_tp_data *data, u8 *packet,
|
||||
bool high_precision)
|
||||
{
|
||||
struct input_dev *input = data->input;
|
||||
u8 *finger_data = &packet[ETP_FINGER_DATA_OFFSET];
|
||||
@@ -953,11 +1000,12 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet)
|
||||
|
||||
pm_wakeup_event(&data->client->dev, 0);
|
||||
|
||||
hover_event = hover_info & 0x40;
|
||||
for (i = 0; i < ETP_MAX_FINGERS; i++) {
|
||||
contact_valid = tp_info & (1U << (3 + i));
|
||||
elan_report_contact(data, i, contact_valid, finger_data);
|
||||
hover_event = hover_info & BIT(6);
|
||||
|
||||
for (i = 0; i < ETP_MAX_FINGERS; i++) {
|
||||
contact_valid = tp_info & BIT(3 + i);
|
||||
elan_report_contact(data, i, contact_valid, high_precision,
|
||||
packet, finger_data);
|
||||
if (contact_valid)
|
||||
finger_data += ETP_FINGER_DATA_LEN;
|
||||
}
|
||||
@@ -1015,13 +1063,16 @@ static irqreturn_t elan_isr(int irq, void *dev_id)
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = data->ops->get_report(data->client, report);
|
||||
error = data->ops->get_report(data->client, report, data->report_len);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
switch (report[ETP_REPORT_ID_OFFSET]) {
|
||||
case ETP_REPORT_ID:
|
||||
elan_report_absolute(data, report);
|
||||
elan_report_absolute(data, report, false);
|
||||
break;
|
||||
case ETP_REPORT_ID2:
|
||||
elan_report_absolute(data, report, true);
|
||||
break;
|
||||
case ETP_TP_REPORT_ID:
|
||||
elan_report_trackpoint(data, report);
|
||||
@@ -1112,7 +1163,9 @@ static int elan_setup_input_device(struct elan_tp_data *data)
|
||||
input_abs_set_res(input, ABS_X, data->x_res);
|
||||
input_abs_set_res(input, ABS_Y, data->y_res);
|
||||
input_set_abs_params(input, ABS_PRESSURE, 0, ETP_MAX_PRESSURE, 0, 0);
|
||||
input_set_abs_params(input, ABS_TOOL_WIDTH, 0, ETP_FINGER_WIDTH, 0, 0);
|
||||
if (data->report_features & ETP_FEATURE_REPORT_MK)
|
||||
input_set_abs_params(input, ABS_TOOL_WIDTH,
|
||||
0, ETP_FINGER_WIDTH, 0, 0);
|
||||
input_set_abs_params(input, ABS_DISTANCE, 0, 1, 0, 0);
|
||||
|
||||
/* And MT parameters */
|
||||
@@ -1122,10 +1175,12 @@ static int elan_setup_input_device(struct elan_tp_data *data)
|
||||
input_abs_set_res(input, ABS_MT_POSITION_Y, data->y_res);
|
||||
input_set_abs_params(input, ABS_MT_PRESSURE, 0,
|
||||
ETP_MAX_PRESSURE, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0,
|
||||
ETP_FINGER_WIDTH * max_width, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0,
|
||||
ETP_FINGER_WIDTH * min_width, 0, 0);
|
||||
if (data->report_features & ETP_FEATURE_REPORT_MK) {
|
||||
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR,
|
||||
0, ETP_FINGER_WIDTH * max_width, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_TOUCH_MINOR,
|
||||
0, ETP_FINGER_WIDTH * min_width, 0, 0);
|
||||
}
|
||||
|
||||
data->input = input;
|
||||
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
@@ -43,6 +44,8 @@
|
||||
#define ETP_I2C_RESOLUTION_CMD 0x0108
|
||||
#define ETP_I2C_PRESSURE_CMD 0x010A
|
||||
#define ETP_I2C_IAP_VERSION_CMD 0x0110
|
||||
#define ETP_I2C_IC_TYPE_P0_CMD 0x0110
|
||||
#define ETP_I2C_IAP_VERSION_P0_CMD 0x0111
|
||||
#define ETP_I2C_SET_CMD 0x0300
|
||||
#define ETP_I2C_POWER_CMD 0x0307
|
||||
#define ETP_I2C_FW_CHECKSUM_CMD 0x030F
|
||||
@@ -53,8 +56,12 @@
|
||||
#define ETP_I2C_CALIBRATE_CMD 0x0316
|
||||
#define ETP_I2C_MAX_BASELINE_CMD 0x0317
|
||||
#define ETP_I2C_MIN_BASELINE_CMD 0x0318
|
||||
#define ETP_I2C_IAP_TYPE_REG 0x0040
|
||||
#define ETP_I2C_IAP_TYPE_CMD 0x0304
|
||||
|
||||
#define ETP_I2C_REPORT_LEN 34
|
||||
#define ETP_I2C_REPORT_LEN_ID2 39
|
||||
#define ETP_I2C_REPORT_MAX_LEN 39
|
||||
#define ETP_I2C_DESC_LENGTH 30
|
||||
#define ETP_I2C_REPORT_DESC_LENGTH 158
|
||||
#define ETP_I2C_INF_LENGTH 2
|
||||
@@ -249,56 +256,52 @@ static int elan_i2c_get_pattern(struct i2c_client *client, u8 *pattern)
|
||||
dev_err(&client->dev, "failed to get pattern: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
*pattern = val[1];
|
||||
|
||||
/*
|
||||
* Not all versions of firmware implement "get pattern" command.
|
||||
* When this command is not implemented the device will respond
|
||||
* with 0xFF 0xFF, which we will treat as "old" pattern 0.
|
||||
*/
|
||||
*pattern = val[0] == 0xFF && val[1] == 0xFF ? 0 : val[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int elan_i2c_get_version(struct i2c_client *client,
|
||||
bool iap, u8 *version)
|
||||
u8 pattern, bool iap, u8 *version)
|
||||
{
|
||||
int error;
|
||||
u8 pattern_ver;
|
||||
u16 cmd;
|
||||
u8 val[3];
|
||||
|
||||
error = elan_i2c_get_pattern(client, &pattern_ver);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "failed to get pattern version\n");
|
||||
return error;
|
||||
}
|
||||
if (!iap)
|
||||
cmd = ETP_I2C_FW_VERSION_CMD;
|
||||
else if (pattern == 0)
|
||||
cmd = ETP_I2C_IAP_VERSION_P0_CMD;
|
||||
else
|
||||
cmd = ETP_I2C_IAP_VERSION_CMD;
|
||||
|
||||
error = elan_i2c_read_cmd(client,
|
||||
iap ? ETP_I2C_IAP_VERSION_CMD :
|
||||
ETP_I2C_FW_VERSION_CMD,
|
||||
val);
|
||||
error = elan_i2c_read_cmd(client, cmd, val);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "failed to get %s version: %d\n",
|
||||
iap ? "IAP" : "FW", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
if (pattern_ver == 0x01)
|
||||
if (pattern >= 0x01)
|
||||
*version = iap ? val[1] : val[0];
|
||||
else
|
||||
*version = val[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int elan_i2c_get_sm_version(struct i2c_client *client,
|
||||
u16 *ic_type, u8 *version,
|
||||
u8 *clickpad)
|
||||
static int elan_i2c_get_sm_version(struct i2c_client *client, u8 pattern,
|
||||
u16 *ic_type, u8 *version, u8 *clickpad)
|
||||
{
|
||||
int error;
|
||||
u8 pattern_ver;
|
||||
u8 val[3];
|
||||
|
||||
error = elan_i2c_get_pattern(client, &pattern_ver);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "failed to get pattern version\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
if (pattern_ver == 0x01) {
|
||||
if (pattern >= 0x01) {
|
||||
error = elan_i2c_read_cmd(client, ETP_I2C_IC_TYPE_CMD, val);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "failed to get ic type: %d\n",
|
||||
@@ -324,7 +327,14 @@ static int elan_i2c_get_sm_version(struct i2c_client *client,
|
||||
return error;
|
||||
}
|
||||
*version = val[0];
|
||||
*ic_type = val[1];
|
||||
|
||||
error = elan_i2c_read_cmd(client, ETP_I2C_IC_TYPE_P0_CMD, val);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "failed to get ic type: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
*ic_type = val[0];
|
||||
|
||||
error = elan_i2c_read_cmd(client, ETP_I2C_NSM_VERSION_CMD,
|
||||
val);
|
||||
@@ -386,7 +396,7 @@ static int elan_i2c_get_max(struct i2c_client *client,
|
||||
return error;
|
||||
}
|
||||
|
||||
*max_x = le16_to_cpup((__le16 *)val) & 0x0fff;
|
||||
*max_x = le16_to_cpup((__le16 *)val);
|
||||
|
||||
error = elan_i2c_read_cmd(client, ETP_I2C_MAX_Y_AXIS_CMD, val);
|
||||
if (error) {
|
||||
@@ -394,7 +404,7 @@ static int elan_i2c_get_max(struct i2c_client *client,
|
||||
return error;
|
||||
}
|
||||
|
||||
*max_y = le16_to_cpup((__le16 *)val) & 0x0fff;
|
||||
*max_y = le16_to_cpup((__le16 *)val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -507,7 +517,43 @@ static int elan_i2c_set_flash_key(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int elan_i2c_prepare_fw_update(struct i2c_client *client)
|
||||
static int elan_read_write_iap_type(struct i2c_client *client)
|
||||
{
|
||||
int error;
|
||||
u16 constant;
|
||||
u8 val[3];
|
||||
int retry = 3;
|
||||
|
||||
do {
|
||||
error = elan_i2c_write_cmd(client, ETP_I2C_IAP_TYPE_CMD,
|
||||
ETP_I2C_IAP_TYPE_REG);
|
||||
if (error) {
|
||||
dev_err(&client->dev,
|
||||
"cannot write iap type: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = elan_i2c_read_cmd(client, ETP_I2C_IAP_TYPE_CMD, val);
|
||||
if (error) {
|
||||
dev_err(&client->dev,
|
||||
"failed to read iap type register: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
constant = le16_to_cpup((__le16 *)val);
|
||||
dev_dbg(&client->dev, "iap type reg: 0x%04x\n", constant);
|
||||
|
||||
if (constant == ETP_I2C_IAP_TYPE_REG)
|
||||
return 0;
|
||||
|
||||
} while (--retry > 0);
|
||||
|
||||
dev_err(&client->dev, "cannot set iap type\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int elan_i2c_prepare_fw_update(struct i2c_client *client, u16 ic_type,
|
||||
u8 iap_version)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
int error;
|
||||
@@ -547,6 +593,12 @@ static int elan_i2c_prepare_fw_update(struct i2c_client *client)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (ic_type >= 0x0D && iap_version >= 1) {
|
||||
error = elan_read_write_iap_type(client);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Set flash key again */
|
||||
error = elan_i2c_set_flash_key(client);
|
||||
if (error)
|
||||
@@ -572,57 +624,64 @@ static int elan_i2c_prepare_fw_update(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int elan_i2c_write_fw_block(struct i2c_client *client,
|
||||
static int elan_i2c_write_fw_block(struct i2c_client *client, u16 fw_page_size,
|
||||
const u8 *page, u16 checksum, int idx)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
u8 page_store[ETP_FW_PAGE_SIZE + 4];
|
||||
u8 *page_store;
|
||||
u8 val[3];
|
||||
u16 result;
|
||||
int ret, error;
|
||||
|
||||
page_store = kmalloc(fw_page_size + 4, GFP_KERNEL);
|
||||
if (!page_store)
|
||||
return -ENOMEM;
|
||||
|
||||
page_store[0] = ETP_I2C_IAP_REG_L;
|
||||
page_store[1] = ETP_I2C_IAP_REG_H;
|
||||
memcpy(&page_store[2], page, ETP_FW_PAGE_SIZE);
|
||||
memcpy(&page_store[2], page, fw_page_size);
|
||||
/* recode checksum at last two bytes */
|
||||
put_unaligned_le16(checksum, &page_store[ETP_FW_PAGE_SIZE + 2]);
|
||||
put_unaligned_le16(checksum, &page_store[fw_page_size + 2]);
|
||||
|
||||
ret = i2c_master_send(client, page_store, sizeof(page_store));
|
||||
if (ret != sizeof(page_store)) {
|
||||
ret = i2c_master_send(client, page_store, fw_page_size + 4);
|
||||
if (ret != fw_page_size + 4) {
|
||||
error = ret < 0 ? ret : -EIO;
|
||||
dev_err(dev, "Failed to write page %d: %d\n", idx, error);
|
||||
return error;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Wait for F/W to update one page ROM data. */
|
||||
msleep(35);
|
||||
msleep(fw_page_size == ETP_FW_PAGE_SIZE_512 ? 50 : 35);
|
||||
|
||||
error = elan_i2c_read_cmd(client, ETP_I2C_IAP_CTRL_CMD, val);
|
||||
if (error) {
|
||||
dev_err(dev, "Failed to read IAP write result: %d\n", error);
|
||||
return error;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
result = le16_to_cpup((__le16 *)val);
|
||||
if (result & (ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR)) {
|
||||
dev_err(dev, "IAP reports failed write: %04hx\n",
|
||||
result);
|
||||
return -EIO;
|
||||
error = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
exit:
|
||||
kfree(page_store);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int elan_i2c_finish_fw_update(struct i2c_client *client,
|
||||
struct completion *completion)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
int error;
|
||||
int error = 0;
|
||||
int len;
|
||||
u8 buffer[ETP_I2C_REPORT_LEN];
|
||||
u8 buffer[ETP_I2C_REPORT_MAX_LEN];
|
||||
|
||||
len = i2c_master_recv(client, buffer, ETP_I2C_REPORT_LEN);
|
||||
if (len != ETP_I2C_REPORT_LEN) {
|
||||
len = i2c_master_recv(client, buffer, ETP_I2C_REPORT_MAX_LEN);
|
||||
if (len <= 0) {
|
||||
error = len < 0 ? len : -EIO;
|
||||
dev_warn(dev, "failed to read I2C data after FW WDT reset: %d (%d)\n",
|
||||
error, len);
|
||||
@@ -656,20 +715,31 @@ static int elan_i2c_finish_fw_update(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int elan_i2c_get_report(struct i2c_client *client, u8 *report)
|
||||
static int elan_i2c_get_report_features(struct i2c_client *client, u8 pattern,
|
||||
unsigned int *features,
|
||||
unsigned int *report_len)
|
||||
{
|
||||
*features = ETP_FEATURE_REPORT_MK;
|
||||
*report_len = pattern <= 0x01 ?
|
||||
ETP_I2C_REPORT_LEN : ETP_I2C_REPORT_LEN_ID2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int elan_i2c_get_report(struct i2c_client *client,
|
||||
u8 *report, unsigned int report_len)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = i2c_master_recv(client, report, ETP_I2C_REPORT_LEN);
|
||||
len = i2c_master_recv(client, report, report_len);
|
||||
if (len < 0) {
|
||||
dev_err(&client->dev, "failed to read report data: %d\n", len);
|
||||
return len;
|
||||
}
|
||||
|
||||
if (len != ETP_I2C_REPORT_LEN) {
|
||||
if (len != report_len) {
|
||||
dev_err(&client->dev,
|
||||
"wrong report length (%d vs %d expected)\n",
|
||||
len, ETP_I2C_REPORT_LEN);
|
||||
len, report_len);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -706,5 +776,6 @@ const struct elan_transport_ops elan_i2c_ops = {
|
||||
|
||||
.get_pattern = elan_i2c_get_pattern,
|
||||
|
||||
.get_report_features = elan_i2c_get_report_features,
|
||||
.get_report = elan_i2c_get_report,
|
||||
};
|
||||
|
@@ -147,7 +147,7 @@ static int elan_smbus_get_baseline_data(struct i2c_client *client,
|
||||
}
|
||||
|
||||
static int elan_smbus_get_version(struct i2c_client *client,
|
||||
bool iap, u8 *version)
|
||||
u8 pattern, bool iap, u8 *version)
|
||||
{
|
||||
int error;
|
||||
u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
|
||||
@@ -166,9 +166,8 @@ static int elan_smbus_get_version(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int elan_smbus_get_sm_version(struct i2c_client *client,
|
||||
u16 *ic_type, u8 *version,
|
||||
u8 *clickpad)
|
||||
static int elan_smbus_get_sm_version(struct i2c_client *client, u8 pattern,
|
||||
u16 *ic_type, u8 *version, u8 *clickpad)
|
||||
{
|
||||
int error;
|
||||
u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
|
||||
@@ -340,7 +339,8 @@ static int elan_smbus_set_flash_key(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int elan_smbus_prepare_fw_update(struct i2c_client *client)
|
||||
static int elan_smbus_prepare_fw_update(struct i2c_client *client, u16 ic_type,
|
||||
u8 iap_version)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
int len;
|
||||
@@ -414,7 +414,7 @@ static int elan_smbus_prepare_fw_update(struct i2c_client *client)
|
||||
}
|
||||
|
||||
|
||||
static int elan_smbus_write_fw_block(struct i2c_client *client,
|
||||
static int elan_smbus_write_fw_block(struct i2c_client *client, u16 fw_page_size,
|
||||
const u8 *page, u16 checksum, int idx)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
@@ -429,7 +429,7 @@ static int elan_smbus_write_fw_block(struct i2c_client *client,
|
||||
*/
|
||||
error = i2c_smbus_write_block_data(client,
|
||||
ETP_SMBUS_WRITE_FW_BLOCK,
|
||||
ETP_FW_PAGE_SIZE / 2,
|
||||
fw_page_size / 2,
|
||||
page);
|
||||
if (error) {
|
||||
dev_err(dev, "Failed to write page %d (part %d): %d\n",
|
||||
@@ -439,8 +439,8 @@ static int elan_smbus_write_fw_block(struct i2c_client *client,
|
||||
|
||||
error = i2c_smbus_write_block_data(client,
|
||||
ETP_SMBUS_WRITE_FW_BLOCK,
|
||||
ETP_FW_PAGE_SIZE / 2,
|
||||
page + ETP_FW_PAGE_SIZE / 2);
|
||||
fw_page_size / 2,
|
||||
page + fw_page_size / 2);
|
||||
if (error) {
|
||||
dev_err(dev, "Failed to write page %d (part %d): %d\n",
|
||||
idx, 2, error);
|
||||
@@ -469,7 +469,21 @@ static int elan_smbus_write_fw_block(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int elan_smbus_get_report(struct i2c_client *client, u8 *report)
|
||||
static int elan_smbus_get_report_features(struct i2c_client *client, u8 pattern,
|
||||
unsigned int *features,
|
||||
unsigned int *report_len)
|
||||
{
|
||||
/*
|
||||
* SMBus controllers with pattern 2 lack area info, as newer
|
||||
* high-precision packets use that space for coordinates.
|
||||
*/
|
||||
*features = pattern <= 0x01 ? ETP_FEATURE_REPORT_MK : 0;
|
||||
*report_len = ETP_SMBUS_REPORT_LEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int elan_smbus_get_report(struct i2c_client *client,
|
||||
u8 *report, unsigned int report_len)
|
||||
{
|
||||
int len;
|
||||
|
||||
@@ -534,6 +548,7 @@ const struct elan_transport_ops elan_smbus_ops = {
|
||||
.write_fw_block = elan_smbus_write_fw_block,
|
||||
.finish_fw_update = elan_smbus_finish_fw_update,
|
||||
|
||||
.get_report_features = elan_smbus_get_report_features,
|
||||
.get_report = elan_smbus_get_report,
|
||||
.get_pattern = elan_smbus_get_pattern,
|
||||
};
|
||||
|
@@ -383,7 +383,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
|
||||
*/
|
||||
if (packet[3] & 0x80)
|
||||
fingers = 4;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 1:
|
||||
/*
|
||||
* byte 1: . . . . x11 x10 x9 x8
|
||||
@@ -1146,7 +1146,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
|
||||
case 2:
|
||||
__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
|
||||
__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 3:
|
||||
if (info->hw_version == 3)
|
||||
elantech_set_buttonpad_prop(psmouse);
|
||||
@@ -1877,12 +1877,10 @@ static bool elantech_use_host_notify(struct psmouse *psmouse,
|
||||
/* expected case */
|
||||
break;
|
||||
case ETP_BUS_SMB_ALERT_ONLY:
|
||||
/* fall-through */
|
||||
case ETP_BUS_PS2_SMB_ALERT:
|
||||
psmouse_dbg(psmouse, "Ignoring SMBus provider through alert protocol.\n");
|
||||
break;
|
||||
case ETP_BUS_SMB_HST_NTFY_ONLY:
|
||||
/* fall-through */
|
||||
case ETP_BUS_PS2_SMB_HST_NTFY:
|
||||
return true;
|
||||
default:
|
||||
@@ -1897,7 +1895,7 @@ static bool elantech_use_host_notify(struct psmouse *psmouse,
|
||||
int elantech_init_smbus(struct psmouse *psmouse)
|
||||
{
|
||||
struct elantech_device_info info;
|
||||
int error = -EINVAL;
|
||||
int error;
|
||||
|
||||
psmouse_reset(psmouse);
|
||||
|
||||
@@ -2015,7 +2013,7 @@ static int elantech_setup_ps2(struct psmouse *psmouse,
|
||||
int elantech_init_ps2(struct psmouse *psmouse)
|
||||
{
|
||||
struct elantech_device_info info;
|
||||
int error = -EINVAL;
|
||||
int error;
|
||||
|
||||
psmouse_reset(psmouse);
|
||||
|
||||
@@ -2036,7 +2034,7 @@ int elantech_init_ps2(struct psmouse *psmouse)
|
||||
int elantech_init(struct psmouse *psmouse)
|
||||
{
|
||||
struct elantech_device_info info;
|
||||
int error = -EINVAL;
|
||||
int error;
|
||||
|
||||
psmouse_reset(psmouse);
|
||||
|
||||
|
@@ -238,7 +238,7 @@ static void hgpk_spewing_hack(struct psmouse *psmouse,
|
||||
/* we're not spewing, but this packet might be the start */
|
||||
priv->spew_flag = MAYBE_SPEWING;
|
||||
|
||||
/* fall-through */
|
||||
fallthrough;
|
||||
|
||||
case MAYBE_SPEWING:
|
||||
priv->spew_count++;
|
||||
@@ -249,7 +249,7 @@ static void hgpk_spewing_hack(struct psmouse *psmouse,
|
||||
/* excessive spew detected, request recalibration */
|
||||
priv->spew_flag = SPEW_DETECTED;
|
||||
|
||||
/* fall-through */
|
||||
fallthrough;
|
||||
|
||||
case SPEW_DETECTED:
|
||||
/* only recalibrate when the overall delta to the cursor
|
||||
|
@@ -105,7 +105,7 @@ static void navpoint_packet(struct navpoint *navpoint)
|
||||
case 0x19: /* Module 0, Hello packet */
|
||||
if ((navpoint->data[1] & 0xf0) == 0x10)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
fallthrough;
|
||||
default:
|
||||
dev_warn(navpoint->dev,
|
||||
"spurious packet: data=0x%02x,0x%02x,...\n",
|
||||
|
@@ -2042,7 +2042,7 @@ static int psmouse_get_maxproto(char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
int type = *((unsigned int *)kp->arg);
|
||||
|
||||
return sprintf(buffer, "%s", psmouse_protocol_by_type(type)->name);
|
||||
return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name);
|
||||
}
|
||||
|
||||
static int __init psmouse_init(void)
|
||||
|
@@ -441,7 +441,7 @@ static ssize_t fsp_attr_set_setreg(struct psmouse *psmouse, void *data,
|
||||
|
||||
fsp_reg_write_enable(psmouse, false);
|
||||
|
||||
return count;
|
||||
return retval;
|
||||
}
|
||||
|
||||
PSMOUSE_DEFINE_WO_ATTR(setreg, S_IWUSR, NULL, fsp_attr_set_setreg);
|
||||
@@ -794,7 +794,7 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
|
||||
/* on-pad click, filter it if necessary */
|
||||
if ((ad->flags & FSPDRV_FLAG_EN_OPC) != FSPDRV_FLAG_EN_OPC)
|
||||
packet[0] &= ~FSP_PB0_LBTN;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case FSP_PKT_TYPE_NORMAL:
|
||||
/* normal packet */
|
||||
|
@@ -128,7 +128,7 @@ static void sermouse_process_ms(struct sermouse *sermouse, signed char data)
|
||||
|
||||
case SERIO_MS:
|
||||
sermouse->type = SERIO_MP;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case SERIO_MP:
|
||||
if ((data >> 2) & 3) break; /* M++ Wireless Extension packet. */
|
||||
@@ -139,7 +139,7 @@ static void sermouse_process_ms(struct sermouse *sermouse, signed char data)
|
||||
case SERIO_MZP:
|
||||
case SERIO_MZPP:
|
||||
input_report_key(dev, BTN_SIDE, (data >> 5) & 1);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case SERIO_MZ:
|
||||
input_report_key(dev, BTN_MIDDLE, (data >> 4) & 1);
|
||||
|
@@ -562,7 +562,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
|
||||
str = last_str;
|
||||
break;
|
||||
}
|
||||
/* fall through - report timeout */
|
||||
fallthrough; /* report timeout */
|
||||
case 0xfc:
|
||||
case 0xfd:
|
||||
case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break;
|
||||
|
@@ -418,7 +418,7 @@ bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data)
|
||||
ps2dev->nak = 0;
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
fallthrough;
|
||||
default:
|
||||
/*
|
||||
* Do not signal errors if we get unexpected reply while
|
||||
|
@@ -247,7 +247,7 @@ void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *k
|
||||
|
||||
case KE_SW:
|
||||
value = ke->sw.value;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case KE_VSW:
|
||||
input_report_switch(dev, ke->sw.code, value);
|
||||
|
@@ -676,8 +676,8 @@ static void gtco_urb_callback(struct urb *urbinfo)
|
||||
|
||||
/* Mask out the Y tilt value used for pressure */
|
||||
device->buffer[7] = (u8)((device->buffer[7]) & 0x7F);
|
||||
fallthrough;
|
||||
|
||||
/* Fall thru */
|
||||
case 4:
|
||||
/* Tilt */
|
||||
input_report_abs(inputdev, ABS_TILT_X,
|
||||
@@ -685,8 +685,8 @@ static void gtco_urb_callback(struct urb *urbinfo)
|
||||
|
||||
input_report_abs(inputdev, ABS_TILT_Y,
|
||||
sign_extend32(device->buffer[7], 6));
|
||||
fallthrough;
|
||||
|
||||
/* Fall thru */
|
||||
case 2:
|
||||
case 3:
|
||||
/* Convert buttons, only 5 bits possible */
|
||||
@@ -695,8 +695,8 @@ static void gtco_urb_callback(struct urb *urbinfo)
|
||||
/* We don't apply any meaning to the bitmask,
|
||||
just report */
|
||||
input_event(inputdev, EV_MSC, MSC_SERIAL, val);
|
||||
fallthrough;
|
||||
|
||||
/* Fall thru */
|
||||
case 1:
|
||||
/* All reports have X and Y coords in the same place */
|
||||
val = get_unaligned_le16(&device->buffer[1]);
|
||||
|
@@ -146,7 +146,7 @@ static void pegasus_parse_packet(struct pegasus *pegasus)
|
||||
/* xy data */
|
||||
case BATTERY_LOW:
|
||||
dev_warn_once(&dev->dev, "Pen battery low\n");
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case BATTERY_NO_REPORT:
|
||||
case BATTERY_GOOD:
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user