2968 lines
100 KiB
Diff
2968 lines
100 KiB
Diff
diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt
|
|
index 35e17f748ca7..af5859b2d0f9 100644
|
|
--- a/Documentation/sysctl/fs.txt
|
|
+++ b/Documentation/sysctl/fs.txt
|
|
@@ -34,7 +34,9 @@ Currently, these files are in /proc/sys/fs:
|
|
- overflowgid
|
|
- pipe-user-pages-hard
|
|
- pipe-user-pages-soft
|
|
+- protected_fifos
|
|
- protected_hardlinks
|
|
+- protected_regular
|
|
- protected_symlinks
|
|
- suid_dumpable
|
|
- super-max
|
|
@@ -182,6 +184,24 @@ applied.
|
|
|
|
==============================================================
|
|
|
|
+protected_fifos:
|
|
+
|
|
+The intent of this protection is to avoid unintentional writes to
|
|
+an attacker-controlled FIFO, where a program expected to create a regular
|
|
+file.
|
|
+
|
|
+When set to "0", writing to FIFOs is unrestricted.
|
|
+
|
|
+When set to "1" don't allow O_CREAT open on FIFOs that we don't own
|
|
+in world writable sticky directories, unless they are owned by the
|
|
+owner of the directory.
|
|
+
|
|
+When set to "2" it also applies to group writable sticky directories.
|
|
+
|
|
+This protection is based on the restrictions in Openwall.
|
|
+
|
|
+==============================================================
|
|
+
|
|
protected_hardlinks:
|
|
|
|
A long-standing class of security issues is the hardlink-based
|
|
@@ -202,6 +222,22 @@ This protection is based on the restrictions in Openwall and grsecurity.
|
|
|
|
==============================================================
|
|
|
|
+protected_regular:
|
|
+
|
|
+This protection is similar to protected_fifos, but it
|
|
+avoids writes to an attacker-controlled regular file, where a program
|
|
+expected to create one.
|
|
+
|
|
+When set to "0", writing to regular files is unrestricted.
|
|
+
|
|
+When set to "1" don't allow O_CREAT open on regular files that we
|
|
+don't own in world writable sticky directories, unless they are
|
|
+owned by the owner of the directory.
|
|
+
|
|
+When set to "2" it also applies to group writable sticky directories.
|
|
+
|
|
+==============================================================
|
|
+
|
|
protected_symlinks:
|
|
|
|
A long-standing class of security issues is the symlink-based
|
|
diff --git a/MAINTAINERS b/MAINTAINERS
|
|
index ab65bbecb159..f4d4a5544dc1 100644
|
|
--- a/MAINTAINERS
|
|
+++ b/MAINTAINERS
|
|
@@ -10135,6 +10135,7 @@ F: arch/alpha/kernel/srm_env.c
|
|
|
|
STABLE BRANCH
|
|
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
+M: Sasha Levin <sashal@kernel.org>
|
|
L: stable@vger.kernel.org
|
|
S: Supported
|
|
F: Documentation/stable_kernel_rules.txt
|
|
diff --git a/Makefile b/Makefile
|
|
index 441a760dc5a4..64521458d35e 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,6 +1,6 @@
|
|
VERSION = 4
|
|
PATCHLEVEL = 4
|
|
-SUBLEVEL = 165
|
|
+SUBLEVEL = 166
|
|
EXTRAVERSION =
|
|
NAME = Blurry Fish Butt
|
|
|
|
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
|
|
index c10bb98144b0..fb4ac87fc398 100644
|
|
--- a/arch/arm64/Makefile
|
|
+++ b/arch/arm64/Makefile
|
|
@@ -10,7 +10,7 @@
|
|
#
|
|
# Copyright (C) 1995-2001 by Russell King
|
|
|
|
-LDFLAGS_vmlinux :=-p --no-undefined -X
|
|
+LDFLAGS_vmlinux :=--no-undefined -X
|
|
CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET)
|
|
OBJCOPYFLAGS :=-O binary -R .note -R .note.gnu.build-id -R .comment -S
|
|
GZFLAGS :=-9
|
|
diff --git a/arch/powerpc/kvm/trace.h b/arch/powerpc/kvm/trace.h
|
|
index 2e0e67ef3544..e8cedf32345a 100644
|
|
--- a/arch/powerpc/kvm/trace.h
|
|
+++ b/arch/powerpc/kvm/trace.h
|
|
@@ -5,8 +5,6 @@
|
|
|
|
#undef TRACE_SYSTEM
|
|
#define TRACE_SYSTEM kvm
|
|
-#define TRACE_INCLUDE_PATH .
|
|
-#define TRACE_INCLUDE_FILE trace
|
|
|
|
/*
|
|
* Tracepoint for guest mode entry.
|
|
@@ -119,4 +117,10 @@ TRACE_EVENT(kvm_check_requests,
|
|
#endif /* _TRACE_KVM_H */
|
|
|
|
/* This part must be outside protection */
|
|
+#undef TRACE_INCLUDE_PATH
|
|
+#undef TRACE_INCLUDE_FILE
|
|
+
|
|
+#define TRACE_INCLUDE_PATH .
|
|
+#define TRACE_INCLUDE_FILE trace
|
|
+
|
|
#include <trace/define_trace.h>
|
|
diff --git a/arch/powerpc/kvm/trace_booke.h b/arch/powerpc/kvm/trace_booke.h
|
|
index 7ec534d1db9f..7eadbf449a1f 100644
|
|
--- a/arch/powerpc/kvm/trace_booke.h
|
|
+++ b/arch/powerpc/kvm/trace_booke.h
|
|
@@ -5,8 +5,6 @@
|
|
|
|
#undef TRACE_SYSTEM
|
|
#define TRACE_SYSTEM kvm_booke
|
|
-#define TRACE_INCLUDE_PATH .
|
|
-#define TRACE_INCLUDE_FILE trace_booke
|
|
|
|
#define kvm_trace_symbol_exit \
|
|
{0, "CRITICAL"}, \
|
|
@@ -217,4 +215,11 @@ TRACE_EVENT(kvm_booke_queue_irqprio,
|
|
#endif
|
|
|
|
/* This part must be outside protection */
|
|
+
|
|
+#undef TRACE_INCLUDE_PATH
|
|
+#undef TRACE_INCLUDE_FILE
|
|
+
|
|
+#define TRACE_INCLUDE_PATH .
|
|
+#define TRACE_INCLUDE_FILE trace_booke
|
|
+
|
|
#include <trace/define_trace.h>
|
|
diff --git a/arch/powerpc/kvm/trace_hv.h b/arch/powerpc/kvm/trace_hv.h
|
|
index 33d9daff5783..d1bfe017d751 100644
|
|
--- a/arch/powerpc/kvm/trace_hv.h
|
|
+++ b/arch/powerpc/kvm/trace_hv.h
|
|
@@ -8,8 +8,6 @@
|
|
|
|
#undef TRACE_SYSTEM
|
|
#define TRACE_SYSTEM kvm_hv
|
|
-#define TRACE_INCLUDE_PATH .
|
|
-#define TRACE_INCLUDE_FILE trace_hv
|
|
|
|
#define kvm_trace_symbol_hcall \
|
|
{H_REMOVE, "H_REMOVE"}, \
|
|
@@ -474,4 +472,11 @@ TRACE_EVENT(kvmppc_run_vcpu_exit,
|
|
#endif /* _TRACE_KVM_HV_H */
|
|
|
|
/* This part must be outside protection */
|
|
+
|
|
+#undef TRACE_INCLUDE_PATH
|
|
+#undef TRACE_INCLUDE_FILE
|
|
+
|
|
+#define TRACE_INCLUDE_PATH .
|
|
+#define TRACE_INCLUDE_FILE trace_hv
|
|
+
|
|
#include <trace/define_trace.h>
|
|
diff --git a/arch/powerpc/kvm/trace_pr.h b/arch/powerpc/kvm/trace_pr.h
|
|
index 810507cb688a..1e40aa2aa5af 100644
|
|
--- a/arch/powerpc/kvm/trace_pr.h
|
|
+++ b/arch/powerpc/kvm/trace_pr.h
|
|
@@ -7,8 +7,6 @@
|
|
|
|
#undef TRACE_SYSTEM
|
|
#define TRACE_SYSTEM kvm_pr
|
|
-#define TRACE_INCLUDE_PATH .
|
|
-#define TRACE_INCLUDE_FILE trace_pr
|
|
|
|
TRACE_EVENT(kvm_book3s_reenter,
|
|
TP_PROTO(int r, struct kvm_vcpu *vcpu),
|
|
@@ -271,4 +269,11 @@ TRACE_EVENT(kvm_unmap_hva,
|
|
#endif /* _TRACE_KVM_H */
|
|
|
|
/* This part must be outside protection */
|
|
+
|
|
+#undef TRACE_INCLUDE_PATH
|
|
+#undef TRACE_INCLUDE_FILE
|
|
+
|
|
+#define TRACE_INCLUDE_PATH .
|
|
+#define TRACE_INCLUDE_FILE trace_pr
|
|
+
|
|
#include <trace/define_trace.h>
|
|
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
|
|
index 3c4faa4c2742..bb3df222ae71 100644
|
|
--- a/arch/powerpc/mm/numa.c
|
|
+++ b/arch/powerpc/mm/numa.c
|
|
@@ -1319,7 +1319,7 @@ static long vphn_get_associativity(unsigned long cpu,
|
|
|
|
switch (rc) {
|
|
case H_FUNCTION:
|
|
- printk(KERN_INFO
|
|
+ printk_once(KERN_INFO
|
|
"VPHN is not supported. Disabling polling...\n");
|
|
stop_topology_update();
|
|
break;
|
|
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
|
|
index 05ae254f84cf..1866b6a5171a 100644
|
|
--- a/arch/s390/mm/pgtable.c
|
|
+++ b/arch/s390/mm/pgtable.c
|
|
@@ -637,6 +637,8 @@ void gmap_discard(struct gmap *gmap, unsigned long from, unsigned long to)
|
|
vmaddr |= gaddr & ~PMD_MASK;
|
|
/* Find vma in the parent mm */
|
|
vma = find_vma(gmap->mm, vmaddr);
|
|
+ if (!vma)
|
|
+ continue;
|
|
size = min(to - gaddr, PMD_SIZE - (gaddr & ~PMD_MASK));
|
|
zap_page_range(vma, vmaddr, size, NULL);
|
|
}
|
|
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
|
|
index 8be48b1d7596..375ed605c83d 100644
|
|
--- a/arch/x86/entry/entry_64.S
|
|
+++ b/arch/x86/entry/entry_64.S
|
|
@@ -856,7 +856,7 @@ ENTRY(\sym)
|
|
|
|
call \do_sym
|
|
|
|
- jmp error_exit /* %ebx: no swapgs flag */
|
|
+ jmp error_exit
|
|
.endif
|
|
END(\sym)
|
|
.endm
|
|
@@ -1118,7 +1118,6 @@ END(paranoid_exit)
|
|
|
|
/*
|
|
* Save all registers in pt_regs, and switch gs if needed.
|
|
- * Return: EBX=0: came from user mode; EBX=1: otherwise
|
|
*/
|
|
ENTRY(error_entry)
|
|
cld
|
|
@@ -1131,7 +1130,6 @@ ENTRY(error_entry)
|
|
* the kernel CR3 here.
|
|
*/
|
|
SWITCH_KERNEL_CR3
|
|
- xorl %ebx, %ebx
|
|
testb $3, CS+8(%rsp)
|
|
jz .Lerror_kernelspace
|
|
|
|
@@ -1165,7 +1163,6 @@ ENTRY(error_entry)
|
|
* for these here too.
|
|
*/
|
|
.Lerror_kernelspace:
|
|
- incl %ebx
|
|
leaq native_irq_return_iret(%rip), %rcx
|
|
cmpq %rcx, RIP+8(%rsp)
|
|
je .Lerror_bad_iret
|
|
@@ -1196,28 +1193,19 @@ ENTRY(error_entry)
|
|
|
|
/*
|
|
* Pretend that the exception came from user mode: set up pt_regs
|
|
- * as if we faulted immediately after IRET and clear EBX so that
|
|
- * error_exit knows that we will be returning to user mode.
|
|
+ * as if we faulted immediately after IRET.
|
|
*/
|
|
mov %rsp, %rdi
|
|
call fixup_bad_iret
|
|
mov %rax, %rsp
|
|
- decl %ebx
|
|
jmp .Lerror_entry_from_usermode_after_swapgs
|
|
END(error_entry)
|
|
|
|
-
|
|
-/*
|
|
- * On entry, EBS is a "return to kernel mode" flag:
|
|
- * 1: already in kernel mode, don't need SWAPGS
|
|
- * 0: user gsbase is loaded, we need SWAPGS and standard preparation for return to usermode
|
|
- */
|
|
ENTRY(error_exit)
|
|
- movl %ebx, %eax
|
|
DISABLE_INTERRUPTS(CLBR_NONE)
|
|
TRACE_IRQS_OFF
|
|
- testl %eax, %eax
|
|
- jnz retint_kernel
|
|
+ testb $3, CS(%rsp)
|
|
+ jz retint_kernel
|
|
jmp retint_user
|
|
END(error_exit)
|
|
|
|
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
|
|
index ef1fa8145419..fa86946d12aa 100644
|
|
--- a/drivers/cpufreq/imx6q-cpufreq.c
|
|
+++ b/drivers/cpufreq/imx6q-cpufreq.c
|
|
@@ -130,8 +130,13 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
|
|
/* Ensure the arm clock divider is what we expect */
|
|
ret = clk_set_rate(arm_clk, new_freq * 1000);
|
|
if (ret) {
|
|
+ int ret1;
|
|
+
|
|
dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
|
|
- regulator_set_voltage_tol(arm_reg, volt_old, 0);
|
|
+ ret1 = regulator_set_voltage_tol(arm_reg, volt_old, 0);
|
|
+ if (ret1)
|
|
+ dev_warn(cpu_dev,
|
|
+ "failed to restore vddarm voltage: %d\n", ret1);
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c
|
|
index 9a32d9dfdd26..011700262824 100644
|
|
--- a/drivers/gpu/drm/ast/ast_drv.c
|
|
+++ b/drivers/gpu/drm/ast/ast_drv.c
|
|
@@ -60,8 +60,29 @@ static const struct pci_device_id pciidlist[] = {
|
|
|
|
MODULE_DEVICE_TABLE(pci, pciidlist);
|
|
|
|
+static void ast_kick_out_firmware_fb(struct pci_dev *pdev)
|
|
+{
|
|
+ struct apertures_struct *ap;
|
|
+ bool primary = false;
|
|
+
|
|
+ ap = alloc_apertures(1);
|
|
+ if (!ap)
|
|
+ return;
|
|
+
|
|
+ ap->ranges[0].base = pci_resource_start(pdev, 0);
|
|
+ ap->ranges[0].size = pci_resource_len(pdev, 0);
|
|
+
|
|
+#ifdef CONFIG_X86
|
|
+ primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
|
|
+#endif
|
|
+ remove_conflicting_framebuffers(ap, "astdrmfb", primary);
|
|
+ kfree(ap);
|
|
+}
|
|
+
|
|
static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
{
|
|
+ ast_kick_out_firmware_fb(pdev);
|
|
+
|
|
return drm_get_pci_dev(pdev, ent, &driver);
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
|
|
index 69d19f3304a5..21085f669e21 100644
|
|
--- a/drivers/gpu/drm/ast/ast_mode.c
|
|
+++ b/drivers/gpu/drm/ast/ast_mode.c
|
|
@@ -552,6 +552,7 @@ static int ast_crtc_do_set_base(struct drm_crtc *crtc,
|
|
}
|
|
ast_bo_unreserve(bo);
|
|
|
|
+ ast_set_offset_reg(crtc);
|
|
ast_set_start_address_crt1(crtc, (u32)gpu_addr);
|
|
|
|
return 0;
|
|
@@ -1249,7 +1250,7 @@ static int ast_cursor_move(struct drm_crtc *crtc,
|
|
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc7, ((y >> 8) & 0x07));
|
|
|
|
/* dummy write to fire HWC */
|
|
- ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xCB, 0xFF, 0x00);
|
|
+ ast_show_cursor(crtc);
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
|
|
index 3258baf3282e..2e52015634f9 100644
|
|
--- a/drivers/input/joystick/xpad.c
|
|
+++ b/drivers/input/joystick/xpad.c
|
|
@@ -76,18 +76,23 @@
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
+#include <linux/input.h>
|
|
+#include <linux/rcupdate.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/stat.h>
|
|
#include <linux/module.h>
|
|
#include <linux/usb/input.h>
|
|
+#include <linux/usb/quirks.h>
|
|
|
|
#define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>"
|
|
#define DRIVER_DESC "X-Box pad driver"
|
|
|
|
-#define XPAD_PKT_LEN 32
|
|
+#define XPAD_PKT_LEN 64
|
|
|
|
-/* xbox d-pads should map to buttons, as is required for DDR pads
|
|
- but we map them to axes when possible to simplify things */
|
|
+/*
|
|
+ * xbox d-pads should map to buttons, as is required for DDR pads
|
|
+ * but we map them to axes when possible to simplify things
|
|
+ */
|
|
#define MAP_DPAD_TO_BUTTONS (1 << 0)
|
|
#define MAP_TRIGGERS_TO_BUTTONS (1 << 1)
|
|
#define MAP_STICKS_TO_NULL (1 << 2)
|
|
@@ -112,6 +117,10 @@ static bool sticks_to_null;
|
|
module_param(sticks_to_null, bool, S_IRUGO);
|
|
MODULE_PARM_DESC(sticks_to_null, "Do not map sticks at all for unknown pads");
|
|
|
|
+static bool auto_poweroff = true;
|
|
+module_param(auto_poweroff, bool, S_IWUSR | S_IRUGO);
|
|
+MODULE_PARM_DESC(auto_poweroff, "Power off wireless controllers on suspend");
|
|
+
|
|
static const struct xpad_device {
|
|
u16 idVendor;
|
|
u16 idProduct;
|
|
@@ -119,43 +128,77 @@ static const struct xpad_device {
|
|
u8 mapping;
|
|
u8 xtype;
|
|
} xpad_device[] = {
|
|
+ { 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 },
|
|
+ { 0x044f, 0x0f00, "Thrustmaster Wheel", 0, XTYPE_XBOX },
|
|
+ { 0x044f, 0x0f03, "Thrustmaster Wheel", 0, XTYPE_XBOX },
|
|
+ { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
|
|
+ { 0x044f, 0x0f10, "Thrustmaster Modena GT Wheel", 0, XTYPE_XBOX },
|
|
+ { 0x044f, 0xb326, "Thrustmaster Gamepad GP XID", 0, XTYPE_XBOX360 },
|
|
{ 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", 0, XTYPE_XBOX },
|
|
{ 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX },
|
|
{ 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX },
|
|
+ { 0x045e, 0x0288, "Microsoft Xbox Controller S v2", 0, XTYPE_XBOX },
|
|
{ 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX },
|
|
{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
|
|
- { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
|
|
- { 0x045e, 0x02dd, "Microsoft X-Box One pad (Covert Forces)", 0, XTYPE_XBOXONE },
|
|
+ { 0x045e, 0x028f, "Microsoft X-Box 360 pad v2", 0, XTYPE_XBOX360 },
|
|
{ 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
|
|
+ { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
|
|
+ { 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE },
|
|
+ { 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", 0, XTYPE_XBOXONE },
|
|
+ { 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE },
|
|
{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
|
|
- { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
|
|
- { 0x044f, 0xb326, "Thrustmaster Gamepad GP XID", 0, XTYPE_XBOX360 },
|
|
{ 0x046d, 0xc21d, "Logitech Gamepad F310", 0, XTYPE_XBOX360 },
|
|
{ 0x046d, 0xc21e, "Logitech Gamepad F510", 0, XTYPE_XBOX360 },
|
|
{ 0x046d, 0xc21f, "Logitech Gamepad F710", 0, XTYPE_XBOX360 },
|
|
{ 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 },
|
|
{ 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX },
|
|
{ 0x046d, 0xca88, "Logitech Compact Controller for Xbox", 0, XTYPE_XBOX },
|
|
+ { 0x046d, 0xca8a, "Logitech Precision Vibration Feedback Wheel", 0, XTYPE_XBOX },
|
|
+ { 0x046d, 0xcaa3, "Logitech DriveFx Racing Wheel", 0, XTYPE_XBOX360 },
|
|
+ { 0x056e, 0x2004, "Elecom JC-U3613M", 0, XTYPE_XBOX360 },
|
|
{ 0x05fd, 0x1007, "Mad Catz Controller (unverified)", 0, XTYPE_XBOX },
|
|
{ 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", 0, XTYPE_XBOX },
|
|
+ { 0x05fe, 0x3030, "Chic Controller", 0, XTYPE_XBOX },
|
|
+ { 0x05fe, 0x3031, "Chic Controller", 0, XTYPE_XBOX },
|
|
+ { 0x062a, 0x0020, "Logic3 Xbox GamePad", 0, XTYPE_XBOX },
|
|
+ { 0x062a, 0x0033, "Competition Pro Steering Wheel", 0, XTYPE_XBOX },
|
|
+ { 0x06a3, 0x0200, "Saitek Racing Wheel", 0, XTYPE_XBOX },
|
|
+ { 0x06a3, 0x0201, "Saitek Adrenalin", 0, XTYPE_XBOX },
|
|
+ { 0x06a3, 0xf51a, "Saitek P3600", 0, XTYPE_XBOX360 },
|
|
+ { 0x0738, 0x4506, "Mad Catz 4506 Wireless Controller", 0, XTYPE_XBOX },
|
|
{ 0x0738, 0x4516, "Mad Catz Control Pad", 0, XTYPE_XBOX },
|
|
+ { 0x0738, 0x4520, "Mad Catz Control Pad Pro", 0, XTYPE_XBOX },
|
|
{ 0x0738, 0x4522, "Mad Catz LumiCON", 0, XTYPE_XBOX },
|
|
{ 0x0738, 0x4526, "Mad Catz Control Pad Pro", 0, XTYPE_XBOX },
|
|
+ { 0x0738, 0x4530, "Mad Catz Universal MC2 Racing Wheel and Pedals", 0, XTYPE_XBOX },
|
|
{ 0x0738, 0x4536, "Mad Catz MicroCON", 0, XTYPE_XBOX },
|
|
{ 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
|
{ 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", 0, XTYPE_XBOX },
|
|
+ { 0x0738, 0x4586, "Mad Catz MicroCon Wireless Controller", 0, XTYPE_XBOX },
|
|
+ { 0x0738, 0x4588, "Mad Catz Blaster", 0, XTYPE_XBOX },
|
|
+ { 0x0738, 0x45ff, "Mad Catz Beat Pad (w/ Handle)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
|
{ 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
|
|
{ 0x0738, 0x4718, "Mad Catz Street Fighter IV FightStick SE", 0, XTYPE_XBOX360 },
|
|
{ 0x0738, 0x4726, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 },
|
|
{ 0x0738, 0x4728, "Mad Catz Street Fighter IV FightPad", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x0738, 0x4736, "Mad Catz MicroCon Gamepad", 0, XTYPE_XBOX360 },
|
|
{ 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
{ 0x0738, 0x4740, "Mad Catz Beat Pad", 0, XTYPE_XBOX360 },
|
|
+ { 0x0738, 0x4743, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
|
+ { 0x0738, 0x4758, "Mad Catz Arcade Game Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x0738, 0x4a01, "Mad Catz FightStick TE 2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
|
|
{ 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
|
+ { 0x0738, 0x9871, "Mad Catz Portable Drum", 0, XTYPE_XBOX360 },
|
|
{ 0x0738, 0xb726, "Mad Catz Xbox controller - MW2", 0, XTYPE_XBOX360 },
|
|
+ { 0x0738, 0xb738, "Mad Catz MVC2TE Stick 2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
{ 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", XTYPE_XBOX360 },
|
|
{ 0x0738, 0xcb02, "Saitek Cyborg Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 },
|
|
{ 0x0738, 0xcb03, "Saitek P3200 Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 },
|
|
+ { 0x0738, 0xcb29, "Saitek Aviator Stick AV8R02", 0, XTYPE_XBOX360 },
|
|
{ 0x0738, 0xf738, "Super SFIV FightStick TE S", 0, XTYPE_XBOX360 },
|
|
+ { 0x07ff, 0xffff, "Mad Catz GamePad", 0, XTYPE_XBOX360 },
|
|
+ { 0x0c12, 0x0005, "Intec wireless", 0, XTYPE_XBOX },
|
|
+ { 0x0c12, 0x8801, "Nyko Xbox Controller", 0, XTYPE_XBOX },
|
|
{ 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
|
|
{ 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX },
|
|
{ 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX },
|
|
@@ -163,32 +206,66 @@ static const struct xpad_device {
|
|
{ 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", 0, XTYPE_XBOX },
|
|
{ 0x0d2f, 0x0002, "Andamiro Pump It Up pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
|
{ 0x0e4c, 0x1097, "Radica Gamester Controller", 0, XTYPE_XBOX },
|
|
+ { 0x0e4c, 0x1103, "Radica Gamester Reflex", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX },
|
|
{ 0x0e4c, 0x2390, "Radica Games Jtech Controller", 0, XTYPE_XBOX },
|
|
+ { 0x0e4c, 0x3510, "Radica Gamester", 0, XTYPE_XBOX },
|
|
{ 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", 0, XTYPE_XBOX },
|
|
{ 0x0e6f, 0x0005, "Eclipse wireless Controller", 0, XTYPE_XBOX },
|
|
{ 0x0e6f, 0x0006, "Edge wireless Controller", 0, XTYPE_XBOX },
|
|
+ { 0x0e6f, 0x0008, "After Glow Pro Controller", 0, XTYPE_XBOX },
|
|
{ 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
|
|
{ 0x0e6f, 0x0113, "Afterglow AX.1 Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
|
|
+ { 0x0e6f, 0x011f, "Rock Candy Gamepad Wired Controller", 0, XTYPE_XBOX360 },
|
|
+ { 0x0e6f, 0x0131, "PDP EA Sports Controller", 0, XTYPE_XBOX360 },
|
|
+ { 0x0e6f, 0x0133, "Xbox 360 Wired Controller", 0, XTYPE_XBOX360 },
|
|
+ { 0x0e6f, 0x0139, "Afterglow Prismatic Wired Controller", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x013a, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x0146, "Rock Candy Wired Controller for Xbox One", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x0147, "PDP Marvel Xbox One Controller", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x015c, "PDP Xbox One Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x0161, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x0162, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x0163, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x0164, "PDP Battlefield One", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x0165, "PDP Titanfall 2", 0, XTYPE_XBOXONE },
|
|
{ 0x0e6f, 0x0201, "Pelican PL-3601 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
|
|
{ 0x0e6f, 0x0213, "Afterglow Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
|
|
{ 0x0e6f, 0x021f, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
|
|
+ { 0x0e6f, 0x0246, "Rock Candy Gamepad for Xbox One 2015", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x02ab, "PDP Controller for Xbox One", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x02a4, "PDP Wired Controller for Xbox One - Stealth Series", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x02a6, "PDP Wired Controller for Xbox One - Camo Series", 0, XTYPE_XBOXONE },
|
|
{ 0x0e6f, 0x0301, "Logic3 Controller", 0, XTYPE_XBOX360 },
|
|
+ { 0x0e6f, 0x0346, "Rock Candy Gamepad for Xbox One 2016", 0, XTYPE_XBOXONE },
|
|
{ 0x0e6f, 0x0401, "Logic3 Controller", 0, XTYPE_XBOX360 },
|
|
+ { 0x0e6f, 0x0413, "Afterglow AX.1 Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
|
|
+ { 0x0e6f, 0x0501, "PDP Xbox 360 Controller", 0, XTYPE_XBOX360 },
|
|
+ { 0x0e6f, 0xf900, "PDP Afterglow AX.1", 0, XTYPE_XBOX360 },
|
|
{ 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", 0, XTYPE_XBOX },
|
|
{ 0x0e8f, 0x3008, "Generic xbox control (dealextreme)", 0, XTYPE_XBOX },
|
|
{ 0x0f0d, 0x000a, "Hori Co. DOA4 FightStick", 0, XTYPE_XBOX360 },
|
|
+ { 0x0f0d, 0x000c, "Hori PadEX Turbo", 0, XTYPE_XBOX360 },
|
|
{ 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
{ 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x0f0d, 0x001b, "Hori Real Arcade Pro VX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x0f0d, 0x0063, "Hori Real Arcade Pro Hayabusa (USA) Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
|
|
+ { 0x0f0d, 0x0067, "HORIPAD ONE", 0, XTYPE_XBOXONE },
|
|
+ { 0x0f0d, 0x0078, "Hori Real Arcade Pro V Kai Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
|
|
+ { 0x0f30, 0x010b, "Philips Recoil", 0, XTYPE_XBOX },
|
|
{ 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX },
|
|
{ 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX },
|
|
{ 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX },
|
|
+ { 0x11c9, 0x55f0, "Nacon GC-100XF", 0, XTYPE_XBOX360 },
|
|
{ 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
|
|
{ 0x12ab, 0x0301, "PDP AFTERGLOW AX.1", 0, XTYPE_XBOX360 },
|
|
+ { 0x12ab, 0x0303, "Mortal Kombat Klassic FightStick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
{ 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
|
{ 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 },
|
|
{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
|
+ { 0x1430, 0xf801, "RedOctane Controller", 0, XTYPE_XBOX360 },
|
|
{ 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 },
|
|
{ 0x1532, 0x0037, "Razer Sabertooth", 0, XTYPE_XBOX360 },
|
|
+ { 0x1532, 0x0a00, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
|
|
{ 0x1532, 0x0a03, "Razer Wildcat", 0, XTYPE_XBOXONE },
|
|
{ 0x15e4, 0x3f00, "Power A Mini Pro Elite", 0, XTYPE_XBOX360 },
|
|
{ 0x15e4, 0x3f0a, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 },
|
|
@@ -196,24 +273,67 @@ static const struct xpad_device {
|
|
{ 0x162e, 0xbeef, "Joytech Neo-Se Take2", 0, XTYPE_XBOX360 },
|
|
{ 0x1689, 0xfd00, "Razer Onza Tournament Edition", 0, XTYPE_XBOX360 },
|
|
{ 0x1689, 0xfd01, "Razer Onza Classic Edition", 0, XTYPE_XBOX360 },
|
|
- { 0x24c6, 0x5d04, "Razer Sabertooth", 0, XTYPE_XBOX360 },
|
|
+ { 0x1689, 0xfe00, "Razer Sabertooth", 0, XTYPE_XBOX360 },
|
|
{ 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 },
|
|
{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0x0130, "Ion Drum Rocker", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
|
|
{ 0x1bad, 0xf016, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf018, "Mad Catz Street Fighter IV SE Fighting Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf019, "Mad Catz Brawlstick for Xbox 360", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf021, "Mad Cats Ghost Recon FS GamePad", 0, XTYPE_XBOX360 },
|
|
{ 0x1bad, 0xf023, "MLG Pro Circuit Controller (Xbox)", 0, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf025, "Mad Catz Call Of Duty", 0, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf027, "Mad Catz FPS Pro", 0, XTYPE_XBOX360 },
|
|
{ 0x1bad, 0xf028, "Street Fighter IV FightPad", 0, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf02e, "Mad Catz Fightpad", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf030, "Mad Catz Xbox 360 MC2 MicroCon Racing Wheel", 0, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf036, "Mad Catz MicroCon GamePad Pro", 0, XTYPE_XBOX360 },
|
|
{ 0x1bad, 0xf038, "Street Fighter IV FightStick TE", 0, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf039, "Mad Catz MvC2 TE", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf03a, "Mad Catz SFxT Fightstick Pro", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf03d, "Street Fighter IV Arcade Stick TE - Chun Li", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf03e, "Mad Catz MLG FightStick TE", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf03f, "Mad Catz FightStick SoulCaliber", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf042, "Mad Catz FightStick TES+", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf080, "Mad Catz FightStick TE2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf501, "HoriPad EX2 Turbo", 0, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf502, "Hori Real Arcade Pro.VX SA", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf503, "Hori Fighting Stick VX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf504, "Hori Real Arcade Pro. EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf505, "Hori Fighting Stick EX2B", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf506, "Hori Real Arcade Pro.EX Premium VLX", 0, XTYPE_XBOX360 },
|
|
{ 0x1bad, 0xf900, "Harmonix Xbox 360 Controller", 0, XTYPE_XBOX360 },
|
|
{ 0x1bad, 0xf901, "Gamestop Xbox 360 Controller", 0, XTYPE_XBOX360 },
|
|
{ 0x1bad, 0xf903, "Tron Xbox 360 controller", 0, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf904, "PDP Versus Fighting Pad", 0, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xf906, "MortalKombat FightStick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xfa01, "MadCatz GamePad", 0, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xfd00, "Razer Onza TE", 0, XTYPE_XBOX360 },
|
|
+ { 0x1bad, 0xfd01, "Razer Onza", 0, XTYPE_XBOX360 },
|
|
{ 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
{ 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 },
|
|
{ 0x24c6, 0x5303, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 },
|
|
+ { 0x24c6, 0x530a, "Xbox 360 Pro EX Controller", 0, XTYPE_XBOX360 },
|
|
+ { 0x24c6, 0x531a, "PowerA Pro Ex", 0, XTYPE_XBOX360 },
|
|
+ { 0x24c6, 0x5397, "FUS1ON Tournament Controller", 0, XTYPE_XBOX360 },
|
|
+ { 0x24c6, 0x541a, "PowerA Xbox One Mini Wired Controller", 0, XTYPE_XBOXONE },
|
|
+ { 0x24c6, 0x542a, "Xbox ONE spectra", 0, XTYPE_XBOXONE },
|
|
+ { 0x24c6, 0x543a, "PowerA Xbox One wired controller", 0, XTYPE_XBOXONE },
|
|
{ 0x24c6, 0x5500, "Hori XBOX 360 EX 2 with Turbo", 0, XTYPE_XBOX360 },
|
|
{ 0x24c6, 0x5501, "Hori Real Arcade Pro VX-SA", 0, XTYPE_XBOX360 },
|
|
+ { 0x24c6, 0x5502, "Hori Fighting Stick VX Alt", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x24c6, 0x5503, "Hori Fighting Edge", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
{ 0x24c6, 0x5506, "Hori SOULCALIBUR V Stick", 0, XTYPE_XBOX360 },
|
|
+ { 0x24c6, 0x550d, "Hori GEM Xbox controller", 0, XTYPE_XBOX360 },
|
|
+ { 0x24c6, 0x550e, "Hori Real Arcade Pro V Kai 360", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
+ { 0x24c6, 0x551a, "PowerA FUSION Pro Controller", 0, XTYPE_XBOXONE },
|
|
+ { 0x24c6, 0x561a, "PowerA FUSION Controller", 0, XTYPE_XBOXONE },
|
|
+ { 0x24c6, 0x5b00, "ThrustMaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 },
|
|
{ 0x24c6, 0x5b02, "Thrustmaster, Inc. GPX Controller", 0, XTYPE_XBOX360 },
|
|
{ 0x24c6, 0x5b03, "Thrustmaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 },
|
|
+ { 0x24c6, 0x5d04, "Razer Sabertooth", 0, XTYPE_XBOX360 },
|
|
+ { 0x24c6, 0xfafe, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
|
|
+ { 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX },
|
|
{ 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
|
|
{ 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
|
|
};
|
|
@@ -274,15 +394,15 @@ static const signed short xpad_abs_triggers[] = {
|
|
* match against vendor id as well. Wired Xbox 360 devices have protocol 1,
|
|
* wireless controllers have protocol 129.
|
|
*/
|
|
-#define XPAD_XBOX360_VENDOR_PROTOCOL(vend,pr) \
|
|
+#define XPAD_XBOX360_VENDOR_PROTOCOL(vend, pr) \
|
|
.match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \
|
|
.idVendor = (vend), \
|
|
.bInterfaceClass = USB_CLASS_VENDOR_SPEC, \
|
|
.bInterfaceSubClass = 93, \
|
|
.bInterfaceProtocol = (pr)
|
|
#define XPAD_XBOX360_VENDOR(vend) \
|
|
- { XPAD_XBOX360_VENDOR_PROTOCOL(vend,1) }, \
|
|
- { XPAD_XBOX360_VENDOR_PROTOCOL(vend,129) }
|
|
+ { XPAD_XBOX360_VENDOR_PROTOCOL((vend), 1) }, \
|
|
+ { XPAD_XBOX360_VENDOR_PROTOCOL((vend), 129) }
|
|
|
|
/* The Xbox One controller uses subclass 71 and protocol 208. */
|
|
#define XPAD_XBOXONE_VENDOR_PROTOCOL(vend, pr) \
|
|
@@ -292,33 +412,138 @@ static const signed short xpad_abs_triggers[] = {
|
|
.bInterfaceSubClass = 71, \
|
|
.bInterfaceProtocol = (pr)
|
|
#define XPAD_XBOXONE_VENDOR(vend) \
|
|
- { XPAD_XBOXONE_VENDOR_PROTOCOL(vend, 208) }
|
|
+ { XPAD_XBOXONE_VENDOR_PROTOCOL((vend), 208) }
|
|
|
|
-static struct usb_device_id xpad_table[] = {
|
|
+static const struct usb_device_id xpad_table[] = {
|
|
{ USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */
|
|
+ XPAD_XBOX360_VENDOR(0x0079), /* GPD Win 2 Controller */
|
|
XPAD_XBOX360_VENDOR(0x044f), /* Thrustmaster X-Box 360 controllers */
|
|
XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */
|
|
XPAD_XBOXONE_VENDOR(0x045e), /* Microsoft X-Box One controllers */
|
|
XPAD_XBOX360_VENDOR(0x046d), /* Logitech X-Box 360 style controllers */
|
|
+ XPAD_XBOX360_VENDOR(0x056e), /* Elecom JC-U3613M */
|
|
+ XPAD_XBOX360_VENDOR(0x06a3), /* Saitek P3600 */
|
|
XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */
|
|
{ USB_DEVICE(0x0738, 0x4540) }, /* Mad Catz Beat Pad */
|
|
+ XPAD_XBOXONE_VENDOR(0x0738), /* Mad Catz FightStick TE 2 */
|
|
+ XPAD_XBOX360_VENDOR(0x07ff), /* Mad Catz GamePad */
|
|
XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */
|
|
+ XPAD_XBOXONE_VENDOR(0x0e6f), /* 0x0e6f X-Box One controllers */
|
|
+ XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */
|
|
+ XPAD_XBOXONE_VENDOR(0x0f0d), /* Hori Controllers */
|
|
+ XPAD_XBOX360_VENDOR(0x11c9), /* Nacon GC100XF */
|
|
XPAD_XBOX360_VENDOR(0x12ab), /* X-Box 360 dance pads */
|
|
XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */
|
|
XPAD_XBOX360_VENDOR(0x146b), /* BigBen Interactive Controllers */
|
|
- XPAD_XBOX360_VENDOR(0x1bad), /* Harminix Rock Band Guitar and Drums */
|
|
- XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */
|
|
- XPAD_XBOX360_VENDOR(0x1689), /* Razer Onza */
|
|
- XPAD_XBOX360_VENDOR(0x24c6), /* PowerA Controllers */
|
|
XPAD_XBOX360_VENDOR(0x1532), /* Razer Sabertooth */
|
|
XPAD_XBOXONE_VENDOR(0x1532), /* Razer Wildcat */
|
|
XPAD_XBOX360_VENDOR(0x15e4), /* Numark X-Box 360 controllers */
|
|
XPAD_XBOX360_VENDOR(0x162e), /* Joytech X-Box 360 controllers */
|
|
+ XPAD_XBOX360_VENDOR(0x1689), /* Razer Onza */
|
|
+ XPAD_XBOX360_VENDOR(0x1bad), /* Harminix Rock Band Guitar and Drums */
|
|
+ XPAD_XBOX360_VENDOR(0x24c6), /* PowerA Controllers */
|
|
+ XPAD_XBOXONE_VENDOR(0x24c6), /* PowerA Controllers */
|
|
{ }
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(usb, xpad_table);
|
|
|
|
+struct xboxone_init_packet {
|
|
+ u16 idVendor;
|
|
+ u16 idProduct;
|
|
+ const u8 *data;
|
|
+ u8 len;
|
|
+};
|
|
+
|
|
+#define XBOXONE_INIT_PKT(_vid, _pid, _data) \
|
|
+ { \
|
|
+ .idVendor = (_vid), \
|
|
+ .idProduct = (_pid), \
|
|
+ .data = (_data), \
|
|
+ .len = ARRAY_SIZE(_data), \
|
|
+ }
|
|
+
|
|
+
|
|
+/*
|
|
+ * This packet is required for all Xbox One pads with 2015
|
|
+ * or later firmware installed (or present from the factory).
|
|
+ */
|
|
+static const u8 xboxone_fw2015_init[] = {
|
|
+ 0x05, 0x20, 0x00, 0x01, 0x00
|
|
+};
|
|
+
|
|
+/*
|
|
+ * This packet is required for the Titanfall 2 Xbox One pads
|
|
+ * (0x0e6f:0x0165) to finish initialization and for Hori pads
|
|
+ * (0x0f0d:0x0067) to make the analog sticks work.
|
|
+ */
|
|
+static const u8 xboxone_hori_init[] = {
|
|
+ 0x01, 0x20, 0x00, 0x09, 0x00, 0x04, 0x20, 0x3a,
|
|
+ 0x00, 0x00, 0x00, 0x80, 0x00
|
|
+};
|
|
+
|
|
+/*
|
|
+ * This packet is required for some of the PDP pads to start
|
|
+ * sending input reports. These pads include: (0x0e6f:0x02ab),
|
|
+ * (0x0e6f:0x02a4).
|
|
+ */
|
|
+static const u8 xboxone_pdp_init1[] = {
|
|
+ 0x0a, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14
|
|
+};
|
|
+
|
|
+/*
|
|
+ * This packet is required for some of the PDP pads to start
|
|
+ * sending input reports. These pads include: (0x0e6f:0x02ab),
|
|
+ * (0x0e6f:0x02a4).
|
|
+ */
|
|
+static const u8 xboxone_pdp_init2[] = {
|
|
+ 0x06, 0x20, 0x00, 0x02, 0x01, 0x00
|
|
+};
|
|
+
|
|
+/*
|
|
+ * A specific rumble packet is required for some PowerA pads to start
|
|
+ * sending input reports. One of those pads is (0x24c6:0x543a).
|
|
+ */
|
|
+static const u8 xboxone_rumblebegin_init[] = {
|
|
+ 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
|
|
+ 0x1D, 0x1D, 0xFF, 0x00, 0x00
|
|
+};
|
|
+
|
|
+/*
|
|
+ * A rumble packet with zero FF intensity will immediately
|
|
+ * terminate the rumbling required to init PowerA pads.
|
|
+ * This should happen fast enough that the motors don't
|
|
+ * spin up to enough speed to actually vibrate the gamepad.
|
|
+ */
|
|
+static const u8 xboxone_rumbleend_init[] = {
|
|
+ 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00
|
|
+};
|
|
+
|
|
+/*
|
|
+ * This specifies the selection of init packets that a gamepad
|
|
+ * will be sent on init *and* the order in which they will be
|
|
+ * sent. The correct sequence number will be added when the
|
|
+ * packet is going to be sent.
|
|
+ */
|
|
+static const struct xboxone_init_packet xboxone_init_packets[] = {
|
|
+ XBOXONE_INIT_PKT(0x0e6f, 0x0165, xboxone_hori_init),
|
|
+ XBOXONE_INIT_PKT(0x0f0d, 0x0067, xboxone_hori_init),
|
|
+ XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_fw2015_init),
|
|
+ XBOXONE_INIT_PKT(0x0e6f, 0x02ab, xboxone_pdp_init1),
|
|
+ XBOXONE_INIT_PKT(0x0e6f, 0x02ab, xboxone_pdp_init2),
|
|
+ XBOXONE_INIT_PKT(0x0e6f, 0x02a4, xboxone_pdp_init1),
|
|
+ XBOXONE_INIT_PKT(0x0e6f, 0x02a4, xboxone_pdp_init2),
|
|
+ XBOXONE_INIT_PKT(0x0e6f, 0x02a6, xboxone_pdp_init1),
|
|
+ XBOXONE_INIT_PKT(0x0e6f, 0x02a6, xboxone_pdp_init2),
|
|
+ XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumblebegin_init),
|
|
+ XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_rumblebegin_init),
|
|
+ XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_rumblebegin_init),
|
|
+ XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumbleend_init),
|
|
+ XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_rumbleend_init),
|
|
+ XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_rumbleend_init),
|
|
+};
|
|
+
|
|
struct xpad_output_packet {
|
|
u8 data[XPAD_PKT_LEN];
|
|
u8 len;
|
|
@@ -334,23 +559,28 @@ struct xpad_output_packet {
|
|
|
|
struct usb_xpad {
|
|
struct input_dev *dev; /* input device interface */
|
|
+ struct input_dev __rcu *x360w_dev;
|
|
struct usb_device *udev; /* usb device */
|
|
struct usb_interface *intf; /* usb interface */
|
|
|
|
- int pad_present;
|
|
+ bool pad_present;
|
|
+ bool input_created;
|
|
|
|
struct urb *irq_in; /* urb for interrupt in report */
|
|
unsigned char *idata; /* input data */
|
|
dma_addr_t idata_dma;
|
|
|
|
struct urb *irq_out; /* urb for interrupt out report */
|
|
+ struct usb_anchor irq_out_anchor;
|
|
bool irq_out_active; /* we must not use an active URB */
|
|
+ u8 odata_serial; /* serial number for xbox one protocol */
|
|
unsigned char *odata; /* output data */
|
|
dma_addr_t odata_dma;
|
|
spinlock_t odata_lock;
|
|
|
|
struct xpad_output_packet out_packets[XPAD_NUM_OUT_PACKETS];
|
|
int last_out_packet;
|
|
+ int init_seq;
|
|
|
|
#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
|
|
struct xpad_led *led;
|
|
@@ -362,8 +592,13 @@ struct usb_xpad {
|
|
int xtype; /* type of xbox device */
|
|
int pad_nr; /* the order x360 pads were attached */
|
|
const char *name; /* name of the device */
|
|
+ struct work_struct work; /* init/remove device from callback */
|
|
};
|
|
|
|
+static int xpad_init_input(struct usb_xpad *xpad);
|
|
+static void xpad_deinit_input(struct usb_xpad *xpad);
|
|
+static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num);
|
|
+
|
|
/*
|
|
* xpad_process_packet
|
|
*
|
|
@@ -443,10 +678,12 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
|
|
* http://www.free60.org/wiki/Gamepad
|
|
*/
|
|
|
|
-static void xpad360_process_packet(struct usb_xpad *xpad,
|
|
+static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev,
|
|
u16 cmd, unsigned char *data)
|
|
{
|
|
- struct input_dev *dev = xpad->dev;
|
|
+ /* valid pad data */
|
|
+ if (data[0] != 0x00)
|
|
+ return;
|
|
|
|
/* digital pad */
|
|
if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
|
|
@@ -514,7 +751,30 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
|
|
input_sync(dev);
|
|
}
|
|
|
|
-static void xpad_identify_controller(struct usb_xpad *xpad);
|
|
+static void xpad_presence_work(struct work_struct *work)
|
|
+{
|
|
+ struct usb_xpad *xpad = container_of(work, struct usb_xpad, work);
|
|
+ int error;
|
|
+
|
|
+ if (xpad->pad_present) {
|
|
+ error = xpad_init_input(xpad);
|
|
+ if (error) {
|
|
+ /* complain only, not much else we can do here */
|
|
+ dev_err(&xpad->dev->dev,
|
|
+ "unable to init device: %d\n", error);
|
|
+ } else {
|
|
+ rcu_assign_pointer(xpad->x360w_dev, xpad->dev);
|
|
+ }
|
|
+ } else {
|
|
+ RCU_INIT_POINTER(xpad->x360w_dev, NULL);
|
|
+ synchronize_rcu();
|
|
+ /*
|
|
+ * Now that we are sure xpad360w_process_packet is not
|
|
+ * using input device we can get rid of it.
|
|
+ */
|
|
+ xpad_deinit_input(xpad);
|
|
+ }
|
|
+}
|
|
|
|
/*
|
|
* xpad360w_process_packet
|
|
@@ -532,35 +792,61 @@ static void xpad_identify_controller(struct usb_xpad *xpad);
|
|
*/
|
|
static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
|
|
{
|
|
+ struct input_dev *dev;
|
|
+ bool present;
|
|
+
|
|
/* Presence change */
|
|
if (data[0] & 0x08) {
|
|
- if (data[1] & 0x80) {
|
|
- xpad->pad_present = 1;
|
|
- /*
|
|
- * Light up the segment corresponding to
|
|
- * controller number.
|
|
- */
|
|
- xpad_identify_controller(xpad);
|
|
- } else
|
|
- xpad->pad_present = 0;
|
|
+ present = (data[1] & 0x80) != 0;
|
|
+
|
|
+ if (xpad->pad_present != present) {
|
|
+ xpad->pad_present = present;
|
|
+ schedule_work(&xpad->work);
|
|
+ }
|
|
}
|
|
|
|
/* Valid pad data */
|
|
- if (!(data[1] & 0x1))
|
|
+ if (data[1] != 0x1)
|
|
return;
|
|
|
|
- xpad360_process_packet(xpad, cmd, &data[4]);
|
|
+ rcu_read_lock();
|
|
+ dev = rcu_dereference(xpad->x360w_dev);
|
|
+ if (dev)
|
|
+ xpad360_process_packet(xpad, dev, cmd, &data[4]);
|
|
+ rcu_read_unlock();
|
|
}
|
|
|
|
/*
|
|
- * xpadone_process_buttons
|
|
+ * xpadone_process_packet
|
|
*
|
|
- * Process a button update packet from an Xbox one controller.
|
|
+ * Completes a request by converting the data into events for the
|
|
+ * input subsystem. This version is for the Xbox One controller.
|
|
+ *
|
|
+ * The report format was gleaned from
|
|
+ * https://github.com/kylelemons/xbox/blob/master/xbox.go
|
|
*/
|
|
-static void xpadone_process_buttons(struct usb_xpad *xpad,
|
|
- struct input_dev *dev,
|
|
- unsigned char *data)
|
|
+static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
|
|
{
|
|
+ struct input_dev *dev = xpad->dev;
|
|
+
|
|
+ /* the xbox button has its own special report */
|
|
+ if (data[0] == 0X07) {
|
|
+ /*
|
|
+ * The Xbox One S controller requires these reports to be
|
|
+ * acked otherwise it continues sending them forever and
|
|
+ * won't report further mode button events.
|
|
+ */
|
|
+ if (data[1] == 0x30)
|
|
+ xpadone_ack_mode_report(xpad, data[2]);
|
|
+
|
|
+ input_report_key(dev, BTN_MODE, data[4] & 0x01);
|
|
+ input_sync(dev);
|
|
+ return;
|
|
+ }
|
|
+ /* check invalid packet */
|
|
+ else if (data[0] != 0X20)
|
|
+ return;
|
|
+
|
|
/* menu/view buttons */
|
|
input_report_key(dev, BTN_START, data[4] & 0x04);
|
|
input_report_key(dev, BTN_SELECT, data[4] & 0x08);
|
|
@@ -623,34 +909,6 @@ static void xpadone_process_buttons(struct usb_xpad *xpad,
|
|
input_sync(dev);
|
|
}
|
|
|
|
-/*
|
|
- * xpadone_process_packet
|
|
- *
|
|
- * Completes a request by converting the data into events for the
|
|
- * input subsystem. This version is for the Xbox One controller.
|
|
- *
|
|
- * The report format was gleaned from
|
|
- * https://github.com/kylelemons/xbox/blob/master/xbox.go
|
|
- */
|
|
-
|
|
-static void xpadone_process_packet(struct usb_xpad *xpad,
|
|
- u16 cmd, unsigned char *data)
|
|
-{
|
|
- struct input_dev *dev = xpad->dev;
|
|
-
|
|
- switch (data[0]) {
|
|
- case 0x20:
|
|
- xpadone_process_buttons(xpad, dev, data);
|
|
- break;
|
|
-
|
|
- case 0x07:
|
|
- /* the xbox button has its own special report */
|
|
- input_report_key(dev, BTN_MODE, data[4] & 0x01);
|
|
- input_sync(dev);
|
|
- break;
|
|
- }
|
|
-}
|
|
-
|
|
static void xpad_irq_in(struct urb *urb)
|
|
{
|
|
struct usb_xpad *xpad = urb->context;
|
|
@@ -678,7 +936,7 @@ static void xpad_irq_in(struct urb *urb)
|
|
|
|
switch (xpad->xtype) {
|
|
case XTYPE_XBOX360:
|
|
- xpad360_process_packet(xpad, 0, xpad->idata);
|
|
+ xpad360_process_packet(xpad, xpad->dev, 0, xpad->idata);
|
|
break;
|
|
case XTYPE_XBOX360W:
|
|
xpad360w_process_packet(xpad, 0, xpad->idata);
|
|
@@ -697,12 +955,48 @@ exit:
|
|
__func__, retval);
|
|
}
|
|
|
|
+/* Callers must hold xpad->odata_lock spinlock */
|
|
+static bool xpad_prepare_next_init_packet(struct usb_xpad *xpad)
|
|
+{
|
|
+ const struct xboxone_init_packet *init_packet;
|
|
+
|
|
+ if (xpad->xtype != XTYPE_XBOXONE)
|
|
+ return false;
|
|
+
|
|
+ /* Perform initialization sequence for Xbox One pads that require it */
|
|
+ while (xpad->init_seq < ARRAY_SIZE(xboxone_init_packets)) {
|
|
+ init_packet = &xboxone_init_packets[xpad->init_seq++];
|
|
+
|
|
+ if (init_packet->idVendor != 0 &&
|
|
+ init_packet->idVendor != xpad->dev->id.vendor)
|
|
+ continue;
|
|
+
|
|
+ if (init_packet->idProduct != 0 &&
|
|
+ init_packet->idProduct != xpad->dev->id.product)
|
|
+ continue;
|
|
+
|
|
+ /* This packet applies to our device, so prepare to send it */
|
|
+ memcpy(xpad->odata, init_packet->data, init_packet->len);
|
|
+ xpad->irq_out->transfer_buffer_length = init_packet->len;
|
|
+
|
|
+ /* Update packet with current sequence number */
|
|
+ xpad->odata[2] = xpad->odata_serial++;
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
/* Callers must hold xpad->odata_lock spinlock */
|
|
static bool xpad_prepare_next_out_packet(struct usb_xpad *xpad)
|
|
{
|
|
struct xpad_output_packet *pkt, *packet = NULL;
|
|
int i;
|
|
|
|
+ /* We may have init packets to send before we can send user commands */
|
|
+ if (xpad_prepare_next_init_packet(xpad))
|
|
+ return true;
|
|
+
|
|
for (i = 0; i < XPAD_NUM_OUT_PACKETS; i++) {
|
|
if (++xpad->last_out_packet >= XPAD_NUM_OUT_PACKETS)
|
|
xpad->last_out_packet = 0;
|
|
@@ -733,11 +1027,13 @@ static int xpad_try_sending_next_out_packet(struct usb_xpad *xpad)
|
|
int error;
|
|
|
|
if (!xpad->irq_out_active && xpad_prepare_next_out_packet(xpad)) {
|
|
+ usb_anchor_urb(xpad->irq_out, &xpad->irq_out_anchor);
|
|
error = usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
|
|
if (error) {
|
|
dev_err(&xpad->intf->dev,
|
|
"%s - usb_submit_urb failed with result %d\n",
|
|
__func__, error);
|
|
+ usb_unanchor_urb(xpad->irq_out);
|
|
return -EIO;
|
|
}
|
|
|
|
@@ -779,11 +1075,13 @@ static void xpad_irq_out(struct urb *urb)
|
|
}
|
|
|
|
if (xpad->irq_out_active) {
|
|
+ usb_anchor_urb(urb, &xpad->irq_out_anchor);
|
|
error = usb_submit_urb(urb, GFP_ATOMIC);
|
|
if (error) {
|
|
dev_err(dev,
|
|
"%s - usb_submit_urb failed with result %d\n",
|
|
__func__, error);
|
|
+ usb_unanchor_urb(urb);
|
|
xpad->irq_out_active = false;
|
|
}
|
|
}
|
|
@@ -791,34 +1089,29 @@ static void xpad_irq_out(struct urb *urb)
|
|
spin_unlock_irqrestore(&xpad->odata_lock, flags);
|
|
}
|
|
|
|
-static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
|
|
+static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad,
|
|
+ struct usb_endpoint_descriptor *ep_irq_out)
|
|
{
|
|
- struct usb_endpoint_descriptor *ep_irq_out;
|
|
- int ep_irq_out_idx;
|
|
int error;
|
|
|
|
if (xpad->xtype == XTYPE_UNKNOWN)
|
|
return 0;
|
|
|
|
+ init_usb_anchor(&xpad->irq_out_anchor);
|
|
+
|
|
xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN,
|
|
GFP_KERNEL, &xpad->odata_dma);
|
|
- if (!xpad->odata) {
|
|
- error = -ENOMEM;
|
|
- goto fail1;
|
|
- }
|
|
+ if (!xpad->odata)
|
|
+ return -ENOMEM;
|
|
|
|
spin_lock_init(&xpad->odata_lock);
|
|
|
|
xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
|
|
if (!xpad->irq_out) {
|
|
error = -ENOMEM;
|
|
- goto fail2;
|
|
+ goto err_free_coherent;
|
|
}
|
|
|
|
- /* Xbox One controller has in/out endpoints swapped. */
|
|
- ep_irq_out_idx = xpad->xtype == XTYPE_XBOXONE ? 0 : 1;
|
|
- ep_irq_out = &intf->cur_altsetting->endpoint[ep_irq_out_idx].desc;
|
|
-
|
|
usb_fill_int_urb(xpad->irq_out, xpad->udev,
|
|
usb_sndintpipe(xpad->udev, ep_irq_out->bEndpointAddress),
|
|
xpad->odata, XPAD_PKT_LEN,
|
|
@@ -828,14 +1121,21 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
|
|
|
|
return 0;
|
|
|
|
- fail2: usb_free_coherent(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
|
|
- fail1: return error;
|
|
+err_free_coherent:
|
|
+ usb_free_coherent(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
|
|
+ return error;
|
|
}
|
|
|
|
static void xpad_stop_output(struct usb_xpad *xpad)
|
|
{
|
|
- if (xpad->xtype != XTYPE_UNKNOWN)
|
|
- usb_kill_urb(xpad->irq_out);
|
|
+ if (xpad->xtype != XTYPE_UNKNOWN) {
|
|
+ if (!usb_wait_anchor_empty_timeout(&xpad->irq_out_anchor,
|
|
+ 5000)) {
|
|
+ dev_warn(&xpad->intf->dev,
|
|
+ "timed out waiting for output URB to complete, killing\n");
|
|
+ usb_kill_anchored_urbs(&xpad->irq_out_anchor);
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
static void xpad_deinit_output(struct usb_xpad *xpad)
|
|
@@ -882,21 +1182,17 @@ static int xpad_inquiry_pad_presence(struct usb_xpad *xpad)
|
|
|
|
static int xpad_start_xbox_one(struct usb_xpad *xpad)
|
|
{
|
|
- struct xpad_output_packet *packet =
|
|
- &xpad->out_packets[XPAD_OUT_CMD_IDX];
|
|
unsigned long flags;
|
|
int retval;
|
|
|
|
spin_lock_irqsave(&xpad->odata_lock, flags);
|
|
|
|
- /* Xbox one controller needs to be initialized. */
|
|
- packet->data[0] = 0x05;
|
|
- packet->data[1] = 0x20;
|
|
- packet->len = 2;
|
|
- packet->pending = true;
|
|
-
|
|
- /* Reset the sequence so we send out start packet first */
|
|
- xpad->last_out_packet = -1;
|
|
+ /*
|
|
+ * Begin the init sequence by attempting to send a packet.
|
|
+ * We will cycle through the init packet sequence before
|
|
+ * sending any packets from the output ring.
|
|
+ */
|
|
+ xpad->init_seq = 0;
|
|
retval = xpad_try_sending_next_out_packet(xpad);
|
|
|
|
spin_unlock_irqrestore(&xpad->odata_lock, flags);
|
|
@@ -904,6 +1200,30 @@ static int xpad_start_xbox_one(struct usb_xpad *xpad)
|
|
return retval;
|
|
}
|
|
|
|
+static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num)
|
|
+{
|
|
+ unsigned long flags;
|
|
+ struct xpad_output_packet *packet =
|
|
+ &xpad->out_packets[XPAD_OUT_CMD_IDX];
|
|
+ static const u8 mode_report_ack[] = {
|
|
+ 0x01, 0x20, 0x00, 0x09, 0x00, 0x07, 0x20, 0x02,
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00
|
|
+ };
|
|
+
|
|
+ spin_lock_irqsave(&xpad->odata_lock, flags);
|
|
+
|
|
+ packet->len = sizeof(mode_report_ack);
|
|
+ memcpy(packet->data, mode_report_ack, packet->len);
|
|
+ packet->data[2] = seq_num;
|
|
+ packet->pending = true;
|
|
+
|
|
+ /* Reset the sequence so we send out the ack now */
|
|
+ xpad->last_out_packet = -1;
|
|
+ xpad_try_sending_next_out_packet(xpad);
|
|
+
|
|
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
|
|
+}
|
|
+
|
|
#ifdef CONFIG_JOYSTICK_XPAD_FF
|
|
static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
|
|
{
|
|
@@ -966,18 +1286,19 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
|
|
|
|
case XTYPE_XBOXONE:
|
|
packet->data[0] = 0x09; /* activate rumble */
|
|
- packet->data[1] = 0x08;
|
|
- packet->data[2] = 0x00;
|
|
- packet->data[3] = 0x08; /* continuous effect */
|
|
- packet->data[4] = 0x00; /* simple rumble mode */
|
|
- packet->data[5] = 0x03; /* L and R actuator only */
|
|
- packet->data[6] = 0x00; /* TODO: LT actuator */
|
|
- packet->data[7] = 0x00; /* TODO: RT actuator */
|
|
- packet->data[8] = strong / 256; /* left actuator */
|
|
- packet->data[9] = weak / 256; /* right actuator */
|
|
- packet->data[10] = 0x80; /* length of pulse */
|
|
- packet->data[11] = 0x00; /* stop period of pulse */
|
|
- packet->len = 12;
|
|
+ packet->data[1] = 0x00;
|
|
+ packet->data[2] = xpad->odata_serial++;
|
|
+ packet->data[3] = 0x09;
|
|
+ packet->data[4] = 0x00;
|
|
+ packet->data[5] = 0x0F;
|
|
+ packet->data[6] = 0x00;
|
|
+ packet->data[7] = 0x00;
|
|
+ packet->data[8] = strong / 512; /* left actuator */
|
|
+ packet->data[9] = weak / 512; /* right actuator */
|
|
+ packet->data[10] = 0xFF; /* on period */
|
|
+ packet->data[11] = 0x00; /* off period */
|
|
+ packet->data[12] = 0xFF; /* repeat count */
|
|
+ packet->len = 13;
|
|
packet->pending = true;
|
|
break;
|
|
|
|
@@ -1090,7 +1411,7 @@ static void xpad_send_led_command(struct usb_xpad *xpad, int command)
|
|
*/
|
|
static void xpad_identify_controller(struct usb_xpad *xpad)
|
|
{
|
|
- xpad_send_led_command(xpad, (xpad->pad_nr % 4) + 2);
|
|
+ led_set_brightness(&xpad->led->led_cdev, (xpad->pad_nr % 4) + 2);
|
|
}
|
|
|
|
static void xpad_led_set(struct led_classdev *led_cdev,
|
|
@@ -1127,19 +1448,13 @@ static int xpad_led_probe(struct usb_xpad *xpad)
|
|
led_cdev = &led->led_cdev;
|
|
led_cdev->name = led->name;
|
|
led_cdev->brightness_set = xpad_led_set;
|
|
+ led_cdev->flags = LED_CORE_SUSPENDRESUME;
|
|
|
|
error = led_classdev_register(&xpad->udev->dev, led_cdev);
|
|
if (error)
|
|
goto err_free_id;
|
|
|
|
- if (xpad->xtype == XTYPE_XBOX360) {
|
|
- /*
|
|
- * Light up the segment corresponding to controller
|
|
- * number on wired devices. On wireless we'll do that
|
|
- * when they respond to "presence" packet.
|
|
- */
|
|
- xpad_identify_controller(xpad);
|
|
- }
|
|
+ xpad_identify_controller(xpad);
|
|
|
|
return 0;
|
|
|
|
@@ -1164,41 +1479,110 @@ static void xpad_led_disconnect(struct usb_xpad *xpad)
|
|
#else
|
|
static int xpad_led_probe(struct usb_xpad *xpad) { return 0; }
|
|
static void xpad_led_disconnect(struct usb_xpad *xpad) { }
|
|
-static void xpad_identify_controller(struct usb_xpad *xpad) { }
|
|
#endif
|
|
|
|
-static int xpad_open(struct input_dev *dev)
|
|
+static int xpad_start_input(struct usb_xpad *xpad)
|
|
{
|
|
- struct usb_xpad *xpad = input_get_drvdata(dev);
|
|
-
|
|
- /* URB was submitted in probe */
|
|
- if (xpad->xtype == XTYPE_XBOX360W)
|
|
- return 0;
|
|
+ int error;
|
|
|
|
- xpad->irq_in->dev = xpad->udev;
|
|
if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
|
|
return -EIO;
|
|
|
|
- if (xpad->xtype == XTYPE_XBOXONE)
|
|
- return xpad_start_xbox_one(xpad);
|
|
+ if (xpad->xtype == XTYPE_XBOXONE) {
|
|
+ error = xpad_start_xbox_one(xpad);
|
|
+ if (error) {
|
|
+ usb_kill_urb(xpad->irq_in);
|
|
+ return error;
|
|
+ }
|
|
+ }
|
|
|
|
return 0;
|
|
}
|
|
|
|
-static void xpad_close(struct input_dev *dev)
|
|
+static void xpad_stop_input(struct usb_xpad *xpad)
|
|
{
|
|
- struct usb_xpad *xpad = input_get_drvdata(dev);
|
|
+ usb_kill_urb(xpad->irq_in);
|
|
+}
|
|
|
|
- if (xpad->xtype != XTYPE_XBOX360W)
|
|
+static void xpad360w_poweroff_controller(struct usb_xpad *xpad)
|
|
+{
|
|
+ unsigned long flags;
|
|
+ struct xpad_output_packet *packet =
|
|
+ &xpad->out_packets[XPAD_OUT_CMD_IDX];
|
|
+
|
|
+ spin_lock_irqsave(&xpad->odata_lock, flags);
|
|
+
|
|
+ packet->data[0] = 0x00;
|
|
+ packet->data[1] = 0x00;
|
|
+ packet->data[2] = 0x08;
|
|
+ packet->data[3] = 0xC0;
|
|
+ packet->data[4] = 0x00;
|
|
+ packet->data[5] = 0x00;
|
|
+ packet->data[6] = 0x00;
|
|
+ packet->data[7] = 0x00;
|
|
+ packet->data[8] = 0x00;
|
|
+ packet->data[9] = 0x00;
|
|
+ packet->data[10] = 0x00;
|
|
+ packet->data[11] = 0x00;
|
|
+ packet->len = 12;
|
|
+ packet->pending = true;
|
|
+
|
|
+ /* Reset the sequence so we send out poweroff now */
|
|
+ xpad->last_out_packet = -1;
|
|
+ xpad_try_sending_next_out_packet(xpad);
|
|
+
|
|
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
|
|
+}
|
|
+
|
|
+static int xpad360w_start_input(struct usb_xpad *xpad)
|
|
+{
|
|
+ int error;
|
|
+
|
|
+ error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
|
|
+ if (error)
|
|
+ return -EIO;
|
|
+
|
|
+ /*
|
|
+ * Send presence packet.
|
|
+ * This will force the controller to resend connection packets.
|
|
+ * This is useful in the case we activate the module after the
|
|
+ * adapter has been plugged in, as it won't automatically
|
|
+ * send us info about the controllers.
|
|
+ */
|
|
+ error = xpad_inquiry_pad_presence(xpad);
|
|
+ if (error) {
|
|
usb_kill_urb(xpad->irq_in);
|
|
+ return error;
|
|
+ }
|
|
|
|
- xpad_stop_output(xpad);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void xpad360w_stop_input(struct usb_xpad *xpad)
|
|
+{
|
|
+ usb_kill_urb(xpad->irq_in);
|
|
+
|
|
+ /* Make sure we are done with presence work if it was scheduled */
|
|
+ flush_work(&xpad->work);
|
|
+}
|
|
+
|
|
+static int xpad_open(struct input_dev *dev)
|
|
+{
|
|
+ struct usb_xpad *xpad = input_get_drvdata(dev);
|
|
+
|
|
+ return xpad_start_input(xpad);
|
|
+}
|
|
+
|
|
+static void xpad_close(struct input_dev *dev)
|
|
+{
|
|
+ struct usb_xpad *xpad = input_get_drvdata(dev);
|
|
+
|
|
+ xpad_stop_input(xpad);
|
|
}
|
|
|
|
static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
|
|
{
|
|
struct usb_xpad *xpad = input_get_drvdata(input_dev);
|
|
- set_bit(abs, input_dev->absbit);
|
|
|
|
switch (abs) {
|
|
case ABS_X:
|
|
@@ -1218,13 +1602,19 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
|
|
case ABS_HAT0Y: /* the d-pad (only if dpad is mapped to axes */
|
|
input_set_abs_params(input_dev, abs, -1, 1, 0, 0);
|
|
break;
|
|
+ default:
|
|
+ input_set_abs_params(input_dev, abs, 0, 0, 0, 0);
|
|
+ break;
|
|
}
|
|
}
|
|
|
|
static void xpad_deinit_input(struct usb_xpad *xpad)
|
|
{
|
|
- xpad_led_disconnect(xpad);
|
|
- input_unregister_device(xpad->dev);
|
|
+ if (xpad->input_created) {
|
|
+ xpad->input_created = false;
|
|
+ xpad_led_disconnect(xpad);
|
|
+ input_unregister_device(xpad->dev);
|
|
+ }
|
|
}
|
|
|
|
static int xpad_init_input(struct usb_xpad *xpad)
|
|
@@ -1250,13 +1640,12 @@ static int xpad_init_input(struct usb_xpad *xpad)
|
|
|
|
input_set_drvdata(input_dev, xpad);
|
|
|
|
- input_dev->open = xpad_open;
|
|
- input_dev->close = xpad_close;
|
|
-
|
|
- __set_bit(EV_KEY, input_dev->evbit);
|
|
+ if (xpad->xtype != XTYPE_XBOX360W) {
|
|
+ input_dev->open = xpad_open;
|
|
+ input_dev->close = xpad_close;
|
|
+ }
|
|
|
|
if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
|
|
- __set_bit(EV_ABS, input_dev->evbit);
|
|
/* set up axes */
|
|
for (i = 0; xpad_abs[i] >= 0; i++)
|
|
xpad_set_up_abs(input_dev, xpad_abs[i]);
|
|
@@ -1264,21 +1653,22 @@ static int xpad_init_input(struct usb_xpad *xpad)
|
|
|
|
/* set up standard buttons */
|
|
for (i = 0; xpad_common_btn[i] >= 0; i++)
|
|
- __set_bit(xpad_common_btn[i], input_dev->keybit);
|
|
+ input_set_capability(input_dev, EV_KEY, xpad_common_btn[i]);
|
|
|
|
/* set up model-specific ones */
|
|
if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W ||
|
|
xpad->xtype == XTYPE_XBOXONE) {
|
|
for (i = 0; xpad360_btn[i] >= 0; i++)
|
|
- __set_bit(xpad360_btn[i], input_dev->keybit);
|
|
+ input_set_capability(input_dev, EV_KEY, xpad360_btn[i]);
|
|
} else {
|
|
for (i = 0; xpad_btn[i] >= 0; i++)
|
|
- __set_bit(xpad_btn[i], input_dev->keybit);
|
|
+ input_set_capability(input_dev, EV_KEY, xpad_btn[i]);
|
|
}
|
|
|
|
if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
|
|
for (i = 0; xpad_btn_pad[i] >= 0; i++)
|
|
- __set_bit(xpad_btn_pad[i], input_dev->keybit);
|
|
+ input_set_capability(input_dev, EV_KEY,
|
|
+ xpad_btn_pad[i]);
|
|
}
|
|
|
|
/*
|
|
@@ -1295,7 +1685,8 @@ static int xpad_init_input(struct usb_xpad *xpad)
|
|
|
|
if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
|
|
for (i = 0; xpad_btn_triggers[i] >= 0; i++)
|
|
- __set_bit(xpad_btn_triggers[i], input_dev->keybit);
|
|
+ input_set_capability(input_dev, EV_KEY,
|
|
+ xpad_btn_triggers[i]);
|
|
} else {
|
|
for (i = 0; xpad_abs_triggers[i] >= 0; i++)
|
|
xpad_set_up_abs(input_dev, xpad_abs_triggers[i]);
|
|
@@ -1313,6 +1704,7 @@ static int xpad_init_input(struct usb_xpad *xpad)
|
|
if (error)
|
|
goto err_disconnect_led;
|
|
|
|
+ xpad->input_created = true;
|
|
return 0;
|
|
|
|
err_disconnect_led:
|
|
@@ -1328,8 +1720,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
|
{
|
|
struct usb_device *udev = interface_to_usbdev(intf);
|
|
struct usb_xpad *xpad;
|
|
- struct usb_endpoint_descriptor *ep_irq_in;
|
|
- int ep_irq_in_idx;
|
|
+ struct usb_endpoint_descriptor *ep_irq_in, *ep_irq_out;
|
|
int i, error;
|
|
|
|
if (intf->cur_altsetting->desc.bNumEndpoints != 2)
|
|
@@ -1366,6 +1757,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
|
xpad->mapping = xpad_device[i].mapping;
|
|
xpad->xtype = xpad_device[i].xtype;
|
|
xpad->name = xpad_device[i].name;
|
|
+ INIT_WORK(&xpad->work, xpad_presence_work);
|
|
|
|
if (xpad->xtype == XTYPE_UNKNOWN) {
|
|
if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) {
|
|
@@ -1398,13 +1790,28 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
|
goto err_free_in_urb;
|
|
}
|
|
|
|
- error = xpad_init_output(intf, xpad);
|
|
- if (error)
|
|
+ ep_irq_in = ep_irq_out = NULL;
|
|
+
|
|
+ for (i = 0; i < 2; i++) {
|
|
+ struct usb_endpoint_descriptor *ep =
|
|
+ &intf->cur_altsetting->endpoint[i].desc;
|
|
+
|
|
+ if (usb_endpoint_xfer_int(ep)) {
|
|
+ if (usb_endpoint_dir_in(ep))
|
|
+ ep_irq_in = ep;
|
|
+ else
|
|
+ ep_irq_out = ep;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!ep_irq_in || !ep_irq_out) {
|
|
+ error = -ENODEV;
|
|
goto err_free_in_urb;
|
|
+ }
|
|
|
|
- /* Xbox One controller has in/out endpoints swapped. */
|
|
- ep_irq_in_idx = xpad->xtype == XTYPE_XBOXONE ? 1 : 0;
|
|
- ep_irq_in = &intf->cur_altsetting->endpoint[ep_irq_in_idx].desc;
|
|
+ error = xpad_init_output(intf, xpad, ep_irq_out);
|
|
+ if (error)
|
|
+ goto err_free_in_urb;
|
|
|
|
usb_fill_int_urb(xpad->irq_in, udev,
|
|
usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
|
|
@@ -1415,10 +1822,6 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
|
|
|
usb_set_intfdata(intf, xpad);
|
|
|
|
- error = xpad_init_input(xpad);
|
|
- if (error)
|
|
- goto err_deinit_output;
|
|
-
|
|
if (xpad->xtype == XTYPE_XBOX360W) {
|
|
/*
|
|
* Submit the int URB immediately rather than waiting for open
|
|
@@ -1427,28 +1830,24 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
|
* exactly the message that a controller has arrived that
|
|
* we're waiting for.
|
|
*/
|
|
- xpad->irq_in->dev = xpad->udev;
|
|
- error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
|
|
+ error = xpad360w_start_input(xpad);
|
|
if (error)
|
|
- goto err_deinit_input;
|
|
-
|
|
+ goto err_deinit_output;
|
|
/*
|
|
- * Send presence packet.
|
|
- * This will force the controller to resend connection packets.
|
|
- * This is useful in the case we activate the module after the
|
|
- * adapter has been plugged in, as it won't automatically
|
|
- * send us info about the controllers.
|
|
+ * Wireless controllers require RESET_RESUME to work properly
|
|
+ * after suspend. Ideally this quirk should be in usb core
|
|
+ * quirk list, but we have too many vendors producing these
|
|
+ * controllers and we'd need to maintain 2 identical lists
|
|
+ * here in this driver and in usb core.
|
|
*/
|
|
- error = xpad_inquiry_pad_presence(xpad);
|
|
+ udev->quirks |= USB_QUIRK_RESET_RESUME;
|
|
+ } else {
|
|
+ error = xpad_init_input(xpad);
|
|
if (error)
|
|
- goto err_kill_in_urb;
|
|
+ goto err_deinit_output;
|
|
}
|
|
return 0;
|
|
|
|
-err_kill_in_urb:
|
|
- usb_kill_urb(xpad->irq_in);
|
|
-err_deinit_input:
|
|
- xpad_deinit_input(xpad);
|
|
err_deinit_output:
|
|
xpad_deinit_output(xpad);
|
|
err_free_in_urb:
|
|
@@ -1458,19 +1857,24 @@ err_free_idata:
|
|
err_free_mem:
|
|
kfree(xpad);
|
|
return error;
|
|
-
|
|
}
|
|
|
|
static void xpad_disconnect(struct usb_interface *intf)
|
|
{
|
|
- struct usb_xpad *xpad = usb_get_intfdata (intf);
|
|
+ struct usb_xpad *xpad = usb_get_intfdata(intf);
|
|
+
|
|
+ if (xpad->xtype == XTYPE_XBOX360W)
|
|
+ xpad360w_stop_input(xpad);
|
|
|
|
xpad_deinit_input(xpad);
|
|
- xpad_deinit_output(xpad);
|
|
|
|
- if (xpad->xtype == XTYPE_XBOX360W) {
|
|
- usb_kill_urb(xpad->irq_in);
|
|
- }
|
|
+ /*
|
|
+ * Now that both input device and LED device are gone we can
|
|
+ * stop output URB.
|
|
+ */
|
|
+ xpad_stop_output(xpad);
|
|
+
|
|
+ xpad_deinit_output(xpad);
|
|
|
|
usb_free_urb(xpad->irq_in);
|
|
usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
|
|
@@ -1481,10 +1885,72 @@ static void xpad_disconnect(struct usb_interface *intf)
|
|
usb_set_intfdata(intf, NULL);
|
|
}
|
|
|
|
+static int xpad_suspend(struct usb_interface *intf, pm_message_t message)
|
|
+{
|
|
+ struct usb_xpad *xpad = usb_get_intfdata(intf);
|
|
+ struct input_dev *input = xpad->dev;
|
|
+
|
|
+ if (xpad->xtype == XTYPE_XBOX360W) {
|
|
+ /*
|
|
+ * Wireless controllers always listen to input so
|
|
+ * they are notified when controller shows up
|
|
+ * or goes away.
|
|
+ */
|
|
+ xpad360w_stop_input(xpad);
|
|
+
|
|
+ /*
|
|
+ * The wireless adapter is going off now, so the
|
|
+ * gamepads are going to become disconnected.
|
|
+ * Unless explicitly disabled, power them down
|
|
+ * so they don't just sit there flashing.
|
|
+ */
|
|
+ if (auto_poweroff && xpad->pad_present)
|
|
+ xpad360w_poweroff_controller(xpad);
|
|
+ } else {
|
|
+ mutex_lock(&input->mutex);
|
|
+ if (input->users)
|
|
+ xpad_stop_input(xpad);
|
|
+ mutex_unlock(&input->mutex);
|
|
+ }
|
|
+
|
|
+ xpad_stop_output(xpad);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int xpad_resume(struct usb_interface *intf)
|
|
+{
|
|
+ struct usb_xpad *xpad = usb_get_intfdata(intf);
|
|
+ struct input_dev *input = xpad->dev;
|
|
+ int retval = 0;
|
|
+
|
|
+ if (xpad->xtype == XTYPE_XBOX360W) {
|
|
+ retval = xpad360w_start_input(xpad);
|
|
+ } else {
|
|
+ mutex_lock(&input->mutex);
|
|
+ if (input->users) {
|
|
+ retval = xpad_start_input(xpad);
|
|
+ } else if (xpad->xtype == XTYPE_XBOXONE) {
|
|
+ /*
|
|
+ * Even if there are no users, we'll send Xbox One pads
|
|
+ * the startup sequence so they don't sit there and
|
|
+ * blink until somebody opens the input device again.
|
|
+ */
|
|
+ retval = xpad_start_xbox_one(xpad);
|
|
+ }
|
|
+ mutex_unlock(&input->mutex);
|
|
+ }
|
|
+
|
|
+ return retval;
|
|
+}
|
|
+
|
|
static struct usb_driver xpad_driver = {
|
|
.name = "xpad",
|
|
.probe = xpad_probe,
|
|
.disconnect = xpad_disconnect,
|
|
+ .suspend = xpad_suspend,
|
|
+ .resume = xpad_resume,
|
|
+ .reset_resume = xpad_resume,
|
|
.id_table = xpad_table,
|
|
};
|
|
|
|
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
|
|
index eab132778e67..1dbee1cb3df9 100644
|
|
--- a/drivers/net/can/dev.c
|
|
+++ b/drivers/net/can/dev.c
|
|
@@ -423,6 +423,34 @@ void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
|
|
}
|
|
EXPORT_SYMBOL_GPL(can_put_echo_skb);
|
|
|
|
+struct sk_buff *__can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+ struct sk_buff *skb = priv->echo_skb[idx];
|
|
+ struct canfd_frame *cf;
|
|
+
|
|
+ if (idx >= priv->echo_skb_max) {
|
|
+ netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n",
|
|
+ __func__, idx, priv->echo_skb_max);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (!skb) {
|
|
+ netdev_err(dev, "%s: BUG! Trying to echo non existing skb: can_priv::echo_skb[%u]\n",
|
|
+ __func__, idx);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ /* Using "struct canfd_frame::len" for the frame
|
|
+ * length is supported on both CAN and CANFD frames.
|
|
+ */
|
|
+ cf = (struct canfd_frame *)skb->data;
|
|
+ *len_ptr = cf->len;
|
|
+ priv->echo_skb[idx] = NULL;
|
|
+
|
|
+ return skb;
|
|
+}
|
|
+
|
|
/*
|
|
* Get the skb from the stack and loop it back locally
|
|
*
|
|
@@ -432,22 +460,16 @@ EXPORT_SYMBOL_GPL(can_put_echo_skb);
|
|
*/
|
|
unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx)
|
|
{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
-
|
|
- BUG_ON(idx >= priv->echo_skb_max);
|
|
-
|
|
- if (priv->echo_skb[idx]) {
|
|
- struct sk_buff *skb = priv->echo_skb[idx];
|
|
- struct can_frame *cf = (struct can_frame *)skb->data;
|
|
- u8 dlc = cf->can_dlc;
|
|
+ struct sk_buff *skb;
|
|
+ u8 len;
|
|
|
|
- netif_rx(priv->echo_skb[idx]);
|
|
- priv->echo_skb[idx] = NULL;
|
|
+ skb = __can_get_echo_skb(dev, idx, &len);
|
|
+ if (!skb)
|
|
+ return 0;
|
|
|
|
- return dlc;
|
|
- }
|
|
+ netif_rx(skb);
|
|
|
|
- return 0;
|
|
+ return len;
|
|
}
|
|
EXPORT_SYMBOL_GPL(can_get_echo_skb);
|
|
|
|
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
|
|
index 4c73feca4842..0565efad6e6e 100644
|
|
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
|
|
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
|
|
@@ -491,7 +491,7 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv)
|
|
if (!compat)
|
|
return -ENOMEM;
|
|
|
|
- priv->mdio_dn = of_find_compatible_node(dn, NULL, compat);
|
|
+ priv->mdio_dn = of_get_compatible_child(dn, compat);
|
|
kfree(compat);
|
|
if (!priv->mdio_dn) {
|
|
dev_err(kdev, "unable to find MDIO bus node\n");
|
|
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
|
|
index 4644357d291a..398068ad0b62 100644
|
|
--- a/drivers/net/wireless/ath/ath10k/mac.c
|
|
+++ b/drivers/net/wireless/ath/ath10k/mac.c
|
|
@@ -4470,7 +4470,9 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
|
}
|
|
|
|
ar->free_vdev_map &= ~(1LL << arvif->vdev_id);
|
|
+ spin_lock_bh(&ar->data_lock);
|
|
list_add(&arvif->list, &ar->arvifs);
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
|
|
/* It makes no sense to have firmware do keepalives. mac80211 already
|
|
* takes care of this with idle connection polling.
|
|
@@ -4603,7 +4605,9 @@ err_peer_delete:
|
|
err_vdev_delete:
|
|
ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
|
|
ar->free_vdev_map |= 1LL << arvif->vdev_id;
|
|
+ spin_lock_bh(&ar->data_lock);
|
|
list_del(&arvif->list);
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
|
|
err:
|
|
if (arvif->beacon_buf) {
|
|
@@ -4647,7 +4651,9 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
|
|
arvif->vdev_id, ret);
|
|
|
|
ar->free_vdev_map |= 1LL << arvif->vdev_id;
|
|
+ spin_lock_bh(&ar->data_lock);
|
|
list_del(&arvif->list);
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
|
|
if (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
|
|
arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
|
|
diff --git a/drivers/net/wireless/cw1200/wsm.c b/drivers/net/wireless/cw1200/wsm.c
|
|
index 3dd46c78c1cc..5a595f9f47ff 100644
|
|
--- a/drivers/net/wireless/cw1200/wsm.c
|
|
+++ b/drivers/net/wireless/cw1200/wsm.c
|
|
@@ -1805,16 +1805,18 @@ static int wsm_buf_reserve(struct wsm_buf *buf, size_t extra_size)
|
|
{
|
|
size_t pos = buf->data - buf->begin;
|
|
size_t size = pos + extra_size;
|
|
+ u8 *tmp;
|
|
|
|
size = round_up(size, FWLOAD_BLOCK_SIZE);
|
|
|
|
- buf->begin = krealloc(buf->begin, size, GFP_KERNEL | GFP_DMA);
|
|
- if (buf->begin) {
|
|
- buf->data = &buf->begin[pos];
|
|
- buf->end = &buf->begin[size];
|
|
- return 0;
|
|
- } else {
|
|
- buf->end = buf->data = buf->begin;
|
|
+ tmp = krealloc(buf->begin, size, GFP_KERNEL | GFP_DMA);
|
|
+ if (!tmp) {
|
|
+ wsm_buf_deinit(buf);
|
|
return -ENOMEM;
|
|
}
|
|
+
|
|
+ buf->begin = tmp;
|
|
+ buf->data = &buf->begin[pos];
|
|
+ buf->end = &buf->begin[size];
|
|
+ return 0;
|
|
}
|
|
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
|
|
index 984cd2f05c4a..7b2a7d848a56 100644
|
|
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
|
|
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
|
|
@@ -322,8 +322,12 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
|
|
goto out;
|
|
}
|
|
|
|
- if (changed)
|
|
- *changed = (resp->status == MCC_RESP_NEW_CHAN_PROFILE);
|
|
+ if (changed) {
|
|
+ u32 status = le32_to_cpu(resp->status);
|
|
+
|
|
+ *changed = (status == MCC_RESP_NEW_CHAN_PROFILE ||
|
|
+ status == MCC_RESP_ILLEGAL);
|
|
+ }
|
|
|
|
regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, mvm->cfg,
|
|
__le32_to_cpu(resp->n_channels),
|
|
@@ -4050,10 +4054,6 @@ static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,
|
|
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
|
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
|
|
|
- if (!fw_has_capa(&mvm->fw->ucode_capa,
|
|
- IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
|
|
- return;
|
|
-
|
|
/* if beacon filtering isn't on mac80211 does it anyway */
|
|
if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER))
|
|
return;
|
|
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c
|
|
index 2ee0f6fe56a1..5509c5024352 100644
|
|
--- a/drivers/net/wireless/iwlwifi/mvm/nvm.c
|
|
+++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c
|
|
@@ -667,9 +667,8 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
|
|
|
n_channels = __le32_to_cpu(mcc_resp->n_channels);
|
|
IWL_DEBUG_LAR(mvm,
|
|
- "MCC response status: 0x%x. new MCC: 0x%x ('%c%c') change: %d n_chans: %d\n",
|
|
- status, mcc, mcc >> 8, mcc & 0xff,
|
|
- !!(status == MCC_RESP_NEW_CHAN_PROFILE), n_channels);
|
|
+ "MCC response status: 0x%x. new MCC: 0x%x ('%c%c') n_chans: %d\n",
|
|
+ status, mcc, mcc >> 8, mcc & 0xff, n_channels);
|
|
|
|
resp_len = sizeof(*mcc_resp) + n_channels * sizeof(__le32);
|
|
resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL);
|
|
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
|
|
index 9a8982f581c5..1e074eaf613d 100644
|
|
--- a/drivers/net/wireless/mwifiex/cfg80211.c
|
|
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
|
|
@@ -1150,6 +1150,12 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
|
|
priv->adapter->curr_iface_comb.p2p_intf--;
|
|
priv->adapter->curr_iface_comb.sta_intf++;
|
|
dev->ieee80211_ptr->iftype = type;
|
|
+ if (mwifiex_deinit_priv_params(priv))
|
|
+ return -1;
|
|
+ if (mwifiex_init_new_priv_params(priv, dev, type))
|
|
+ return -1;
|
|
+ if (mwifiex_sta_init_cmd(priv, false, false))
|
|
+ return -1;
|
|
break;
|
|
case NL80211_IFTYPE_ADHOC:
|
|
if (mwifiex_cfg80211_deinit_p2p(priv))
|
|
@@ -2839,8 +2845,10 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
|
|
|
|
mwifiex_stop_net_dev_queue(priv->netdev, adapter);
|
|
|
|
- skb_queue_walk_safe(&priv->bypass_txq, skb, tmp)
|
|
+ skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) {
|
|
+ skb_unlink(skb, &priv->bypass_txq);
|
|
mwifiex_write_data_complete(priv->adapter, skb, 0, -1);
|
|
+ }
|
|
|
|
if (netif_carrier_ok(priv->netdev))
|
|
netif_carrier_off(priv->netdev);
|
|
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
|
|
index acccd6734e3b..ed8b69d1d65c 100644
|
|
--- a/drivers/net/wireless/mwifiex/wmm.c
|
|
+++ b/drivers/net/wireless/mwifiex/wmm.c
|
|
@@ -501,8 +501,10 @@ mwifiex_wmm_del_pkts_in_ralist_node(struct mwifiex_private *priv,
|
|
struct mwifiex_adapter *adapter = priv->adapter;
|
|
struct sk_buff *skb, *tmp;
|
|
|
|
- skb_queue_walk_safe(&ra_list->skb_head, skb, tmp)
|
|
+ skb_queue_walk_safe(&ra_list->skb_head, skb, tmp) {
|
|
+ skb_unlink(skb, &ra_list->skb_head);
|
|
mwifiex_write_data_complete(adapter, skb, 0, -1);
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -598,11 +600,15 @@ mwifiex_clean_txrx(struct mwifiex_private *priv)
|
|
priv->adapter->if_ops.clean_pcie_ring(priv->adapter);
|
|
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
|
|
|
|
- skb_queue_walk_safe(&priv->tdls_txq, skb, tmp)
|
|
+ skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) {
|
|
+ skb_unlink(skb, &priv->tdls_txq);
|
|
mwifiex_write_data_complete(priv->adapter, skb, 0, -1);
|
|
+ }
|
|
|
|
- skb_queue_walk_safe(&priv->bypass_txq, skb, tmp)
|
|
+ skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) {
|
|
+ skb_unlink(skb, &priv->bypass_txq);
|
|
mwifiex_write_data_complete(priv->adapter, skb, 0, -1);
|
|
+ }
|
|
atomic_set(&priv->adapter->bypass_tx_pending, 0);
|
|
|
|
idr_for_each(&priv->ack_status_frames, mwifiex_free_ack_frame, NULL);
|
|
diff --git a/drivers/nfc/nfcmrvl/uart.c b/drivers/nfc/nfcmrvl/uart.c
|
|
index 6c0c301611c4..1b11ded79c4f 100644
|
|
--- a/drivers/nfc/nfcmrvl/uart.c
|
|
+++ b/drivers/nfc/nfcmrvl/uart.c
|
|
@@ -73,10 +73,9 @@ static int nfcmrvl_uart_parse_dt(struct device_node *node,
|
|
struct device_node *matched_node;
|
|
int ret;
|
|
|
|
- matched_node = of_find_compatible_node(node, NULL, "marvell,nfc-uart");
|
|
+ matched_node = of_get_compatible_child(node, "marvell,nfc-uart");
|
|
if (!matched_node) {
|
|
- matched_node = of_find_compatible_node(node, NULL,
|
|
- "mrvl,nfc-uart");
|
|
+ matched_node = of_get_compatible_child(node, "mrvl,nfc-uart");
|
|
if (!matched_node)
|
|
return -ENODEV;
|
|
}
|
|
diff --git a/drivers/of/base.c b/drivers/of/base.c
|
|
index 31341290cd91..c6e019208d17 100644
|
|
--- a/drivers/of/base.c
|
|
+++ b/drivers/of/base.c
|
|
@@ -712,6 +712,31 @@ struct device_node *of_get_next_available_child(const struct device_node *node,
|
|
}
|
|
EXPORT_SYMBOL(of_get_next_available_child);
|
|
|
|
+/**
|
|
+ * of_get_compatible_child - Find compatible child node
|
|
+ * @parent: parent node
|
|
+ * @compatible: compatible string
|
|
+ *
|
|
+ * Lookup child node whose compatible property contains the given compatible
|
|
+ * string.
|
|
+ *
|
|
+ * Returns a node pointer with refcount incremented, use of_node_put() on it
|
|
+ * when done; or NULL if not found.
|
|
+ */
|
|
+struct device_node *of_get_compatible_child(const struct device_node *parent,
|
|
+ const char *compatible)
|
|
+{
|
|
+ struct device_node *child;
|
|
+
|
|
+ for_each_child_of_node(parent, child) {
|
|
+ if (of_device_is_compatible(child, compatible))
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return child;
|
|
+}
|
|
+EXPORT_SYMBOL(of_get_compatible_child);
|
|
+
|
|
/**
|
|
* of_get_child_by_name - Find the child node by name for a given parent
|
|
* @node: parent node
|
|
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
|
|
index 18b19744398a..ff5df33fc740 100644
|
|
--- a/drivers/scsi/qla2xxx/qla_os.c
|
|
+++ b/drivers/scsi/qla2xxx/qla_os.c
|
|
@@ -685,6 +685,11 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
|
|
srb_t *sp;
|
|
int rval;
|
|
|
|
+ if (unlikely(test_bit(UNLOADING, &base_vha->dpc_flags))) {
|
|
+ cmd->result = DID_NO_CONNECT << 16;
|
|
+ goto qc24_fail_command;
|
|
+ }
|
|
+
|
|
if (ha->flags.eeh_busy) {
|
|
if (ha->flags.pci_channel_io_perm_failure) {
|
|
ql_dbg(ql_dbg_aer, vha, 0x9010,
|
|
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
|
|
index 42c459a9d3fe..ce5234555cc9 100644
|
|
--- a/drivers/scsi/ufs/ufs.h
|
|
+++ b/drivers/scsi/ufs/ufs.h
|
|
@@ -45,6 +45,7 @@
|
|
#define QUERY_DESC_MIN_SIZE 2
|
|
#define QUERY_OSF_SIZE (GENERAL_UPIU_REQUEST_SIZE - \
|
|
(sizeof(struct utp_upiu_header)))
|
|
+#define RESPONSE_UPIU_SENSE_DATA_LENGTH 18
|
|
|
|
#define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
|
|
cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
|
|
@@ -383,7 +384,7 @@ struct utp_cmd_rsp {
|
|
__be32 residual_transfer_count;
|
|
__be32 reserved[4];
|
|
__be16 sense_data_len;
|
|
- u8 sense_data[18];
|
|
+ u8 sense_data[RESPONSE_UPIU_SENSE_DATA_LENGTH];
|
|
};
|
|
|
|
/**
|
|
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
|
|
index d15eaa466c59..52b546fb509b 100644
|
|
--- a/drivers/scsi/ufs/ufshcd-pci.c
|
|
+++ b/drivers/scsi/ufs/ufshcd-pci.c
|
|
@@ -104,6 +104,7 @@ static void ufshcd_pci_remove(struct pci_dev *pdev)
|
|
pm_runtime_forbid(&pdev->dev);
|
|
pm_runtime_get_noresume(&pdev->dev);
|
|
ufshcd_remove(hba);
|
|
+ ufshcd_dealloc_host(hba);
|
|
}
|
|
|
|
/**
|
|
@@ -147,6 +148,7 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
err = ufshcd_init(hba, mmio_base, pdev->irq);
|
|
if (err) {
|
|
dev_err(&pdev->dev, "Initialization failed\n");
|
|
+ ufshcd_dealloc_host(hba);
|
|
return err;
|
|
}
|
|
|
|
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
|
|
index 9714f2a8b329..f58abfcdfe81 100644
|
|
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
|
|
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
|
|
@@ -161,7 +161,7 @@ static int ufshcd_populate_vreg(struct device *dev, const char *name,
|
|
if (ret) {
|
|
dev_err(dev, "%s: unable to find %s err %d\n",
|
|
__func__, prop_name, ret);
|
|
- goto out_free;
|
|
+ goto out;
|
|
}
|
|
|
|
vreg->min_uA = 0;
|
|
@@ -183,9 +183,6 @@ static int ufshcd_populate_vreg(struct device *dev, const char *name,
|
|
|
|
goto out;
|
|
|
|
-out_free:
|
|
- devm_kfree(dev, vreg);
|
|
- vreg = NULL;
|
|
out:
|
|
if (!ret)
|
|
*out_vreg = vreg;
|
|
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
|
|
index 8c58adadb728..c94d465de941 100644
|
|
--- a/drivers/scsi/ufs/ufshcd.c
|
|
+++ b/drivers/scsi/ufs/ufshcd.c
|
|
@@ -585,6 +585,21 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
|
|
start:
|
|
switch (hba->clk_gating.state) {
|
|
case CLKS_ON:
|
|
+ /*
|
|
+ * Wait for the ungate work to complete if in progress.
|
|
+ * Though the clocks may be in ON state, the link could
|
|
+ * still be in hibner8 state if hibern8 is allowed
|
|
+ * during clock gating.
|
|
+ * Make sure we exit hibern8 state also in addition to
|
|
+ * clocks being ON.
|
|
+ */
|
|
+ if (ufshcd_can_hibern8_during_gating(hba) &&
|
|
+ ufshcd_is_link_hibern8(hba)) {
|
|
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
|
|
+ flush_work(&hba->clk_gating.ungate_work);
|
|
+ spin_lock_irqsave(hba->host->host_lock, flags);
|
|
+ goto start;
|
|
+ }
|
|
break;
|
|
case REQ_CLKS_OFF:
|
|
if (cancel_delayed_work(&hba->clk_gating.gate_work)) {
|
|
@@ -813,10 +828,14 @@ static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
|
|
int len;
|
|
if (lrbp->sense_buffer &&
|
|
ufshcd_get_rsp_upiu_data_seg_len(lrbp->ucd_rsp_ptr)) {
|
|
+ int len_to_copy;
|
|
+
|
|
len = be16_to_cpu(lrbp->ucd_rsp_ptr->sr.sense_data_len);
|
|
+ len_to_copy = min_t(int, RESPONSE_UPIU_SENSE_DATA_LENGTH, len);
|
|
+
|
|
memcpy(lrbp->sense_buffer,
|
|
lrbp->ucd_rsp_ptr->sr.sense_data,
|
|
- min_t(int, len, SCSI_SENSE_BUFFERSIZE));
|
|
+ min_t(int, len_to_copy, SCSI_SENSE_BUFFERSIZE));
|
|
}
|
|
}
|
|
|
|
@@ -5251,7 +5270,10 @@ EXPORT_SYMBOL(ufshcd_system_suspend);
|
|
|
|
int ufshcd_system_resume(struct ufs_hba *hba)
|
|
{
|
|
- if (!hba || !hba->is_powered || pm_runtime_suspended(hba->dev))
|
|
+ if (!hba)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (!hba->is_powered || pm_runtime_suspended(hba->dev))
|
|
/*
|
|
* Let the runtime resume take care of resuming
|
|
* if runtime suspended.
|
|
@@ -5272,7 +5294,10 @@ EXPORT_SYMBOL(ufshcd_system_resume);
|
|
*/
|
|
int ufshcd_runtime_suspend(struct ufs_hba *hba)
|
|
{
|
|
- if (!hba || !hba->is_powered)
|
|
+ if (!hba)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (!hba->is_powered)
|
|
return 0;
|
|
|
|
return ufshcd_suspend(hba, UFS_RUNTIME_PM);
|
|
@@ -5302,10 +5327,13 @@ EXPORT_SYMBOL(ufshcd_runtime_suspend);
|
|
*/
|
|
int ufshcd_runtime_resume(struct ufs_hba *hba)
|
|
{
|
|
- if (!hba || !hba->is_powered)
|
|
+ if (!hba)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (!hba->is_powered)
|
|
return 0;
|
|
- else
|
|
- return ufshcd_resume(hba, UFS_RUNTIME_PM);
|
|
+
|
|
+ return ufshcd_resume(hba, UFS_RUNTIME_PM);
|
|
}
|
|
EXPORT_SYMBOL(ufshcd_runtime_resume);
|
|
|
|
@@ -5357,8 +5385,6 @@ void ufshcd_remove(struct ufs_hba *hba)
|
|
ufshcd_disable_intr(hba, hba->intr_mask);
|
|
ufshcd_hba_stop(hba);
|
|
|
|
- scsi_host_put(hba->host);
|
|
-
|
|
ufshcd_exit_clk_gating(hba);
|
|
if (ufshcd_is_clkscaling_enabled(hba))
|
|
devfreq_remove_device(hba->devfreq);
|
|
@@ -5483,15 +5509,47 @@ static int ufshcd_devfreq_target(struct device *dev,
|
|
{
|
|
int err = 0;
|
|
struct ufs_hba *hba = dev_get_drvdata(dev);
|
|
+ bool release_clk_hold = false;
|
|
+ unsigned long irq_flags;
|
|
|
|
if (!ufshcd_is_clkscaling_enabled(hba))
|
|
return -EINVAL;
|
|
|
|
+ spin_lock_irqsave(hba->host->host_lock, irq_flags);
|
|
+ if (ufshcd_eh_in_progress(hba)) {
|
|
+ spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (ufshcd_is_clkgating_allowed(hba) &&
|
|
+ (hba->clk_gating.state != CLKS_ON)) {
|
|
+ if (cancel_delayed_work(&hba->clk_gating.gate_work)) {
|
|
+ /* hold the vote until the scaling work is completed */
|
|
+ hba->clk_gating.active_reqs++;
|
|
+ release_clk_hold = true;
|
|
+ hba->clk_gating.state = CLKS_ON;
|
|
+ } else {
|
|
+ /*
|
|
+ * Clock gating work seems to be running in parallel
|
|
+ * hence skip scaling work to avoid deadlock between
|
|
+ * current scaling work and gating work.
|
|
+ */
|
|
+ spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+ spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
|
|
+
|
|
if (*freq == UINT_MAX)
|
|
err = ufshcd_scale_clks(hba, true);
|
|
else if (*freq == 0)
|
|
err = ufshcd_scale_clks(hba, false);
|
|
|
|
+ spin_lock_irqsave(hba->host->host_lock, irq_flags);
|
|
+ if (release_clk_hold)
|
|
+ __ufshcd_release(hba);
|
|
+ spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
|
|
+
|
|
return err;
|
|
}
|
|
|
|
@@ -5673,7 +5731,6 @@ exit_gating:
|
|
ufshcd_exit_clk_gating(hba);
|
|
out_disable:
|
|
hba->is_irq_enabled = false;
|
|
- scsi_host_put(host);
|
|
ufshcd_hba_exit(hba);
|
|
out_error:
|
|
return err;
|
|
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
|
|
index b1ec202099b2..b74de014cef1 100644
|
|
--- a/drivers/tty/n_tty.c
|
|
+++ b/drivers/tty/n_tty.c
|
|
@@ -165,15 +165,29 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
|
|
return put_user(x, ptr);
|
|
}
|
|
|
|
+/* If we are not echoing the data, perhaps this is a secret so erase it */
|
|
+static inline void zero_buffer(struct tty_struct *tty, u8 *buffer, int size)
|
|
+{
|
|
+ bool icanon = !!L_ICANON(tty);
|
|
+ bool no_echo = !L_ECHO(tty);
|
|
+
|
|
+ if (icanon && no_echo)
|
|
+ memset(buffer, 0x00, size);
|
|
+}
|
|
+
|
|
static inline int tty_copy_to_user(struct tty_struct *tty,
|
|
void __user *to,
|
|
- const void *from,
|
|
+ void *from,
|
|
unsigned long n)
|
|
{
|
|
struct n_tty_data *ldata = tty->disc_data;
|
|
+ int retval;
|
|
|
|
tty_audit_add_data(tty, from, n, ldata->icanon);
|
|
- return copy_to_user(to, from, n);
|
|
+ retval = copy_to_user(to, from, n);
|
|
+ if (!retval)
|
|
+ zero_buffer(tty, from, n);
|
|
+ return retval;
|
|
}
|
|
|
|
/**
|
|
@@ -2005,6 +2019,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
|
|
is_eof = n == 1 && read_buf(ldata, tail) == EOF_CHAR(tty);
|
|
tty_audit_add_data(tty, read_buf_addr(ldata, tail), n,
|
|
ldata->icanon);
|
|
+ zero_buffer(tty, read_buf_addr(ldata, tail), n);
|
|
smp_store_release(&ldata->read_tail, ldata->read_tail + n);
|
|
/* Turn single EOF into zero-length read */
|
|
if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
|
|
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
|
|
index 8f3566cde3eb..355e9cad680d 100644
|
|
--- a/drivers/tty/tty_buffer.c
|
|
+++ b/drivers/tty/tty_buffer.c
|
|
@@ -454,6 +454,8 @@ receive_buf(struct tty_struct *tty, struct tty_buffer *head, int count)
|
|
if (count && disc->ops->receive_buf)
|
|
disc->ops->receive_buf(tty, p, f, count);
|
|
}
|
|
+ if (count > 0)
|
|
+ memset(p, 0, count);
|
|
return count;
|
|
}
|
|
|
|
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
|
|
index 2facffea2ee0..f7af730aae82 100644
|
|
--- a/drivers/usb/core/hub.c
|
|
+++ b/drivers/usb/core/hub.c
|
|
@@ -2757,7 +2757,9 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
|
|
USB_PORT_FEAT_C_BH_PORT_RESET);
|
|
usb_clear_port_feature(hub->hdev, port1,
|
|
USB_PORT_FEAT_C_PORT_LINK_STATE);
|
|
- usb_clear_port_feature(hub->hdev, port1,
|
|
+
|
|
+ if (udev)
|
|
+ usb_clear_port_feature(hub->hdev, port1,
|
|
USB_PORT_FEAT_C_CONNECTION);
|
|
|
|
/*
|
|
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
|
|
index aee29604bd79..5d21cd8359d4 100644
|
|
--- a/drivers/usb/host/xhci-hub.c
|
|
+++ b/drivers/usb/host/xhci-hub.c
|
|
@@ -744,7 +744,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
|
|
status |= USB_PORT_STAT_SUSPEND;
|
|
}
|
|
if ((raw_port_status & PORT_PLS_MASK) == XDEV_RESUME &&
|
|
- !DEV_SUPERSPEED_ANY(raw_port_status)) {
|
|
+ !DEV_SUPERSPEED_ANY(raw_port_status) && hcd->speed < HCD_USB3) {
|
|
if ((raw_port_status & PORT_RESET) ||
|
|
!(raw_port_status & PORT_PE))
|
|
return 0xffffffff;
|
|
@@ -790,7 +790,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
|
|
time_left = wait_for_completion_timeout(
|
|
&bus_state->rexit_done[wIndex],
|
|
msecs_to_jiffies(
|
|
- XHCI_MAX_REXIT_TIMEOUT));
|
|
+ XHCI_MAX_REXIT_TIMEOUT_MS));
|
|
spin_lock_irqsave(&xhci->lock, flags);
|
|
|
|
if (time_left) {
|
|
@@ -804,7 +804,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
|
|
} else {
|
|
int port_status = readl(port_array[wIndex]);
|
|
xhci_warn(xhci, "Port resume took longer than %i msec, port status = 0x%x\n",
|
|
- XHCI_MAX_REXIT_TIMEOUT,
|
|
+ XHCI_MAX_REXIT_TIMEOUT_MS,
|
|
port_status);
|
|
status |= USB_PORT_STAT_SUSPEND;
|
|
clear_bit(wIndex, &bus_state->rexit_ports);
|
|
@@ -1298,13 +1298,16 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
|
|
__le32 __iomem **port_array;
|
|
struct xhci_bus_state *bus_state;
|
|
unsigned long flags;
|
|
+ u32 portsc_buf[USB_MAXCHILDREN];
|
|
+ bool wake_enabled;
|
|
|
|
max_ports = xhci_get_ports(hcd, &port_array);
|
|
bus_state = &xhci->bus_state[hcd_index(hcd)];
|
|
+ wake_enabled = hcd->self.root_hub->do_remote_wakeup;
|
|
|
|
spin_lock_irqsave(&xhci->lock, flags);
|
|
|
|
- if (hcd->self.root_hub->do_remote_wakeup) {
|
|
+ if (wake_enabled) {
|
|
if (bus_state->resuming_ports || /* USB2 */
|
|
bus_state->port_remote_wakeup) { /* USB3 */
|
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
|
@@ -1312,26 +1315,36 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
|
|
return -EBUSY;
|
|
}
|
|
}
|
|
-
|
|
- port_index = max_ports;
|
|
+ /*
|
|
+ * Prepare ports for suspend, but don't write anything before all ports
|
|
+ * are checked and we know bus suspend can proceed
|
|
+ */
|
|
bus_state->bus_suspended = 0;
|
|
+ port_index = max_ports;
|
|
while (port_index--) {
|
|
- /* suspend the port if the port is not suspended */
|
|
u32 t1, t2;
|
|
- int slot_id;
|
|
|
|
t1 = readl(port_array[port_index]);
|
|
t2 = xhci_port_state_to_neutral(t1);
|
|
+ portsc_buf[port_index] = 0;
|
|
|
|
- if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) {
|
|
- xhci_dbg(xhci, "port %d not suspended\n", port_index);
|
|
- slot_id = xhci_find_slot_id_by_port(hcd, xhci,
|
|
- port_index + 1);
|
|
- if (slot_id) {
|
|
+ /* Bail out if a USB3 port has a new device in link training */
|
|
+ if ((t1 & PORT_PLS_MASK) == XDEV_POLLING) {
|
|
+ bus_state->bus_suspended = 0;
|
|
+ spin_unlock_irqrestore(&xhci->lock, flags);
|
|
+ xhci_dbg(xhci, "Bus suspend bailout, port in polling\n");
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ /* suspend ports in U0, or bail out for new connect changes */
|
|
+ if ((t1 & PORT_PE) && (t1 & PORT_PLS_MASK) == XDEV_U0) {
|
|
+ if ((t1 & PORT_CSC) && wake_enabled) {
|
|
+ bus_state->bus_suspended = 0;
|
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
|
- xhci_stop_device(xhci, slot_id, 1);
|
|
- spin_lock_irqsave(&xhci->lock, flags);
|
|
+ xhci_dbg(xhci, "Bus suspend bailout, port connect change\n");
|
|
+ return -EBUSY;
|
|
}
|
|
+ xhci_dbg(xhci, "port %d not suspended\n", port_index);
|
|
t2 &= ~PORT_PLS_MASK;
|
|
t2 |= PORT_LINK_STROBE | XDEV_U3;
|
|
set_bit(port_index, &bus_state->bus_suspended);
|
|
@@ -1340,7 +1353,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
|
|
* including the USB 3.0 roothub, but only if CONFIG_PM
|
|
* is enabled, so also enable remote wake here.
|
|
*/
|
|
- if (hcd->self.root_hub->do_remote_wakeup) {
|
|
+ if (wake_enabled) {
|
|
if (t1 & PORT_CONNECT) {
|
|
t2 |= PORT_WKOC_E | PORT_WKDISC_E;
|
|
t2 &= ~PORT_WKCONN_E;
|
|
@@ -1353,7 +1366,26 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
|
|
|
|
t1 = xhci_port_state_to_neutral(t1);
|
|
if (t1 != t2)
|
|
- writel(t2, port_array[port_index]);
|
|
+ portsc_buf[port_index] = t2;
|
|
+ }
|
|
+
|
|
+ /* write port settings, stopping and suspending ports if needed */
|
|
+ port_index = max_ports;
|
|
+ while (port_index--) {
|
|
+ if (!portsc_buf[port_index])
|
|
+ continue;
|
|
+ if (test_bit(port_index, &bus_state->bus_suspended)) {
|
|
+ int slot_id;
|
|
+
|
|
+ slot_id = xhci_find_slot_id_by_port(hcd, xhci,
|
|
+ port_index + 1);
|
|
+ if (slot_id) {
|
|
+ spin_unlock_irqrestore(&xhci->lock, flags);
|
|
+ xhci_stop_device(xhci, slot_id, 1);
|
|
+ spin_lock_irqsave(&xhci->lock, flags);
|
|
+ }
|
|
+ }
|
|
+ writel(portsc_buf[port_index], port_array[port_index]);
|
|
}
|
|
hcd->state = HC_STATE_SUSPENDED;
|
|
bus_state->next_statechange = jiffies + msecs_to_jiffies(10);
|
|
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
|
|
index ece0787d62bf..845fa426fa0d 100644
|
|
--- a/drivers/usb/host/xhci-ring.c
|
|
+++ b/drivers/usb/host/xhci-ring.c
|
|
@@ -1673,7 +1673,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|
* RExit to a disconnect state). If so, let the the driver know it's
|
|
* out of the RExit state.
|
|
*/
|
|
- if (!DEV_SUPERSPEED_ANY(temp) &&
|
|
+ if (!DEV_SUPERSPEED_ANY(temp) && hcd->speed < HCD_USB3 &&
|
|
test_and_clear_bit(faked_port_index,
|
|
&bus_state->rexit_ports)) {
|
|
complete(&bus_state->rexit_done[faked_port_index]);
|
|
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
|
|
index 84d8871755b7..0635cea42e6f 100644
|
|
--- a/drivers/usb/host/xhci.h
|
|
+++ b/drivers/usb/host/xhci.h
|
|
@@ -1490,7 +1490,7 @@ struct xhci_bus_state {
|
|
* It can take up to 20 ms to transition from RExit to U0 on the
|
|
* Intel Lynx Point LP xHCI host.
|
|
*/
|
|
-#define XHCI_MAX_REXIT_TIMEOUT (20 * 1000)
|
|
+#define XHCI_MAX_REXIT_TIMEOUT_MS 20
|
|
|
|
static inline unsigned int hcd_index(struct usb_hcd *hcd)
|
|
{
|
|
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
|
|
index 5cc00e56206e..7d889f56b8e7 100644
|
|
--- a/fs/9p/vfs_dir.c
|
|
+++ b/fs/9p/vfs_dir.c
|
|
@@ -76,15 +76,6 @@ static inline int dt_type(struct p9_wstat *mistat)
|
|
return rettype;
|
|
}
|
|
|
|
-static void p9stat_init(struct p9_wstat *stbuf)
|
|
-{
|
|
- stbuf->name = NULL;
|
|
- stbuf->uid = NULL;
|
|
- stbuf->gid = NULL;
|
|
- stbuf->muid = NULL;
|
|
- stbuf->extension = NULL;
|
|
-}
|
|
-
|
|
/**
|
|
* v9fs_alloc_rdir_buf - Allocate buffer used for read and readdir
|
|
* @filp: opened file structure
|
|
@@ -145,12 +136,10 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
|
|
rdir->tail = n;
|
|
}
|
|
while (rdir->head < rdir->tail) {
|
|
- p9stat_init(&st);
|
|
err = p9stat_read(fid->clnt, rdir->buf + rdir->head,
|
|
rdir->tail - rdir->head, &st);
|
|
if (err) {
|
|
p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
|
|
- p9stat_free(&st);
|
|
return -EIO;
|
|
}
|
|
reclen = st.size+2;
|
|
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
|
|
index fdcb4d69f430..4714c55c1ae5 100644
|
|
--- a/fs/bfs/inode.c
|
|
+++ b/fs/bfs/inode.c
|
|
@@ -350,7 +350,8 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
|
|
|
|
s->s_magic = BFS_MAGIC;
|
|
|
|
- if (le32_to_cpu(bfs_sb->s_start) > le32_to_cpu(bfs_sb->s_end)) {
|
|
+ if (le32_to_cpu(bfs_sb->s_start) > le32_to_cpu(bfs_sb->s_end) ||
|
|
+ le32_to_cpu(bfs_sb->s_start) < BFS_BSIZE) {
|
|
printf("Superblock is corrupted\n");
|
|
goto out1;
|
|
}
|
|
@@ -359,9 +360,11 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
|
|
sizeof(struct bfs_inode)
|
|
+ BFS_ROOT_INO - 1;
|
|
imap_len = (info->si_lasti / 8) + 1;
|
|
- info->si_imap = kzalloc(imap_len, GFP_KERNEL);
|
|
- if (!info->si_imap)
|
|
+ info->si_imap = kzalloc(imap_len, GFP_KERNEL | __GFP_NOWARN);
|
|
+ if (!info->si_imap) {
|
|
+ printf("Cannot allocate %u bytes\n", imap_len);
|
|
goto out1;
|
|
+ }
|
|
for (i = 0; i < BFS_ROOT_INO; i++)
|
|
set_bit(i, info->si_imap);
|
|
|
|
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
|
|
index 80cd28456f08..13ff0fdae03e 100644
|
|
--- a/fs/btrfs/extent-tree.c
|
|
+++ b/fs/btrfs/extent-tree.c
|
|
@@ -10708,17 +10708,9 @@ int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range)
|
|
u64 start;
|
|
u64 end;
|
|
u64 trimmed = 0;
|
|
- u64 total_bytes = btrfs_super_total_bytes(fs_info->super_copy);
|
|
int ret = 0;
|
|
|
|
- /*
|
|
- * try to trim all FS space, our block group may start from non-zero.
|
|
- */
|
|
- if (range->len == total_bytes)
|
|
- cache = btrfs_lookup_first_block_group(fs_info, range->start);
|
|
- else
|
|
- cache = btrfs_lookup_block_group(fs_info, range->start);
|
|
-
|
|
+ cache = btrfs_lookup_first_block_group(fs_info, range->start);
|
|
while (cache) {
|
|
if (cache->key.objectid >= (range->start + range->len)) {
|
|
btrfs_put_block_group(cache);
|
|
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
|
|
index 150d3c891815..3379490ce54d 100644
|
|
--- a/fs/btrfs/ioctl.c
|
|
+++ b/fs/btrfs/ioctl.c
|
|
@@ -378,7 +378,6 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
|
|
struct fstrim_range range;
|
|
u64 minlen = ULLONG_MAX;
|
|
u64 num_devices = 0;
|
|
- u64 total_bytes = btrfs_super_total_bytes(fs_info->super_copy);
|
|
int ret;
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
@@ -402,11 +401,15 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
|
|
return -EOPNOTSUPP;
|
|
if (copy_from_user(&range, arg, sizeof(range)))
|
|
return -EFAULT;
|
|
- if (range.start > total_bytes ||
|
|
- range.len < fs_info->sb->s_blocksize)
|
|
+
|
|
+ /*
|
|
+ * NOTE: Don't truncate the range using super->total_bytes. Bytenr of
|
|
+ * block group is in the logical address space, which can be any
|
|
+ * sectorsize aligned bytenr in the range [0, U64_MAX].
|
|
+ */
|
|
+ if (range.len < fs_info->sb->s_blocksize)
|
|
return -EINVAL;
|
|
|
|
- range.len = min(range.len, total_bytes - range.start);
|
|
range.minlen = max(range.minlen, minlen);
|
|
ret = btrfs_trim_fs(fs_info->tree_root, &range);
|
|
if (ret < 0)
|
|
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
|
|
index d9178388cf48..de7143e2b361 100644
|
|
--- a/fs/gfs2/ops_fstype.c
|
|
+++ b/fs/gfs2/ops_fstype.c
|
|
@@ -71,13 +71,13 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
|
|
if (!sdp)
|
|
return NULL;
|
|
|
|
- sb->s_fs_info = sdp;
|
|
sdp->sd_vfs = sb;
|
|
sdp->sd_lkstats = alloc_percpu(struct gfs2_pcpu_lkstats);
|
|
if (!sdp->sd_lkstats) {
|
|
kfree(sdp);
|
|
return NULL;
|
|
}
|
|
+ sb->s_fs_info = sdp;
|
|
|
|
set_bit(SDF_NOJOURNALID, &sdp->sd_flags);
|
|
gfs2_tune_init(&sdp->sd_tune);
|
|
diff --git a/fs/namei.c b/fs/namei.c
|
|
index de57dd59d95f..40049d61ef37 100644
|
|
--- a/fs/namei.c
|
|
+++ b/fs/namei.c
|
|
@@ -869,6 +869,8 @@ static inline void put_link(struct nameidata *nd)
|
|
|
|
int sysctl_protected_symlinks __read_mostly = 0;
|
|
int sysctl_protected_hardlinks __read_mostly = 0;
|
|
+int sysctl_protected_fifos __read_mostly;
|
|
+int sysctl_protected_regular __read_mostly;
|
|
|
|
/**
|
|
* may_follow_link - Check symlink following for unsafe situations
|
|
@@ -982,6 +984,45 @@ static int may_linkat(struct path *link)
|
|
return -EPERM;
|
|
}
|
|
|
|
+/**
|
|
+ * may_create_in_sticky - Check whether an O_CREAT open in a sticky directory
|
|
+ * should be allowed, or not, on files that already
|
|
+ * exist.
|
|
+ * @dir: the sticky parent directory
|
|
+ * @inode: the inode of the file to open
|
|
+ *
|
|
+ * Block an O_CREAT open of a FIFO (or a regular file) when:
|
|
+ * - sysctl_protected_fifos (or sysctl_protected_regular) is enabled
|
|
+ * - the file already exists
|
|
+ * - we are in a sticky directory
|
|
+ * - we don't own the file
|
|
+ * - the owner of the directory doesn't own the file
|
|
+ * - the directory is world writable
|
|
+ * If the sysctl_protected_fifos (or sysctl_protected_regular) is set to 2
|
|
+ * the directory doesn't have to be world writable: being group writable will
|
|
+ * be enough.
|
|
+ *
|
|
+ * Returns 0 if the open is allowed, -ve on error.
|
|
+ */
|
|
+static int may_create_in_sticky(struct dentry * const dir,
|
|
+ struct inode * const inode)
|
|
+{
|
|
+ if ((!sysctl_protected_fifos && S_ISFIFO(inode->i_mode)) ||
|
|
+ (!sysctl_protected_regular && S_ISREG(inode->i_mode)) ||
|
|
+ likely(!(dir->d_inode->i_mode & S_ISVTX)) ||
|
|
+ uid_eq(inode->i_uid, dir->d_inode->i_uid) ||
|
|
+ uid_eq(current_fsuid(), inode->i_uid))
|
|
+ return 0;
|
|
+
|
|
+ if (likely(dir->d_inode->i_mode & 0002) ||
|
|
+ (dir->d_inode->i_mode & 0020 &&
|
|
+ ((sysctl_protected_fifos >= 2 && S_ISFIFO(inode->i_mode)) ||
|
|
+ (sysctl_protected_regular >= 2 && S_ISREG(inode->i_mode))))) {
|
|
+ return -EACCES;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static __always_inline
|
|
const char *get_link(struct nameidata *nd)
|
|
{
|
|
@@ -3166,9 +3207,15 @@ finish_open:
|
|
error = -ELOOP;
|
|
goto out;
|
|
}
|
|
- error = -EISDIR;
|
|
- if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry))
|
|
- goto out;
|
|
+ if (open_flag & O_CREAT) {
|
|
+ error = -EISDIR;
|
|
+ if (d_is_dir(nd->path.dentry))
|
|
+ goto out;
|
|
+ error = may_create_in_sticky(dir,
|
|
+ d_backing_inode(nd->path.dentry));
|
|
+ if (unlikely(error))
|
|
+ goto out;
|
|
+ }
|
|
error = -ENOTDIR;
|
|
if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry))
|
|
goto out;
|
|
diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h
|
|
index 5f5270941ba0..f7178f44825b 100644
|
|
--- a/include/linux/can/dev.h
|
|
+++ b/include/linux/can/dev.h
|
|
@@ -154,6 +154,7 @@ void can_change_state(struct net_device *dev, struct can_frame *cf,
|
|
|
|
void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
|
|
unsigned int idx);
|
|
+struct sk_buff *__can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr);
|
|
unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx);
|
|
void can_free_echo_skb(struct net_device *dev, unsigned int idx);
|
|
|
|
diff --git a/include/linux/fs.h b/include/linux/fs.h
|
|
index 240cbaee819f..13277d2715df 100644
|
|
--- a/include/linux/fs.h
|
|
+++ b/include/linux/fs.h
|
|
@@ -65,6 +65,8 @@ extern struct inodes_stat_t inodes_stat;
|
|
extern int leases_enable, lease_break_time;
|
|
extern int sysctl_protected_symlinks;
|
|
extern int sysctl_protected_hardlinks;
|
|
+extern int sysctl_protected_fifos;
|
|
+extern int sysctl_protected_regular;
|
|
|
|
struct buffer_head;
|
|
typedef int (get_block_t)(struct inode *inode, sector_t iblock,
|
|
diff --git a/include/linux/of.h b/include/linux/of.h
|
|
index dd10626a615f..d9371c9cd88a 100644
|
|
--- a/include/linux/of.h
|
|
+++ b/include/linux/of.h
|
|
@@ -265,6 +265,8 @@ extern struct device_node *of_get_next_child(const struct device_node *node,
|
|
extern struct device_node *of_get_next_available_child(
|
|
const struct device_node *node, struct device_node *prev);
|
|
|
|
+extern struct device_node *of_get_compatible_child(const struct device_node *parent,
|
|
+ const char *compatible);
|
|
extern struct device_node *of_get_child_by_name(const struct device_node *node,
|
|
const char *name);
|
|
|
|
@@ -462,6 +464,12 @@ static inline bool of_have_populated_dt(void)
|
|
return false;
|
|
}
|
|
|
|
+static inline struct device_node *of_get_compatible_child(const struct device_node *parent,
|
|
+ const char *compatible)
|
|
+{
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
static inline struct device_node *of_get_child_by_name(
|
|
const struct device_node *node,
|
|
const char *name)
|
|
diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c
|
|
index 77777d918676..cc892a9e109d 100644
|
|
--- a/kernel/debug/kdb/kdb_io.c
|
|
+++ b/kernel/debug/kdb/kdb_io.c
|
|
@@ -215,7 +215,7 @@ static char *kdb_read(char *buffer, size_t bufsize)
|
|
int count;
|
|
int i;
|
|
int diag, dtab_count;
|
|
- int key;
|
|
+ int key, buf_size, ret;
|
|
static int last_crlf;
|
|
|
|
diag = kdbgetintenv("DTABCOUNT", &dtab_count);
|
|
@@ -335,9 +335,8 @@ poll_again:
|
|
else
|
|
p_tmp = tmpbuffer;
|
|
len = strlen(p_tmp);
|
|
- count = kallsyms_symbol_complete(p_tmp,
|
|
- sizeof(tmpbuffer) -
|
|
- (p_tmp - tmpbuffer));
|
|
+ buf_size = sizeof(tmpbuffer) - (p_tmp - tmpbuffer);
|
|
+ count = kallsyms_symbol_complete(p_tmp, buf_size);
|
|
if (tab == 2 && count > 0) {
|
|
kdb_printf("\n%d symbols are found.", count);
|
|
if (count > dtab_count) {
|
|
@@ -349,9 +348,13 @@ poll_again:
|
|
}
|
|
kdb_printf("\n");
|
|
for (i = 0; i < count; i++) {
|
|
- if (WARN_ON(!kallsyms_symbol_next(p_tmp, i)))
|
|
+ ret = kallsyms_symbol_next(p_tmp, i, buf_size);
|
|
+ if (WARN_ON(!ret))
|
|
break;
|
|
- kdb_printf("%s ", p_tmp);
|
|
+ if (ret != -E2BIG)
|
|
+ kdb_printf("%s ", p_tmp);
|
|
+ else
|
|
+ kdb_printf("%s... ", p_tmp);
|
|
*(p_tmp + len) = '\0';
|
|
}
|
|
if (i >= dtab_count)
|
|
diff --git a/kernel/debug/kdb/kdb_private.h b/kernel/debug/kdb/kdb_private.h
|
|
index 75014d7f4568..533e04e75a9c 100644
|
|
--- a/kernel/debug/kdb/kdb_private.h
|
|
+++ b/kernel/debug/kdb/kdb_private.h
|
|
@@ -83,7 +83,7 @@ typedef struct __ksymtab {
|
|
unsigned long sym_start;
|
|
unsigned long sym_end;
|
|
} kdb_symtab_t;
|
|
-extern int kallsyms_symbol_next(char *prefix_name, int flag);
|
|
+extern int kallsyms_symbol_next(char *prefix_name, int flag, int buf_size);
|
|
extern int kallsyms_symbol_complete(char *prefix_name, int max_len);
|
|
|
|
/* Exported Symbols for kernel loadable modules to use. */
|
|
diff --git a/kernel/debug/kdb/kdb_support.c b/kernel/debug/kdb/kdb_support.c
|
|
index d35cc2d3a4cc..2aed4a33521b 100644
|
|
--- a/kernel/debug/kdb/kdb_support.c
|
|
+++ b/kernel/debug/kdb/kdb_support.c
|
|
@@ -221,11 +221,13 @@ int kallsyms_symbol_complete(char *prefix_name, int max_len)
|
|
* Parameters:
|
|
* prefix_name prefix of a symbol name to lookup
|
|
* flag 0 means search from the head, 1 means continue search.
|
|
+ * buf_size maximum length that can be written to prefix_name
|
|
+ * buffer
|
|
* Returns:
|
|
* 1 if a symbol matches the given prefix.
|
|
* 0 if no string found
|
|
*/
|
|
-int kallsyms_symbol_next(char *prefix_name, int flag)
|
|
+int kallsyms_symbol_next(char *prefix_name, int flag, int buf_size)
|
|
{
|
|
int prefix_len = strlen(prefix_name);
|
|
static loff_t pos;
|
|
@@ -235,10 +237,8 @@ int kallsyms_symbol_next(char *prefix_name, int flag)
|
|
pos = 0;
|
|
|
|
while ((name = kdb_walk_kallsyms(&pos))) {
|
|
- if (strncmp(name, prefix_name, prefix_len) == 0) {
|
|
- strncpy(prefix_name, name, strlen(name)+1);
|
|
- return 1;
|
|
- }
|
|
+ if (!strncmp(name, prefix_name, prefix_len))
|
|
+ return strscpy(prefix_name, name, buf_size);
|
|
}
|
|
return 0;
|
|
}
|
|
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
|
|
index 4743e1f2a3d1..d0618951014b 100644
|
|
--- a/kernel/sched/core.c
|
|
+++ b/kernel/sched/core.c
|
|
@@ -3822,8 +3822,8 @@ static int __sched_setscheduler(struct task_struct *p,
|
|
struct rq *rq;
|
|
int reset_on_fork;
|
|
|
|
- /* may grab non-irq protected spin_locks */
|
|
- BUG_ON(in_interrupt());
|
|
+ /* The pi code expects interrupts enabled */
|
|
+ BUG_ON(pi && in_interrupt());
|
|
recheck:
|
|
/* double check policy once rq lock held */
|
|
if (policy < 0) {
|
|
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
|
|
index 66100d1bc3f7..7e832f9a8f42 100644
|
|
--- a/kernel/sysctl.c
|
|
+++ b/kernel/sysctl.c
|
|
@@ -1715,6 +1715,24 @@ static struct ctl_table fs_table[] = {
|
|
.extra1 = &zero,
|
|
.extra2 = &one,
|
|
},
|
|
+ {
|
|
+ .procname = "protected_fifos",
|
|
+ .data = &sysctl_protected_fifos,
|
|
+ .maxlen = sizeof(int),
|
|
+ .mode = 0600,
|
|
+ .proc_handler = proc_dointvec_minmax,
|
|
+ .extra1 = &zero,
|
|
+ .extra2 = &two,
|
|
+ },
|
|
+ {
|
|
+ .procname = "protected_regular",
|
|
+ .data = &sysctl_protected_regular,
|
|
+ .maxlen = sizeof(int),
|
|
+ .mode = 0600,
|
|
+ .proc_handler = proc_dointvec_minmax,
|
|
+ .extra1 = &zero,
|
|
+ .extra2 = &two,
|
|
+ },
|
|
{
|
|
.procname = "suid_dumpable",
|
|
.data = &suid_dumpable,
|
|
diff --git a/mm/shmem.c b/mm/shmem.c
|
|
index 8e506a45a6ef..d902b413941a 100644
|
|
--- a/mm/shmem.c
|
|
+++ b/mm/shmem.c
|
|
@@ -1818,9 +1818,7 @@ static loff_t shmem_file_llseek(struct file *file, loff_t offset, int whence)
|
|
mutex_lock(&inode->i_mutex);
|
|
/* We're holding i_mutex so we can access i_size directly */
|
|
|
|
- if (offset < 0)
|
|
- offset = -EINVAL;
|
|
- else if (offset >= inode->i_size)
|
|
+ if (offset < 0 || offset >= inode->i_size)
|
|
offset = -ENXIO;
|
|
else {
|
|
start = offset >> PAGE_CACHE_SHIFT;
|
|
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
|
|
index 83e8a295c806..c153fc2883a8 100644
|
|
--- a/net/llc/af_llc.c
|
|
+++ b/net/llc/af_llc.c
|
|
@@ -726,7 +726,6 @@ static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
|
struct sk_buff *skb = NULL;
|
|
struct sock *sk = sock->sk;
|
|
struct llc_sock *llc = llc_sk(sk);
|
|
- unsigned long cpu_flags;
|
|
size_t copied = 0;
|
|
u32 peek_seq = 0;
|
|
u32 *seq, skb_len;
|
|
@@ -851,9 +850,8 @@ static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
|
goto copy_uaddr;
|
|
|
|
if (!(flags & MSG_PEEK)) {
|
|
- spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags);
|
|
- sk_eat_skb(sk, skb);
|
|
- spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags);
|
|
+ skb_unlink(skb, &sk->sk_receive_queue);
|
|
+ kfree_skb(skb);
|
|
*seq = 0;
|
|
}
|
|
|
|
@@ -874,9 +872,8 @@ copy_uaddr:
|
|
llc_cmsg_rcv(msg, skb);
|
|
|
|
if (!(flags & MSG_PEEK)) {
|
|
- spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags);
|
|
- sk_eat_skb(sk, skb);
|
|
- spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags);
|
|
+ skb_unlink(skb, &sk->sk_receive_queue);
|
|
+ kfree_skb(skb);
|
|
*seq = 0;
|
|
}
|
|
|
|
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
|
|
index 120e9ae04db3..a7967af0da82 100644
|
|
--- a/net/netfilter/nf_tables_api.c
|
|
+++ b/net/netfilter/nf_tables_api.c
|
|
@@ -3452,6 +3452,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
|
|
dreg = nft_type_to_reg(set->dtype);
|
|
list_for_each_entry(binding, &set->bindings, list) {
|
|
struct nft_ctx bind_ctx = {
|
|
+ .net = ctx->net,
|
|
.afi = ctx->afi,
|
|
.table = ctx->table,
|
|
.chain = (struct nft_chain *)binding->chain,
|
|
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
|
|
index a40b8b0ef0d5..f085b01b6603 100644
|
|
--- a/net/sctp/associola.c
|
|
+++ b/net/sctp/associola.c
|
|
@@ -486,8 +486,9 @@ void sctp_assoc_set_primary(struct sctp_association *asoc,
|
|
void sctp_assoc_rm_peer(struct sctp_association *asoc,
|
|
struct sctp_transport *peer)
|
|
{
|
|
- struct list_head *pos;
|
|
- struct sctp_transport *transport;
|
|
+ struct sctp_transport *transport;
|
|
+ struct list_head *pos;
|
|
+ struct sctp_chunk *ch;
|
|
|
|
pr_debug("%s: association:%p addr:%pISpc\n",
|
|
__func__, asoc, &peer->ipaddr.sa);
|
|
@@ -543,7 +544,6 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
|
|
*/
|
|
if (!list_empty(&peer->transmitted)) {
|
|
struct sctp_transport *active = asoc->peer.active_path;
|
|
- struct sctp_chunk *ch;
|
|
|
|
/* Reset the transport of each chunk on this list */
|
|
list_for_each_entry(ch, &peer->transmitted,
|
|
@@ -565,6 +565,10 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
|
|
sctp_transport_hold(active);
|
|
}
|
|
|
|
+ list_for_each_entry(ch, &asoc->outqueue.out_chunk_list, list)
|
|
+ if (ch->transport == peer)
|
|
+ ch->transport = NULL;
|
|
+
|
|
asoc->peer.transport_count--;
|
|
|
|
sctp_transport_free(peer);
|
|
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c
|
|
index 41248b1820c7..cc27e38392ea 100644
|
|
--- a/net/sunrpc/auth_generic.c
|
|
+++ b/net/sunrpc/auth_generic.c
|
|
@@ -272,13 +272,7 @@ static bool generic_key_to_expire(struct rpc_cred *cred)
|
|
{
|
|
struct auth_cred *acred = &container_of(cred, struct generic_cred,
|
|
gc_base)->acred;
|
|
- bool ret;
|
|
-
|
|
- get_rpccred(cred);
|
|
- ret = test_bit(RPC_CRED_KEY_EXPIRE_SOON, &acred->ac_flags);
|
|
- put_rpccred(cred);
|
|
-
|
|
- return ret;
|
|
+ return test_bit(RPC_CRED_KEY_EXPIRE_SOON, &acred->ac_flags);
|
|
}
|
|
|
|
static const struct rpc_credops generic_credops = {
|