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:
Greg Kroah-Hartman
2020-08-11 10:57:46 +02:00
307 changed files with 7861 additions and 2118 deletions

View 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

View File

@@ -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

View File

@@ -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;
};
};

View File

@@ -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;
};

View File

@@ -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:

View File

@@ -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);

View File

@@ -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``)

View File

@@ -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);

View 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 */

View File

@@ -95,6 +95,7 @@
#include <asm/iosapic.h>
#include <asm/processor.h>
#include <asm/ptrace.h>
#include <asm/xtp.h>
#undef DEBUG_INTERRUPT_ROUTING

View File

@@ -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'.

View File

@@ -47,6 +47,7 @@
#include <linux/uaccess.h>
#include <asm/unwind.h>
#include <asm/user.h>
#include <asm/xtp.h>
#include "entry.h"

View File

@@ -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;

View File

@@ -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!"

View File

@@ -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

View File

@@ -7,6 +7,7 @@
#ifndef _ASMPARISC_TIMEX_H
#define _ASMPARISC_TIMEX_H
#include <asm/special_insns.h>
#define CLOCK_TICK_RATE 1193180 /* Underlying HZ */

View File

@@ -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>

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -6,6 +6,7 @@
#define _ASM_X86_TSC_H
#include <asm/processor.h>
#include <asm/cpufeature.h>
/*
* Standard way to access the cycle counter.

View File

@@ -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>

View File

@@ -10,6 +10,7 @@
* like self-ipi, etc...
*/
#include <linux/cpumask.h>
#include <linux/thread_info.h>
#include <asm/apic.h>

View File

@@ -9,6 +9,7 @@
#include <linux/smp.h>
#include <asm/apic.h>
#include <asm/io_apic.h>
#include "local.h"

View File

@@ -9,6 +9,7 @@
* Bits copied from original nmi.c file
*
*/
#include <linux/thread_info.h>
#include <asm/apic.h>
#include <asm/nmi.h>

View File

@@ -2,6 +2,7 @@
#include <linux/cpumask.h>
#include <linux/smp.h>
#include <asm/io_apic.h>
#include "local.h"

View File

@@ -10,6 +10,7 @@
#include <linux/jump_label.h>
#include <asm/irq_vectors.h>
#include <asm/apic.h>
/* APIC flat 64 */

View File

@@ -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>

View File

@@ -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"

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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);

View File

@@ -7,6 +7,7 @@
*/
#include <linux/kernel.h>
#include <linux/thread_info.h>
#include <asm/apic.h>
#include <asm/cpu_device_id.h>

View File

@@ -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"

View File

@@ -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>

View File

@@ -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>

View File

@@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/thread_info.h>
#include <asm/smp.h>
#include <xen/events.h>

View File

@@ -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>

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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.

View File

@@ -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
*/

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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) },
{ }
};

View File

@@ -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>

View File

@@ -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 }
};

View File

@@ -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
*/

View File

@@ -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 = {

View File

@@ -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);

View File

@@ -162,6 +162,8 @@ struct wiimote_data {
struct work_struct init_worker;
};
extern bool wiimote_dpad_as_analog;
/* wiimote modules */
enum wiimod_module {

View File

@@ -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);
}

View File

@@ -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)

View File

@@ -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 */

View File

@@ -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);
}
}

View File

@@ -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:

View File

@@ -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 */

View File

@@ -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)

View File

@@ -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);

View File

@@ -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;

View File

@@ -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)

View File

@@ -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

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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)

View File

@@ -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,

View File

@@ -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;

View File

@@ -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;

View File

@@ -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))

View File

@@ -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:

View File

@@ -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

View File

@@ -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:
/*

View File

@@ -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:
/*

View File

@@ -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);

View File

@@ -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;

View File

@@ -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,
};

View File

@@ -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,
};

View File

@@ -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);

View File

@@ -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

View File

@@ -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",

View File

@@ -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)

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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;

View File

@@ -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

View File

@@ -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);

View File

@@ -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]);

View File

@@ -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