5514 lines
168 KiB
Diff
5514 lines
168 KiB
Diff
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
|
|
index e7848a0..e2c7487 100644
|
|
--- a/Documentation/kernel-parameters.txt
|
|
+++ b/Documentation/kernel-parameters.txt
|
|
@@ -2703,6 +2703,13 @@ and is between 256 and 4096 characters. It is defined in the file
|
|
medium is write-protected).
|
|
Example: quirks=0419:aaf5:rl,0421:0433:rc
|
|
|
|
+ userpte=
|
|
+ [X86] Flags controlling user PTE allocations.
|
|
+
|
|
+ nohigh = do not allocate PTE pages in
|
|
+ HIGHMEM regardless of setting
|
|
+ of CONFIG_HIGHPTE.
|
|
+
|
|
vdso= [X86,SH]
|
|
vdso=2: enable compat VDSO (default with COMPAT_VDSO)
|
|
vdso=1: enable VDSO (default)
|
|
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
|
|
index 75afa12..39c0a09 100644
|
|
--- a/Documentation/laptops/thinkpad-acpi.txt
|
|
+++ b/Documentation/laptops/thinkpad-acpi.txt
|
|
@@ -650,6 +650,10 @@ LCD, CRT or DVI (if available). The following commands are available:
|
|
echo expand_toggle > /proc/acpi/ibm/video
|
|
echo video_switch > /proc/acpi/ibm/video
|
|
|
|
+NOTE: Access to this feature is restricted to processes owning the
|
|
+CAP_SYS_ADMIN capability for safety reasons, as it can interact badly
|
|
+enough with some versions of X.org to crash it.
|
|
+
|
|
Each video output device can be enabled or disabled individually.
|
|
Reading /proc/acpi/ibm/video shows the status of each device.
|
|
|
|
diff --git a/arch/Kconfig b/arch/Kconfig
|
|
index 9d055b4..25e69f7 100644
|
|
--- a/arch/Kconfig
|
|
+++ b/arch/Kconfig
|
|
@@ -6,8 +6,6 @@ config OPROFILE
|
|
tristate "OProfile system profiling (EXPERIMENTAL)"
|
|
depends on PROFILING
|
|
depends on HAVE_OPROFILE
|
|
- depends on TRACING_SUPPORT
|
|
- select TRACING
|
|
select RING_BUFFER
|
|
select RING_BUFFER_ALLOW_SWAP
|
|
help
|
|
diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c
|
|
index f9f4724..14531ab 100644
|
|
--- a/arch/x86/ia32/ia32_aout.c
|
|
+++ b/arch/x86/ia32/ia32_aout.c
|
|
@@ -327,7 +327,6 @@ static int load_aout_binary(struct linux_binprm *bprm, struct pt_regs *regs)
|
|
current->mm->free_area_cache = TASK_UNMAPPED_BASE;
|
|
current->mm->cached_hole_size = 0;
|
|
|
|
- current->mm->mmap = NULL;
|
|
install_exec_creds(bprm);
|
|
current->flags &= ~PF_FORKNOEXEC;
|
|
|
|
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h
|
|
index 7c7c16c..5f61f6e 100644
|
|
--- a/arch/x86/include/asm/io_apic.h
|
|
+++ b/arch/x86/include/asm/io_apic.h
|
|
@@ -160,6 +160,7 @@ extern int io_apic_get_redir_entries(int ioapic);
|
|
struct io_apic_irq_attr;
|
|
extern int io_apic_set_pci_routing(struct device *dev, int irq,
|
|
struct io_apic_irq_attr *irq_attr);
|
|
+void setup_IO_APIC_irq_extra(u32 gsi);
|
|
extern int (*ioapic_renumber_irq)(int ioapic, int irq);
|
|
extern void ioapic_init_mappings(void);
|
|
extern void ioapic_insert_resources(void);
|
|
diff --git a/arch/x86/include/asm/pgalloc.h b/arch/x86/include/asm/pgalloc.h
|
|
index 0e8c2a0..271de94 100644
|
|
--- a/arch/x86/include/asm/pgalloc.h
|
|
+++ b/arch/x86/include/asm/pgalloc.h
|
|
@@ -23,6 +23,11 @@ static inline void paravirt_release_pud(unsigned long pfn) {}
|
|
#endif
|
|
|
|
/*
|
|
+ * Flags to use when allocating a user page table page.
|
|
+ */
|
|
+extern gfp_t __userpte_alloc_gfp;
|
|
+
|
|
+/*
|
|
* Allocate and free page tables.
|
|
*/
|
|
extern pgd_t *pgd_alloc(struct mm_struct *);
|
|
diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h
|
|
index 40be813..14cc74b 100644
|
|
--- a/arch/x86/include/asm/uv/uv_hub.h
|
|
+++ b/arch/x86/include/asm/uv/uv_hub.h
|
|
@@ -329,7 +329,8 @@ static inline unsigned long uv_read_global_mmr64(int pnode, unsigned long offset
|
|
*/
|
|
static inline unsigned long uv_global_gru_mmr_address(int pnode, unsigned long offset)
|
|
{
|
|
- return UV_GLOBAL_GRU_MMR_BASE | offset | (pnode << uv_hub_info->m_val);
|
|
+ return UV_GLOBAL_GRU_MMR_BASE | offset |
|
|
+ ((unsigned long)pnode << uv_hub_info->m_val);
|
|
}
|
|
|
|
static inline void uv_write_global_mmr8(int pnode, unsigned long offset, unsigned char val)
|
|
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
|
|
index 2b49454..8f6b011 100644
|
|
--- a/arch/x86/include/asm/vmx.h
|
|
+++ b/arch/x86/include/asm/vmx.h
|
|
@@ -251,6 +251,7 @@ enum vmcs_field {
|
|
#define EXIT_REASON_MSR_READ 31
|
|
#define EXIT_REASON_MSR_WRITE 32
|
|
#define EXIT_REASON_MWAIT_INSTRUCTION 36
|
|
+#define EXIT_REASON_MONITOR_INSTRUCTION 39
|
|
#define EXIT_REASON_PAUSE_INSTRUCTION 40
|
|
#define EXIT_REASON_MCE_DURING_VMENTRY 41
|
|
#define EXIT_REASON_TPR_BELOW_THRESHOLD 43
|
|
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
|
|
index af1c583..0a2b21a 100644
|
|
--- a/arch/x86/kernel/acpi/boot.c
|
|
+++ b/arch/x86/kernel/acpi/boot.c
|
|
@@ -446,6 +446,12 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
|
|
int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
|
|
{
|
|
*irq = gsi;
|
|
+
|
|
+#ifdef CONFIG_X86_IO_APIC
|
|
+ if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC)
|
|
+ setup_IO_APIC_irq_extra(gsi);
|
|
+#endif
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -473,7 +479,8 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
|
|
plat_gsi = mp_register_gsi(dev, gsi, trigger, polarity);
|
|
}
|
|
#endif
|
|
- acpi_gsi_to_irq(plat_gsi, &irq);
|
|
+ irq = plat_gsi;
|
|
+
|
|
return irq;
|
|
}
|
|
|
|
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
|
|
index 53243ca..be37059 100644
|
|
--- a/arch/x86/kernel/apic/io_apic.c
|
|
+++ b/arch/x86/kernel/apic/io_apic.c
|
|
@@ -1539,6 +1539,56 @@ static void __init setup_IO_APIC_irqs(void)
|
|
}
|
|
|
|
/*
|
|
+ * for the gsit that is not in first ioapic
|
|
+ * but could not use acpi_register_gsi()
|
|
+ * like some special sci in IBM x3330
|
|
+ */
|
|
+void setup_IO_APIC_irq_extra(u32 gsi)
|
|
+{
|
|
+ int apic_id = 0, pin, idx, irq;
|
|
+ int node = cpu_to_node(boot_cpu_id);
|
|
+ struct irq_desc *desc;
|
|
+ struct irq_cfg *cfg;
|
|
+
|
|
+ /*
|
|
+ * Convert 'gsi' to 'ioapic.pin'.
|
|
+ */
|
|
+ apic_id = mp_find_ioapic(gsi);
|
|
+ if (apic_id < 0)
|
|
+ return;
|
|
+
|
|
+ pin = mp_find_ioapic_pin(apic_id, gsi);
|
|
+ idx = find_irq_entry(apic_id, pin, mp_INT);
|
|
+ if (idx == -1)
|
|
+ return;
|
|
+
|
|
+ irq = pin_2_irq(idx, apic_id, pin);
|
|
+#ifdef CONFIG_SPARSE_IRQ
|
|
+ desc = irq_to_desc(irq);
|
|
+ if (desc)
|
|
+ return;
|
|
+#endif
|
|
+ desc = irq_to_desc_alloc_node(irq, node);
|
|
+ if (!desc) {
|
|
+ printk(KERN_INFO "can not get irq_desc for %d\n", irq);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ cfg = desc->chip_data;
|
|
+ add_pin_to_irq_node(cfg, node, apic_id, pin);
|
|
+
|
|
+ if (test_bit(pin, mp_ioapic_routing[apic_id].pin_programmed)) {
|
|
+ pr_debug("Pin %d-%d already programmed\n",
|
|
+ mp_ioapics[apic_id].apicid, pin);
|
|
+ return;
|
|
+ }
|
|
+ set_bit(pin, mp_ioapic_routing[apic_id].pin_programmed);
|
|
+
|
|
+ setup_IO_APIC_irq(apic_id, pin, irq, desc,
|
|
+ irq_trigger(idx), irq_polarity(idx));
|
|
+}
|
|
+
|
|
+/*
|
|
* Set up the timer pin, possibly with the 8259A-master behind.
|
|
*/
|
|
static void __init setup_timer_IRQ0_pin(unsigned int apic_id, unsigned int pin,
|
|
@@ -3228,12 +3278,9 @@ unsigned int create_irq_nr(unsigned int irq_want, int node)
|
|
}
|
|
spin_unlock_irqrestore(&vector_lock, flags);
|
|
|
|
- if (irq > 0) {
|
|
- dynamic_irq_init(irq);
|
|
- /* restore it, in case dynamic_irq_init clear it */
|
|
- if (desc_new)
|
|
- desc_new->chip_data = cfg_new;
|
|
- }
|
|
+ if (irq > 0)
|
|
+ dynamic_irq_init_keep_chip_data(irq);
|
|
+
|
|
return irq;
|
|
}
|
|
|
|
@@ -3256,17 +3303,12 @@ void destroy_irq(unsigned int irq)
|
|
{
|
|
unsigned long flags;
|
|
struct irq_cfg *cfg;
|
|
- struct irq_desc *desc;
|
|
|
|
- /* store it, in case dynamic_irq_cleanup clear it */
|
|
- desc = irq_to_desc(irq);
|
|
- cfg = desc->chip_data;
|
|
- dynamic_irq_cleanup(irq);
|
|
- /* connect back irq_cfg */
|
|
- desc->chip_data = cfg;
|
|
+ dynamic_irq_cleanup_keep_chip_data(irq);
|
|
|
|
free_irte(irq);
|
|
spin_lock_irqsave(&vector_lock, flags);
|
|
+ cfg = irq_to_desc(irq)->chip_data;
|
|
__clear_irq_vector(irq, cfg);
|
|
spin_unlock_irqrestore(&vector_lock, flags);
|
|
}
|
|
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
|
|
index 704bddc..8e1aac8 100644
|
|
--- a/arch/x86/kernel/reboot.c
|
|
+++ b/arch/x86/kernel/reboot.c
|
|
@@ -461,6 +461,14 @@ static struct dmi_system_id __initdata pci_reboot_dmi_table[] = {
|
|
DMI_MATCH(DMI_PRODUCT_NAME, "Macmini3,1"),
|
|
},
|
|
},
|
|
+ { /* Handle problems with rebooting on the iMac9,1. */
|
|
+ .callback = set_pci_reboot,
|
|
+ .ident = "Apple iMac9,1",
|
|
+ .matches = {
|
|
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
|
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"),
|
|
+ },
|
|
+ },
|
|
{ }
|
|
};
|
|
|
|
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
|
|
index 7e8faea..c998d27 100644
|
|
--- a/arch/x86/kvm/emulate.c
|
|
+++ b/arch/x86/kvm/emulate.c
|
|
@@ -76,6 +76,7 @@
|
|
#define GroupDual (1<<15) /* Alternate decoding of mod == 3 */
|
|
#define GroupMask 0xff /* Group number stored in bits 0:7 */
|
|
/* Misc flags */
|
|
+#define Priv (1<<27) /* instruction generates #GP if current CPL != 0 */
|
|
#define No64 (1<<28)
|
|
/* Source 2 operand type */
|
|
#define Src2None (0<<29)
|
|
@@ -88,6 +89,7 @@
|
|
enum {
|
|
Group1_80, Group1_81, Group1_82, Group1_83,
|
|
Group1A, Group3_Byte, Group3, Group4, Group5, Group7,
|
|
+ Group8, Group9,
|
|
};
|
|
|
|
static u32 opcode_table[256] = {
|
|
@@ -210,7 +212,7 @@ static u32 opcode_table[256] = {
|
|
SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps,
|
|
/* 0xF0 - 0xF7 */
|
|
0, 0, 0, 0,
|
|
- ImplicitOps, ImplicitOps, Group | Group3_Byte, Group | Group3,
|
|
+ ImplicitOps | Priv, ImplicitOps, Group | Group3_Byte, Group | Group3,
|
|
/* 0xF8 - 0xFF */
|
|
ImplicitOps, 0, ImplicitOps, ImplicitOps,
|
|
ImplicitOps, ImplicitOps, Group | Group4, Group | Group5,
|
|
@@ -218,16 +220,20 @@ static u32 opcode_table[256] = {
|
|
|
|
static u32 twobyte_table[256] = {
|
|
/* 0x00 - 0x0F */
|
|
- 0, Group | GroupDual | Group7, 0, 0, 0, ImplicitOps, ImplicitOps, 0,
|
|
- ImplicitOps, ImplicitOps, 0, 0, 0, ImplicitOps | ModRM, 0, 0,
|
|
+ 0, Group | GroupDual | Group7, 0, 0,
|
|
+ 0, ImplicitOps, ImplicitOps | Priv, 0,
|
|
+ ImplicitOps | Priv, ImplicitOps | Priv, 0, 0,
|
|
+ 0, ImplicitOps | ModRM, 0, 0,
|
|
/* 0x10 - 0x1F */
|
|
0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 0x20 - 0x2F */
|
|
- ModRM | ImplicitOps, ModRM, ModRM | ImplicitOps, ModRM, 0, 0, 0, 0,
|
|
+ ModRM | ImplicitOps | Priv, ModRM | Priv,
|
|
+ ModRM | ImplicitOps | Priv, ModRM | Priv,
|
|
+ 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 0x30 - 0x3F */
|
|
- ImplicitOps, 0, ImplicitOps, 0,
|
|
- ImplicitOps, ImplicitOps, 0, 0,
|
|
+ ImplicitOps | Priv, 0, ImplicitOps | Priv, 0,
|
|
+ ImplicitOps, ImplicitOps | Priv, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 0x40 - 0x47 */
|
|
DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
|
|
@@ -267,11 +273,12 @@ static u32 twobyte_table[256] = {
|
|
0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov,
|
|
DstReg | SrcMem16 | ModRM | Mov,
|
|
/* 0xB8 - 0xBF */
|
|
- 0, 0, DstMem | SrcImmByte | ModRM, DstMem | SrcReg | ModRM | BitOp,
|
|
+ 0, 0, Group | Group8, DstMem | SrcReg | ModRM | BitOp,
|
|
0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov,
|
|
DstReg | SrcMem16 | ModRM | Mov,
|
|
/* 0xC0 - 0xCF */
|
|
- 0, 0, 0, DstMem | SrcReg | ModRM | Mov, 0, 0, 0, ImplicitOps | ModRM,
|
|
+ 0, 0, 0, DstMem | SrcReg | ModRM | Mov,
|
|
+ 0, 0, 0, Group | GroupDual | Group9,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 0xD0 - 0xDF */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
@@ -320,16 +327,24 @@ static u32 group_table[] = {
|
|
SrcMem | ModRM | Stack, 0,
|
|
SrcMem | ModRM | Stack, 0, SrcMem | ModRM | Stack, 0,
|
|
[Group7*8] =
|
|
- 0, 0, ModRM | SrcMem, ModRM | SrcMem,
|
|
+ 0, 0, ModRM | SrcMem | Priv, ModRM | SrcMem | Priv,
|
|
SrcNone | ModRM | DstMem | Mov, 0,
|
|
- SrcMem16 | ModRM | Mov, SrcMem | ModRM | ByteOp,
|
|
+ SrcMem16 | ModRM | Mov | Priv, SrcMem | ModRM | ByteOp | Priv,
|
|
+ [Group8*8] =
|
|
+ 0, 0, 0, 0,
|
|
+ DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM,
|
|
+ DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM,
|
|
+ [Group9*8] =
|
|
+ 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0,
|
|
};
|
|
|
|
static u32 group2_table[] = {
|
|
[Group7*8] =
|
|
- SrcNone | ModRM, 0, 0, SrcNone | ModRM,
|
|
+ SrcNone | ModRM | Priv, 0, 0, SrcNone | ModRM,
|
|
SrcNone | ModRM | DstMem | Mov, 0,
|
|
SrcMem16 | ModRM | Mov, 0,
|
|
+ [Group9*8] =
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0,
|
|
};
|
|
|
|
/* EFLAGS bit definitions. */
|
|
@@ -1640,12 +1655,6 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
|
|
return -1;
|
|
}
|
|
|
|
- /* sysexit must be called from CPL 0 */
|
|
- if (kvm_x86_ops->get_cpl(ctxt->vcpu) != 0) {
|
|
- kvm_inject_gp(ctxt->vcpu, 0);
|
|
- return -1;
|
|
- }
|
|
-
|
|
setup_syscalls_segments(ctxt, &cs, &ss);
|
|
|
|
if ((c->rex_prefix & 0x8) != 0x0)
|
|
@@ -1709,6 +1718,12 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
|
|
memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
|
|
saved_eip = c->eip;
|
|
|
|
+ /* Privileged instruction can be executed only in CPL=0 */
|
|
+ if ((c->d & Priv) && kvm_x86_ops->get_cpl(ctxt->vcpu)) {
|
|
+ kvm_inject_gp(ctxt->vcpu, 0);
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
if (((c->d & ModRM) && (c->modrm_mod != 3)) || (c->d & MemAbs))
|
|
memop = c->modrm_ea;
|
|
|
|
@@ -1982,6 +1997,12 @@ special_insn:
|
|
int err;
|
|
|
|
sel = c->src.val;
|
|
+
|
|
+ if (c->modrm_reg == VCPU_SREG_CS) {
|
|
+ kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
if (c->modrm_reg == VCPU_SREG_SS)
|
|
toggle_interruptibility(ctxt, X86_SHADOW_INT_MOV_SS);
|
|
|
|
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
|
|
index d4918d6..8a8e139 100644
|
|
--- a/arch/x86/kvm/vmx.c
|
|
+++ b/arch/x86/kvm/vmx.c
|
|
@@ -1224,6 +1224,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
|
|
CPU_BASED_USE_IO_BITMAPS |
|
|
CPU_BASED_MOV_DR_EXITING |
|
|
CPU_BASED_USE_TSC_OFFSETING |
|
|
+ CPU_BASED_MWAIT_EXITING |
|
|
+ CPU_BASED_MONITOR_EXITING |
|
|
CPU_BASED_INVLPG_EXITING;
|
|
opt = CPU_BASED_TPR_SHADOW |
|
|
CPU_BASED_USE_MSR_BITMAPS |
|
|
@@ -3416,6 +3418,12 @@ static int handle_pause(struct kvm_vcpu *vcpu)
|
|
return 1;
|
|
}
|
|
|
|
+static int handle_invalid_op(struct kvm_vcpu *vcpu)
|
|
+{
|
|
+ kvm_queue_exception(vcpu, UD_VECTOR);
|
|
+ return 1;
|
|
+}
|
|
+
|
|
/*
|
|
* The exit handlers return 1 if the exit was handled fully and guest execution
|
|
* may resume. Otherwise they set the kvm_run parameter to indicate what needs
|
|
@@ -3453,6 +3461,8 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = {
|
|
[EXIT_REASON_EPT_VIOLATION] = handle_ept_violation,
|
|
[EXIT_REASON_EPT_MISCONFIG] = handle_ept_misconfig,
|
|
[EXIT_REASON_PAUSE_INSTRUCTION] = handle_pause,
|
|
+ [EXIT_REASON_MWAIT_INSTRUCTION] = handle_invalid_op,
|
|
+ [EXIT_REASON_MONITOR_INSTRUCTION] = handle_invalid_op,
|
|
};
|
|
|
|
static const int kvm_vmx_max_exit_handlers =
|
|
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
|
|
index ed34f5e..c9ba9de 100644
|
|
--- a/arch/x86/mm/pgtable.c
|
|
+++ b/arch/x86/mm/pgtable.c
|
|
@@ -6,6 +6,14 @@
|
|
|
|
#define PGALLOC_GFP GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO
|
|
|
|
+#ifdef CONFIG_HIGHPTE
|
|
+#define PGALLOC_USER_GFP __GFP_HIGHMEM
|
|
+#else
|
|
+#define PGALLOC_USER_GFP 0
|
|
+#endif
|
|
+
|
|
+gfp_t __userpte_alloc_gfp = PGALLOC_GFP | PGALLOC_USER_GFP;
|
|
+
|
|
pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
|
|
{
|
|
return (pte_t *)__get_free_page(PGALLOC_GFP);
|
|
@@ -15,16 +23,29 @@ pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)
|
|
{
|
|
struct page *pte;
|
|
|
|
-#ifdef CONFIG_HIGHPTE
|
|
- pte = alloc_pages(PGALLOC_GFP | __GFP_HIGHMEM, 0);
|
|
-#else
|
|
- pte = alloc_pages(PGALLOC_GFP, 0);
|
|
-#endif
|
|
+ pte = alloc_pages(__userpte_alloc_gfp, 0);
|
|
if (pte)
|
|
pgtable_page_ctor(pte);
|
|
return pte;
|
|
}
|
|
|
|
+static int __init setup_userpte(char *arg)
|
|
+{
|
|
+ if (!arg)
|
|
+ return -EINVAL;
|
|
+
|
|
+ /*
|
|
+ * "userpte=nohigh" disables allocation of user pagetables in
|
|
+ * high memory.
|
|
+ */
|
|
+ if (strcmp(arg, "nohigh") == 0)
|
|
+ __userpte_alloc_gfp &= ~__GFP_HIGHMEM;
|
|
+ else
|
|
+ return -EINVAL;
|
|
+ return 0;
|
|
+}
|
|
+early_param("userpte", setup_userpte);
|
|
+
|
|
void ___pte_free_tlb(struct mmu_gather *tlb, struct page *pte)
|
|
{
|
|
pgtable_page_dtor(pte);
|
|
diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c
|
|
index 3347f69..2c505ee 100644
|
|
--- a/arch/x86/oprofile/nmi_int.c
|
|
+++ b/arch/x86/oprofile/nmi_int.c
|
|
@@ -159,7 +159,7 @@ static int nmi_setup_mux(void)
|
|
|
|
for_each_possible_cpu(i) {
|
|
per_cpu(cpu_msrs, i).multiplex =
|
|
- kmalloc(multiplex_size, GFP_KERNEL);
|
|
+ kzalloc(multiplex_size, GFP_KERNEL);
|
|
if (!per_cpu(cpu_msrs, i).multiplex)
|
|
return 0;
|
|
}
|
|
@@ -179,7 +179,6 @@ static void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs)
|
|
if (counter_config[i].enabled) {
|
|
multiplex[i].saved = -(u64)counter_config[i].count;
|
|
} else {
|
|
- multiplex[i].addr = 0;
|
|
multiplex[i].saved = 0;
|
|
}
|
|
}
|
|
@@ -189,25 +188,27 @@ static void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs)
|
|
|
|
static void nmi_cpu_save_mpx_registers(struct op_msrs *msrs)
|
|
{
|
|
+ struct op_msr *counters = msrs->counters;
|
|
struct op_msr *multiplex = msrs->multiplex;
|
|
int i;
|
|
|
|
for (i = 0; i < model->num_counters; ++i) {
|
|
int virt = op_x86_phys_to_virt(i);
|
|
- if (multiplex[virt].addr)
|
|
- rdmsrl(multiplex[virt].addr, multiplex[virt].saved);
|
|
+ if (counters[i].addr)
|
|
+ rdmsrl(counters[i].addr, multiplex[virt].saved);
|
|
}
|
|
}
|
|
|
|
static void nmi_cpu_restore_mpx_registers(struct op_msrs *msrs)
|
|
{
|
|
+ struct op_msr *counters = msrs->counters;
|
|
struct op_msr *multiplex = msrs->multiplex;
|
|
int i;
|
|
|
|
for (i = 0; i < model->num_counters; ++i) {
|
|
int virt = op_x86_phys_to_virt(i);
|
|
- if (multiplex[virt].addr)
|
|
- wrmsrl(multiplex[virt].addr, multiplex[virt].saved);
|
|
+ if (counters[i].addr)
|
|
+ wrmsrl(counters[i].addr, multiplex[virt].saved);
|
|
}
|
|
}
|
|
|
|
@@ -303,11 +304,11 @@ static int allocate_msrs(void)
|
|
|
|
int i;
|
|
for_each_possible_cpu(i) {
|
|
- per_cpu(cpu_msrs, i).counters = kmalloc(counters_size,
|
|
+ per_cpu(cpu_msrs, i).counters = kzalloc(counters_size,
|
|
GFP_KERNEL);
|
|
if (!per_cpu(cpu_msrs, i).counters)
|
|
return 0;
|
|
- per_cpu(cpu_msrs, i).controls = kmalloc(controls_size,
|
|
+ per_cpu(cpu_msrs, i).controls = kzalloc(controls_size,
|
|
GFP_KERNEL);
|
|
if (!per_cpu(cpu_msrs, i).controls)
|
|
return 0;
|
|
diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c
|
|
index 39686c2..1ed963d 100644
|
|
--- a/arch/x86/oprofile/op_model_amd.c
|
|
+++ b/arch/x86/oprofile/op_model_amd.c
|
|
@@ -76,19 +76,6 @@ static struct op_ibs_config ibs_config;
|
|
|
|
#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
|
|
|
|
-static void op_mux_fill_in_addresses(struct op_msrs * const msrs)
|
|
-{
|
|
- int i;
|
|
-
|
|
- for (i = 0; i < NUM_VIRT_COUNTERS; i++) {
|
|
- int hw_counter = op_x86_virt_to_phys(i);
|
|
- if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
|
|
- msrs->multiplex[i].addr = MSR_K7_PERFCTR0 + hw_counter;
|
|
- else
|
|
- msrs->multiplex[i].addr = 0;
|
|
- }
|
|
-}
|
|
-
|
|
static void op_mux_switch_ctrl(struct op_x86_model_spec const *model,
|
|
struct op_msrs const * const msrs)
|
|
{
|
|
@@ -98,7 +85,7 @@ static void op_mux_switch_ctrl(struct op_x86_model_spec const *model,
|
|
/* enable active counters */
|
|
for (i = 0; i < NUM_COUNTERS; ++i) {
|
|
int virt = op_x86_phys_to_virt(i);
|
|
- if (!counter_config[virt].enabled)
|
|
+ if (!reset_value[virt])
|
|
continue;
|
|
rdmsrl(msrs->controls[i].addr, val);
|
|
val &= model->reserved;
|
|
@@ -107,10 +94,6 @@ static void op_mux_switch_ctrl(struct op_x86_model_spec const *model,
|
|
}
|
|
}
|
|
|
|
-#else
|
|
-
|
|
-static inline void op_mux_fill_in_addresses(struct op_msrs * const msrs) { }
|
|
-
|
|
#endif
|
|
|
|
/* functions for op_amd_spec */
|
|
@@ -122,18 +105,12 @@ static void op_amd_fill_in_addresses(struct op_msrs * const msrs)
|
|
for (i = 0; i < NUM_COUNTERS; i++) {
|
|
if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
|
|
msrs->counters[i].addr = MSR_K7_PERFCTR0 + i;
|
|
- else
|
|
- msrs->counters[i].addr = 0;
|
|
}
|
|
|
|
for (i = 0; i < NUM_CONTROLS; i++) {
|
|
if (reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i))
|
|
msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i;
|
|
- else
|
|
- msrs->controls[i].addr = 0;
|
|
}
|
|
-
|
|
- op_mux_fill_in_addresses(msrs);
|
|
}
|
|
|
|
static void op_amd_setup_ctrs(struct op_x86_model_spec const *model,
|
|
@@ -144,7 +121,8 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model,
|
|
|
|
/* setup reset_value */
|
|
for (i = 0; i < NUM_VIRT_COUNTERS; ++i) {
|
|
- if (counter_config[i].enabled)
|
|
+ if (counter_config[i].enabled
|
|
+ && msrs->counters[op_x86_virt_to_phys(i)].addr)
|
|
reset_value[i] = counter_config[i].count;
|
|
else
|
|
reset_value[i] = 0;
|
|
@@ -169,9 +147,7 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model,
|
|
/* enable active counters */
|
|
for (i = 0; i < NUM_COUNTERS; ++i) {
|
|
int virt = op_x86_phys_to_virt(i);
|
|
- if (!counter_config[virt].enabled)
|
|
- continue;
|
|
- if (!msrs->counters[i].addr)
|
|
+ if (!reset_value[virt])
|
|
continue;
|
|
|
|
/* setup counter registers */
|
|
@@ -405,16 +381,6 @@ static int init_ibs_nmi(void)
|
|
return 1;
|
|
}
|
|
|
|
-#ifdef CONFIG_NUMA
|
|
- /* Sanity check */
|
|
- /* Works only for 64bit with proper numa implementation. */
|
|
- if (nodes != num_possible_nodes()) {
|
|
- printk(KERN_DEBUG "Failed to setup CPU node(s) for IBS, "
|
|
- "found: %d, expected %d",
|
|
- nodes, num_possible_nodes());
|
|
- return 1;
|
|
- }
|
|
-#endif
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c
|
|
index ac6b354..e6a160a 100644
|
|
--- a/arch/x86/oprofile/op_model_p4.c
|
|
+++ b/arch/x86/oprofile/op_model_p4.c
|
|
@@ -394,12 +394,6 @@ static void p4_fill_in_addresses(struct op_msrs * const msrs)
|
|
setup_num_counters();
|
|
stag = get_stagger();
|
|
|
|
- /* initialize some registers */
|
|
- for (i = 0; i < num_counters; ++i)
|
|
- msrs->counters[i].addr = 0;
|
|
- for (i = 0; i < num_controls; ++i)
|
|
- msrs->controls[i].addr = 0;
|
|
-
|
|
/* the counter & cccr registers we pay attention to */
|
|
for (i = 0; i < num_counters; ++i) {
|
|
addr = p4_counters[VIRT_CTR(stag, i)].counter_address;
|
|
diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c
|
|
index 8eb0587..2873c00 100644
|
|
--- a/arch/x86/oprofile/op_model_ppro.c
|
|
+++ b/arch/x86/oprofile/op_model_ppro.c
|
|
@@ -37,15 +37,11 @@ static void ppro_fill_in_addresses(struct op_msrs * const msrs)
|
|
for (i = 0; i < num_counters; i++) {
|
|
if (reserve_perfctr_nmi(MSR_P6_PERFCTR0 + i))
|
|
msrs->counters[i].addr = MSR_P6_PERFCTR0 + i;
|
|
- else
|
|
- msrs->counters[i].addr = 0;
|
|
}
|
|
|
|
for (i = 0; i < num_counters; i++) {
|
|
if (reserve_evntsel_nmi(MSR_P6_EVNTSEL0 + i))
|
|
msrs->controls[i].addr = MSR_P6_EVNTSEL0 + i;
|
|
- else
|
|
- msrs->controls[i].addr = 0;
|
|
}
|
|
}
|
|
|
|
@@ -57,7 +53,7 @@ static void ppro_setup_ctrs(struct op_x86_model_spec const *model,
|
|
int i;
|
|
|
|
if (!reset_value) {
|
|
- reset_value = kmalloc(sizeof(reset_value[0]) * num_counters,
|
|
+ reset_value = kzalloc(sizeof(reset_value[0]) * num_counters,
|
|
GFP_ATOMIC);
|
|
if (!reset_value)
|
|
return;
|
|
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
|
|
index b19d1e5..8f3f9a5 100644
|
|
--- a/arch/x86/pci/mmconfig-shared.c
|
|
+++ b/arch/x86/pci/mmconfig-shared.c
|
|
@@ -303,22 +303,17 @@ static void __init pci_mmcfg_check_end_bus_number(void)
|
|
{
|
|
struct pci_mmcfg_region *cfg, *cfgx;
|
|
|
|
- /* last one*/
|
|
- cfg = list_entry(pci_mmcfg_list.prev, typeof(*cfg), list);
|
|
- if (cfg)
|
|
- if (cfg->end_bus < cfg->start_bus)
|
|
- cfg->end_bus = 255;
|
|
-
|
|
- if (list_is_singular(&pci_mmcfg_list))
|
|
- return;
|
|
-
|
|
- /* don't overlap please */
|
|
+ /* Fixup overlaps */
|
|
list_for_each_entry(cfg, &pci_mmcfg_list, list) {
|
|
if (cfg->end_bus < cfg->start_bus)
|
|
cfg->end_bus = 255;
|
|
|
|
+ /* Don't access the list head ! */
|
|
+ if (cfg->list.next == &pci_mmcfg_list)
|
|
+ break;
|
|
+
|
|
cfgx = list_entry(cfg->list.next, typeof(*cfg), list);
|
|
- if (cfg != cfgx && cfg->end_bus >= cfgx->start_bus)
|
|
+ if (cfg->end_bus >= cfgx->start_bus)
|
|
cfg->end_bus = cfgx->start_bus - 1;
|
|
}
|
|
}
|
|
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
|
|
index 36daccb..b607239 100644
|
|
--- a/arch/x86/xen/enlighten.c
|
|
+++ b/arch/x86/xen/enlighten.c
|
|
@@ -50,6 +50,7 @@
|
|
#include <asm/traps.h>
|
|
#include <asm/setup.h>
|
|
#include <asm/desc.h>
|
|
+#include <asm/pgalloc.h>
|
|
#include <asm/pgtable.h>
|
|
#include <asm/tlbflush.h>
|
|
#include <asm/reboot.h>
|
|
@@ -1094,6 +1095,12 @@ asmlinkage void __init xen_start_kernel(void)
|
|
|
|
__supported_pte_mask |= _PAGE_IOMAP;
|
|
|
|
+ /*
|
|
+ * Prevent page tables from being allocated in highmem, even
|
|
+ * if CONFIG_HIGHPTE is enabled.
|
|
+ */
|
|
+ __userpte_alloc_gfp &= ~__GFP_HIGHMEM;
|
|
+
|
|
/* Work out if we support NX */
|
|
x86_configure_nx();
|
|
|
|
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
|
|
index bf4cd6b..350a3de 100644
|
|
--- a/arch/x86/xen/mmu.c
|
|
+++ b/arch/x86/xen/mmu.c
|
|
@@ -1432,14 +1432,15 @@ static void *xen_kmap_atomic_pte(struct page *page, enum km_type type)
|
|
{
|
|
pgprot_t prot = PAGE_KERNEL;
|
|
|
|
+ /*
|
|
+ * We disable highmem allocations for page tables so we should never
|
|
+ * see any calls to kmap_atomic_pte on a highmem page.
|
|
+ */
|
|
+ BUG_ON(PageHighMem(page));
|
|
+
|
|
if (PagePinned(page))
|
|
prot = PAGE_KERNEL_RO;
|
|
|
|
- if (0 && PageHighMem(page))
|
|
- printk("mapping highpte %lx type %d prot %s\n",
|
|
- page_to_pfn(page), type,
|
|
- (unsigned long)pgprot_val(prot) & _PAGE_RW ? "WRITE" : "READ");
|
|
-
|
|
return kmap_atomic_prot(page, type, prot);
|
|
}
|
|
#endif
|
|
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
|
|
index b343903..a6a736a 100644
|
|
--- a/drivers/ata/ahci.c
|
|
+++ b/drivers/ata/ahci.c
|
|
@@ -3082,8 +3082,16 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
ahci_save_initial_config(pdev, hpriv);
|
|
|
|
/* prepare host */
|
|
- if (hpriv->cap & HOST_CAP_NCQ)
|
|
- pi.flags |= ATA_FLAG_NCQ | ATA_FLAG_FPDMA_AA;
|
|
+ if (hpriv->cap & HOST_CAP_NCQ) {
|
|
+ pi.flags |= ATA_FLAG_NCQ;
|
|
+ /* Auto-activate optimization is supposed to be supported on
|
|
+ all AHCI controllers indicating NCQ support, but it seems
|
|
+ to be broken at least on some NVIDIA MCP79 chipsets.
|
|
+ Until we get info on which NVIDIA chipsets don't have this
|
|
+ issue, if any, disable AA on all NVIDIA AHCIs. */
|
|
+ if (pdev->vendor != PCI_VENDOR_ID_NVIDIA)
|
|
+ pi.flags |= ATA_FLAG_FPDMA_AA;
|
|
+ }
|
|
|
|
if (hpriv->cap & HOST_CAP_PMP)
|
|
pi.flags |= ATA_FLAG_PMP;
|
|
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
|
|
index dd26bc7..269b5db 100644
|
|
--- a/drivers/ata/pata_hpt3x2n.c
|
|
+++ b/drivers/ata/pata_hpt3x2n.c
|
|
@@ -25,7 +25,7 @@
|
|
#include <linux/libata.h>
|
|
|
|
#define DRV_NAME "pata_hpt3x2n"
|
|
-#define DRV_VERSION "0.3.8"
|
|
+#define DRV_VERSION "0.3.9"
|
|
|
|
enum {
|
|
HPT_PCI_FAST = (1 << 31),
|
|
@@ -544,16 +544,16 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
|
|
pci_mhz);
|
|
/* Set our private data up. We only need a few flags so we use
|
|
it directly */
|
|
- if (pci_mhz > 60) {
|
|
+ if (pci_mhz > 60)
|
|
hpriv = (void *)(PCI66 | USE_DPLL);
|
|
- /*
|
|
- * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in
|
|
- * the MISC. register to stretch the UltraDMA Tss timing.
|
|
- * NOTE: This register is only writeable via I/O space.
|
|
- */
|
|
- if (dev->device == PCI_DEVICE_ID_TTI_HPT371)
|
|
- outb(inb(iobase + 0x9c) | 0x04, iobase + 0x9c);
|
|
- }
|
|
+
|
|
+ /*
|
|
+ * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in
|
|
+ * the MISC. register to stretch the UltraDMA Tss timing.
|
|
+ * NOTE: This register is only writeable via I/O space.
|
|
+ */
|
|
+ if (dev->device == PCI_DEVICE_ID_TTI_HPT371)
|
|
+ outb(inb(iobase + 0x9c) | 0x04, iobase + 0x9c);
|
|
|
|
/* Now kick off ATA set up */
|
|
return ata_pci_sff_init_one(dev, ppi, &hpt3x2n_sht, hpriv);
|
|
diff --git a/drivers/base/core.c b/drivers/base/core.c
|
|
index 2820257..fb4bc4f 100644
|
|
--- a/drivers/base/core.c
|
|
+++ b/drivers/base/core.c
|
|
@@ -607,6 +607,7 @@ static struct kobject *get_device_parent(struct device *dev,
|
|
int retval;
|
|
|
|
if (dev->class) {
|
|
+ static DEFINE_MUTEX(gdp_mutex);
|
|
struct kobject *kobj = NULL;
|
|
struct kobject *parent_kobj;
|
|
struct kobject *k;
|
|
@@ -623,6 +624,8 @@ static struct kobject *get_device_parent(struct device *dev,
|
|
else
|
|
parent_kobj = &parent->kobj;
|
|
|
|
+ mutex_lock(&gdp_mutex);
|
|
+
|
|
/* find our class-directory at the parent and reference it */
|
|
spin_lock(&dev->class->p->class_dirs.list_lock);
|
|
list_for_each_entry(k, &dev->class->p->class_dirs.list, entry)
|
|
@@ -631,20 +634,26 @@ static struct kobject *get_device_parent(struct device *dev,
|
|
break;
|
|
}
|
|
spin_unlock(&dev->class->p->class_dirs.list_lock);
|
|
- if (kobj)
|
|
+ if (kobj) {
|
|
+ mutex_unlock(&gdp_mutex);
|
|
return kobj;
|
|
+ }
|
|
|
|
/* or create a new class-directory at the parent device */
|
|
k = kobject_create();
|
|
- if (!k)
|
|
+ if (!k) {
|
|
+ mutex_unlock(&gdp_mutex);
|
|
return NULL;
|
|
+ }
|
|
k->kset = &dev->class->p->class_dirs;
|
|
retval = kobject_add(k, parent_kobj, "%s", dev->class->name);
|
|
if (retval < 0) {
|
|
+ mutex_unlock(&gdp_mutex);
|
|
kobject_put(k);
|
|
return NULL;
|
|
}
|
|
/* do not emit an uevent for this simple "glue" directory */
|
|
+ mutex_unlock(&gdp_mutex);
|
|
return k;
|
|
}
|
|
|
|
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
|
|
index 42ae452..dac478c 100644
|
|
--- a/drivers/base/devtmpfs.c
|
|
+++ b/drivers/base/devtmpfs.c
|
|
@@ -301,6 +301,19 @@ int devtmpfs_delete_node(struct device *dev)
|
|
if (dentry->d_inode) {
|
|
err = vfs_getattr(nd.path.mnt, dentry, &stat);
|
|
if (!err && dev_mynode(dev, dentry->d_inode, &stat)) {
|
|
+ struct iattr newattrs;
|
|
+ /*
|
|
+ * before unlinking this node, reset permissions
|
|
+ * of possible references like hardlinks
|
|
+ */
|
|
+ newattrs.ia_uid = 0;
|
|
+ newattrs.ia_gid = 0;
|
|
+ newattrs.ia_mode = stat.mode & ~0777;
|
|
+ newattrs.ia_valid =
|
|
+ ATTR_UID|ATTR_GID|ATTR_MODE;
|
|
+ mutex_lock(&dentry->d_inode->i_mutex);
|
|
+ notify_change(dentry, &newattrs);
|
|
+ mutex_unlock(&dentry->d_inode->i_mutex);
|
|
err = vfs_unlink(nd.path.dentry->d_inode,
|
|
dentry);
|
|
if (!err || err == -ENOENT)
|
|
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
|
|
index 3f653f7..500e740 100644
|
|
--- a/drivers/char/tty_ldisc.c
|
|
+++ b/drivers/char/tty_ldisc.c
|
|
@@ -706,12 +706,13 @@ static void tty_reset_termios(struct tty_struct *tty)
|
|
/**
|
|
* tty_ldisc_reinit - reinitialise the tty ldisc
|
|
* @tty: tty to reinit
|
|
+ * @ldisc: line discipline to reinitialize
|
|
*
|
|
- * Switch the tty back to N_TTY line discipline and leave the
|
|
- * ldisc state closed
|
|
+ * Switch the tty to a line discipline and leave the ldisc
|
|
+ * state closed
|
|
*/
|
|
|
|
-static void tty_ldisc_reinit(struct tty_struct *tty)
|
|
+static void tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
|
|
{
|
|
struct tty_ldisc *ld;
|
|
|
|
@@ -721,10 +722,10 @@ static void tty_ldisc_reinit(struct tty_struct *tty)
|
|
/*
|
|
* Switch the line discipline back
|
|
*/
|
|
- ld = tty_ldisc_get(N_TTY);
|
|
+ ld = tty_ldisc_get(ldisc);
|
|
BUG_ON(IS_ERR(ld));
|
|
tty_ldisc_assign(tty, ld);
|
|
- tty_set_termios_ldisc(tty, N_TTY);
|
|
+ tty_set_termios_ldisc(tty, ldisc);
|
|
}
|
|
|
|
/**
|
|
@@ -745,6 +746,8 @@ static void tty_ldisc_reinit(struct tty_struct *tty)
|
|
void tty_ldisc_hangup(struct tty_struct *tty)
|
|
{
|
|
struct tty_ldisc *ld;
|
|
+ int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
|
|
+ int err = 0;
|
|
|
|
/*
|
|
* FIXME! What are the locking issues here? This may me overdoing
|
|
@@ -772,25 +775,32 @@ void tty_ldisc_hangup(struct tty_struct *tty)
|
|
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
|
|
/*
|
|
* Shutdown the current line discipline, and reset it to
|
|
- * N_TTY.
|
|
+ * N_TTY if need be.
|
|
+ *
|
|
+ * Avoid racing set_ldisc or tty_ldisc_release
|
|
*/
|
|
- if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
|
|
- /* Avoid racing set_ldisc or tty_ldisc_release */
|
|
- mutex_lock(&tty->ldisc_mutex);
|
|
- tty_ldisc_halt(tty);
|
|
- if (tty->ldisc) { /* Not yet closed */
|
|
- /* Switch back to N_TTY */
|
|
- tty_ldisc_reinit(tty);
|
|
- /* At this point we have a closed ldisc and we want to
|
|
- reopen it. We could defer this to the next open but
|
|
- it means auditing a lot of other paths so this is
|
|
- a FIXME */
|
|
+ mutex_lock(&tty->ldisc_mutex);
|
|
+ tty_ldisc_halt(tty);
|
|
+ /* At this point we have a closed ldisc and we want to
|
|
+ reopen it. We could defer this to the next open but
|
|
+ it means auditing a lot of other paths so this is
|
|
+ a FIXME */
|
|
+ if (tty->ldisc) { /* Not yet closed */
|
|
+ if (reset == 0) {
|
|
+ tty_ldisc_reinit(tty, tty->termios->c_line);
|
|
+ err = tty_ldisc_open(tty, tty->ldisc);
|
|
+ }
|
|
+ /* If the re-open fails or we reset then go to N_TTY. The
|
|
+ N_TTY open cannot fail */
|
|
+ if (reset || err) {
|
|
+ tty_ldisc_reinit(tty, N_TTY);
|
|
WARN_ON(tty_ldisc_open(tty, tty->ldisc));
|
|
- tty_ldisc_enable(tty);
|
|
}
|
|
- mutex_unlock(&tty->ldisc_mutex);
|
|
- tty_reset_termios(tty);
|
|
+ tty_ldisc_enable(tty);
|
|
}
|
|
+ mutex_unlock(&tty->ldisc_mutex);
|
|
+ if (reset)
|
|
+ tty_reset_termios(tty);
|
|
}
|
|
|
|
/**
|
|
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
|
|
index 6b3e0c2..6fe4f77 100644
|
|
--- a/drivers/clocksource/sh_cmt.c
|
|
+++ b/drivers/clocksource/sh_cmt.c
|
|
@@ -603,18 +603,13 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
|
|
p->irqaction.handler = sh_cmt_interrupt;
|
|
p->irqaction.dev_id = p;
|
|
p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
|
|
- ret = setup_irq(irq, &p->irqaction);
|
|
- if (ret) {
|
|
- pr_err("sh_cmt: failed to request irq %d\n", irq);
|
|
- goto err1;
|
|
- }
|
|
|
|
/* get hold of clock */
|
|
p->clk = clk_get(&p->pdev->dev, cfg->clk);
|
|
if (IS_ERR(p->clk)) {
|
|
pr_err("sh_cmt: cannot get clock \"%s\"\n", cfg->clk);
|
|
ret = PTR_ERR(p->clk);
|
|
- goto err2;
|
|
+ goto err1;
|
|
}
|
|
|
|
if (resource_size(res) == 6) {
|
|
@@ -627,14 +622,25 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
|
|
p->clear_bits = ~0xc000;
|
|
}
|
|
|
|
- return sh_cmt_register(p, cfg->name,
|
|
- cfg->clockevent_rating,
|
|
- cfg->clocksource_rating);
|
|
- err2:
|
|
- remove_irq(irq, &p->irqaction);
|
|
- err1:
|
|
+ ret = sh_cmt_register(p, cfg->name,
|
|
+ cfg->clockevent_rating,
|
|
+ cfg->clocksource_rating);
|
|
+ if (ret) {
|
|
+ pr_err("sh_cmt: registration failed\n");
|
|
+ goto err1;
|
|
+ }
|
|
+
|
|
+ ret = setup_irq(irq, &p->irqaction);
|
|
+ if (ret) {
|
|
+ pr_err("sh_cmt: failed to request irq %d\n", irq);
|
|
+ goto err1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err1:
|
|
iounmap(p->mapbase);
|
|
- err0:
|
|
+err0:
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c
|
|
index 973e714..4c8a759 100644
|
|
--- a/drivers/clocksource/sh_mtu2.c
|
|
+++ b/drivers/clocksource/sh_mtu2.c
|
|
@@ -221,15 +221,15 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_priv *p,
|
|
ced->cpumask = cpumask_of(0);
|
|
ced->set_mode = sh_mtu2_clock_event_mode;
|
|
|
|
+ pr_info("sh_mtu2: %s used for clock events\n", ced->name);
|
|
+ clockevents_register_device(ced);
|
|
+
|
|
ret = setup_irq(p->irqaction.irq, &p->irqaction);
|
|
if (ret) {
|
|
pr_err("sh_mtu2: failed to request irq %d\n",
|
|
p->irqaction.irq);
|
|
return;
|
|
}
|
|
-
|
|
- pr_info("sh_mtu2: %s used for clock events\n", ced->name);
|
|
- clockevents_register_device(ced);
|
|
}
|
|
|
|
static int sh_mtu2_register(struct sh_mtu2_priv *p, char *name,
|
|
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c
|
|
index 93c2322..961f5b5 100644
|
|
--- a/drivers/clocksource/sh_tmu.c
|
|
+++ b/drivers/clocksource/sh_tmu.c
|
|
@@ -323,15 +323,15 @@ static void sh_tmu_register_clockevent(struct sh_tmu_priv *p,
|
|
ced->set_next_event = sh_tmu_clock_event_next;
|
|
ced->set_mode = sh_tmu_clock_event_mode;
|
|
|
|
+ pr_info("sh_tmu: %s used for clock events\n", ced->name);
|
|
+ clockevents_register_device(ced);
|
|
+
|
|
ret = setup_irq(p->irqaction.irq, &p->irqaction);
|
|
if (ret) {
|
|
pr_err("sh_tmu: failed to request irq %d\n",
|
|
p->irqaction.irq);
|
|
return;
|
|
}
|
|
-
|
|
- pr_info("sh_tmu: %s used for clock events\n", ced->name);
|
|
- clockevents_register_device(ced);
|
|
}
|
|
|
|
static int sh_tmu_register(struct sh_tmu_priv *p, char *name,
|
|
diff --git a/drivers/gpio/cs5535-gpio.c b/drivers/gpio/cs5535-gpio.c
|
|
index 0fdbe94..0c3c498 100644
|
|
--- a/drivers/gpio/cs5535-gpio.c
|
|
+++ b/drivers/gpio/cs5535-gpio.c
|
|
@@ -154,7 +154,7 @@ static int chip_gpio_request(struct gpio_chip *c, unsigned offset)
|
|
|
|
static int chip_gpio_get(struct gpio_chip *chip, unsigned offset)
|
|
{
|
|
- return cs5535_gpio_isset(offset, GPIO_OUTPUT_VAL);
|
|
+ return cs5535_gpio_isset(offset, GPIO_READ_BACK);
|
|
}
|
|
|
|
static void chip_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
|
|
@@ -172,6 +172,7 @@ static int chip_direction_input(struct gpio_chip *c, unsigned offset)
|
|
|
|
spin_lock_irqsave(&chip->lock, flags);
|
|
__cs5535_gpio_set(chip, offset, GPIO_INPUT_ENABLE);
|
|
+ __cs5535_gpio_clear(chip, offset, GPIO_OUTPUT_ENABLE);
|
|
spin_unlock_irqrestore(&chip->lock, flags);
|
|
|
|
return 0;
|
|
@@ -184,6 +185,7 @@ static int chip_direction_output(struct gpio_chip *c, unsigned offset, int val)
|
|
|
|
spin_lock_irqsave(&chip->lock, flags);
|
|
|
|
+ __cs5535_gpio_set(chip, offset, GPIO_INPUT_ENABLE);
|
|
__cs5535_gpio_set(chip, offset, GPIO_OUTPUT_ENABLE);
|
|
if (val)
|
|
__cs5535_gpio_set(chip, offset, GPIO_OUTPUT_VAL);
|
|
diff --git a/drivers/gpio/wm831x-gpio.c b/drivers/gpio/wm831x-gpio.c
|
|
index b4468b6..c5a00f7 100644
|
|
--- a/drivers/gpio/wm831x-gpio.c
|
|
+++ b/drivers/gpio/wm831x-gpio.c
|
|
@@ -60,23 +60,31 @@ static int wm831x_gpio_get(struct gpio_chip *chip, unsigned offset)
|
|
return 0;
|
|
}
|
|
|
|
-static int wm831x_gpio_direction_out(struct gpio_chip *chip,
|
|
- unsigned offset, int value)
|
|
+static void wm831x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
|
{
|
|
struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
|
|
struct wm831x *wm831x = wm831x_gpio->wm831x;
|
|
|
|
- return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset,
|
|
- WM831X_GPN_DIR | WM831X_GPN_TRI, 0);
|
|
+ wm831x_set_bits(wm831x, WM831X_GPIO_LEVEL, 1 << offset,
|
|
+ value << offset);
|
|
}
|
|
|
|
-static void wm831x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
|
+static int wm831x_gpio_direction_out(struct gpio_chip *chip,
|
|
+ unsigned offset, int value)
|
|
{
|
|
struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
|
|
struct wm831x *wm831x = wm831x_gpio->wm831x;
|
|
+ int ret;
|
|
|
|
- wm831x_set_bits(wm831x, WM831X_GPIO_LEVEL, 1 << offset,
|
|
- value << offset);
|
|
+ ret = wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset,
|
|
+ WM831X_GPN_DIR | WM831X_GPN_TRI, 0);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ /* Can only set GPIO state once it's in output mode */
|
|
+ wm831x_gpio_set(chip, offset, value);
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
static int wm831x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
|
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
|
|
index c2e8a45..93031a7 100644
|
|
--- a/drivers/gpu/drm/i915/intel_lvds.c
|
|
+++ b/drivers/gpu/drm/i915/intel_lvds.c
|
|
@@ -655,8 +655,15 @@ static const struct dmi_system_id bad_lid_status[] = {
|
|
*/
|
|
static enum drm_connector_status intel_lvds_detect(struct drm_connector *connector)
|
|
{
|
|
+ struct drm_device *dev = connector->dev;
|
|
enum drm_connector_status status = connector_status_connected;
|
|
|
|
+ /* ACPI lid methods were generally unreliable in this generation, so
|
|
+ * don't even bother.
|
|
+ */
|
|
+ if (IS_I8XX(dev))
|
|
+ return connector_status_connected;
|
|
+
|
|
if (!dmi_check_system(bad_lid_status) && !acpi_lid_open())
|
|
status = connector_status_disconnected;
|
|
|
|
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
|
|
index 82678d3..48daee5 100644
|
|
--- a/drivers/gpu/drm/i915/intel_sdvo.c
|
|
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
|
|
@@ -35,6 +35,7 @@
|
|
#include "i915_drm.h"
|
|
#include "i915_drv.h"
|
|
#include "intel_sdvo_regs.h"
|
|
+#include <linux/dmi.h>
|
|
|
|
static char *tv_format_names[] = {
|
|
"NTSC_M" , "NTSC_J" , "NTSC_443",
|
|
@@ -2283,6 +2284,25 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device)
|
|
return 0x72;
|
|
}
|
|
|
|
+static int intel_sdvo_bad_tv_callback(const struct dmi_system_id *id)
|
|
+{
|
|
+ DRM_DEBUG_KMS("Ignoring bad SDVO TV connector for %s\n", id->ident);
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static struct dmi_system_id intel_sdvo_bad_tv[] = {
|
|
+ {
|
|
+ .callback = intel_sdvo_bad_tv_callback,
|
|
+ .ident = "IntelG45/ICH10R/DME1737",
|
|
+ .matches = {
|
|
+ DMI_MATCH(DMI_SYS_VENDOR, "IBM CORPORATION"),
|
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "4800784"),
|
|
+ },
|
|
+ },
|
|
+
|
|
+ { } /* terminating entry */
|
|
+};
|
|
+
|
|
static bool
|
|
intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
|
|
{
|
|
@@ -2323,7 +2343,8 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
|
|
(1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
|
|
(1 << INTEL_ANALOG_CLONE_BIT);
|
|
}
|
|
- } else if (flags & SDVO_OUTPUT_SVID0) {
|
|
+ } else if ((flags & SDVO_OUTPUT_SVID0) &&
|
|
+ !dmi_check_system(intel_sdvo_bad_tv)) {
|
|
|
|
sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0;
|
|
encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
|
|
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c
|
|
index 7f152f6..d75788f 100644
|
|
--- a/drivers/gpu/drm/radeon/atom.c
|
|
+++ b/drivers/gpu/drm/radeon/atom.c
|
|
@@ -881,8 +881,6 @@ static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
|
|
uint8_t attr = U8((*ptr)++), shift;
|
|
uint32_t saved, dst;
|
|
int dptr = *ptr;
|
|
- attr &= 0x38;
|
|
- attr |= atom_def_dst[attr >> 3] << 6;
|
|
SDEBUG(" dst: ");
|
|
dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
|
|
shift = atom_get_src(ctx, attr, ptr);
|
|
@@ -897,8 +895,6 @@ static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
|
|
uint8_t attr = U8((*ptr)++), shift;
|
|
uint32_t saved, dst;
|
|
int dptr = *ptr;
|
|
- attr &= 0x38;
|
|
- attr |= atom_def_dst[attr >> 3] << 6;
|
|
SDEBUG(" dst: ");
|
|
dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
|
|
shift = atom_get_src(ctx, attr, ptr);
|
|
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
|
|
index 3d47a2c..a759170 100644
|
|
--- a/drivers/gpu/drm/ttm/ttm_tt.c
|
|
+++ b/drivers/gpu/drm/ttm/ttm_tt.c
|
|
@@ -480,7 +480,7 @@ static int ttm_tt_swapin(struct ttm_tt *ttm)
|
|
void *from_virtual;
|
|
void *to_virtual;
|
|
int i;
|
|
- int ret;
|
|
+ int ret = -ENOMEM;
|
|
|
|
if (ttm->page_flags & TTM_PAGE_FLAG_USER) {
|
|
ret = ttm_tt_set_user(ttm, ttm->tsk, ttm->start,
|
|
@@ -499,8 +499,10 @@ static int ttm_tt_swapin(struct ttm_tt *ttm)
|
|
|
|
for (i = 0; i < ttm->num_pages; ++i) {
|
|
from_page = read_mapping_page(swap_space, i, NULL);
|
|
- if (IS_ERR(from_page))
|
|
+ if (IS_ERR(from_page)) {
|
|
+ ret = PTR_ERR(from_page);
|
|
goto out_err;
|
|
+ }
|
|
to_page = __ttm_tt_get_page(ttm, i);
|
|
if (unlikely(to_page == NULL))
|
|
goto out_err;
|
|
@@ -523,7 +525,7 @@ static int ttm_tt_swapin(struct ttm_tt *ttm)
|
|
return 0;
|
|
out_err:
|
|
ttm_tt_free_alloced_pages(ttm);
|
|
- return -ENOMEM;
|
|
+ return ret;
|
|
}
|
|
|
|
int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage)
|
|
@@ -535,6 +537,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage)
|
|
void *from_virtual;
|
|
void *to_virtual;
|
|
int i;
|
|
+ int ret = -ENOMEM;
|
|
|
|
BUG_ON(ttm->state != tt_unbound && ttm->state != tt_unpopulated);
|
|
BUG_ON(ttm->caching_state != tt_cached);
|
|
@@ -557,7 +560,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage)
|
|
0);
|
|
if (unlikely(IS_ERR(swap_storage))) {
|
|
printk(KERN_ERR "Failed allocating swap storage.\n");
|
|
- return -ENOMEM;
|
|
+ return PTR_ERR(swap_storage);
|
|
}
|
|
} else
|
|
swap_storage = persistant_swap_storage;
|
|
@@ -569,9 +572,10 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage)
|
|
if (unlikely(from_page == NULL))
|
|
continue;
|
|
to_page = read_mapping_page(swap_space, i, NULL);
|
|
- if (unlikely(to_page == NULL))
|
|
+ if (unlikely(IS_ERR(to_page))) {
|
|
+ ret = PTR_ERR(to_page);
|
|
goto out_err;
|
|
-
|
|
+ }
|
|
preempt_disable();
|
|
from_virtual = kmap_atomic(from_page, KM_USER0);
|
|
to_virtual = kmap_atomic(to_page, KM_USER1);
|
|
@@ -595,5 +599,5 @@ out_err:
|
|
if (!persistant_swap_storage)
|
|
fput(swap_storage);
|
|
|
|
- return -ENOMEM;
|
|
+ return ret;
|
|
}
|
|
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
|
|
index eabe5f8..8455f3d 100644
|
|
--- a/drivers/hid/hid-core.c
|
|
+++ b/drivers/hid/hid-core.c
|
|
@@ -1661,8 +1661,6 @@ static const struct hid_device_id hid_ignore_list[] = {
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) },
|
|
- { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY1) },
|
|
- { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY2) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
|
|
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
|
|
index 010368e..793691f 100644
|
|
--- a/drivers/hid/hid-ids.h
|
|
+++ b/drivers/hid/hid-ids.h
|
|
@@ -402,10 +402,6 @@
|
|
#define USB_VENDOR_ID_SUNPLUS 0x04fc
|
|
#define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8
|
|
|
|
-#define USB_VENDOR_ID_TENX 0x1130
|
|
-#define USB_DEVICE_ID_TENX_IBUDDY1 0x0001
|
|
-#define USB_DEVICE_ID_TENX_IBUDDY2 0x0002
|
|
-
|
|
#define USB_VENDOR_ID_THRUSTMASTER 0x044f
|
|
|
|
#define USB_VENDOR_ID_TOPMAX 0x0663
|
|
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
|
|
index e2997a8..2f84237 100644
|
|
--- a/drivers/hid/usbhid/hid-core.c
|
|
+++ b/drivers/hid/usbhid/hid-core.c
|
|
@@ -316,6 +316,7 @@ static int hid_submit_out(struct hid_device *hid)
|
|
err_hid("usb_submit_urb(out) failed");
|
|
return -1;
|
|
}
|
|
+ usbhid->last_out = jiffies;
|
|
} else {
|
|
/*
|
|
* queue work to wake up the device.
|
|
@@ -377,6 +378,7 @@ static int hid_submit_ctrl(struct hid_device *hid)
|
|
err_hid("usb_submit_urb(ctrl) failed");
|
|
return -1;
|
|
}
|
|
+ usbhid->last_ctrl = jiffies;
|
|
} else {
|
|
/*
|
|
* queue work to wake up the device.
|
|
@@ -512,9 +514,20 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
|
|
usbhid->out[usbhid->outhead].report = report;
|
|
usbhid->outhead = head;
|
|
|
|
- if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl))
|
|
+ if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) {
|
|
if (hid_submit_out(hid))
|
|
clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
|
|
+ } else {
|
|
+ /*
|
|
+ * the queue is known to run
|
|
+ * but an earlier request may be stuck
|
|
+ * we may need to time out
|
|
+ * no race because this is called under
|
|
+ * spinlock
|
|
+ */
|
|
+ if (time_after(jiffies, usbhid->last_out + HZ * 5))
|
|
+ usb_unlink_urb(usbhid->urbout);
|
|
+ }
|
|
return;
|
|
}
|
|
|
|
@@ -535,9 +548,20 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
|
|
usbhid->ctrl[usbhid->ctrlhead].dir = dir;
|
|
usbhid->ctrlhead = head;
|
|
|
|
- if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl))
|
|
+ if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) {
|
|
if (hid_submit_ctrl(hid))
|
|
clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
|
|
+ } else {
|
|
+ /*
|
|
+ * the queue is known to run
|
|
+ * but an earlier request may be stuck
|
|
+ * we may need to time out
|
|
+ * no race because this is called under
|
|
+ * spinlock
|
|
+ */
|
|
+ if (time_after(jiffies, usbhid->last_ctrl + HZ * 5))
|
|
+ usb_unlink_urb(usbhid->urbctrl);
|
|
+ }
|
|
}
|
|
|
|
void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
|
|
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
|
|
index 08f505c..ec20400 100644
|
|
--- a/drivers/hid/usbhid/usbhid.h
|
|
+++ b/drivers/hid/usbhid/usbhid.h
|
|
@@ -80,12 +80,14 @@ struct usbhid_device {
|
|
unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */
|
|
char *ctrlbuf; /* Control buffer */
|
|
dma_addr_t ctrlbuf_dma; /* Control buffer dma */
|
|
+ unsigned long last_ctrl; /* record of last output for timeouts */
|
|
|
|
struct urb *urbout; /* Output URB */
|
|
struct hid_output_fifo out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */
|
|
unsigned char outhead, outtail; /* Output pipe fifo head & tail */
|
|
char *outbuf; /* Output buffer */
|
|
dma_addr_t outbuf_dma; /* Output buffer dma */
|
|
+ unsigned long last_out; /* record of last output for timeouts */
|
|
|
|
spinlock_t lock; /* fifo spinlock */
|
|
unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
|
|
diff --git a/drivers/hwmon/ams/ams-core.c b/drivers/hwmon/ams/ams-core.c
|
|
index 6c9ace1..2ad62c3 100644
|
|
--- a/drivers/hwmon/ams/ams-core.c
|
|
+++ b/drivers/hwmon/ams/ams-core.c
|
|
@@ -213,7 +213,7 @@ int __init ams_init(void)
|
|
return -ENODEV;
|
|
}
|
|
|
|
-void ams_exit(void)
|
|
+void ams_sensor_detach(void)
|
|
{
|
|
/* Remove input device */
|
|
ams_input_exit();
|
|
@@ -221,9 +221,6 @@ void ams_exit(void)
|
|
/* Remove attributes */
|
|
device_remove_file(&ams_info.of_dev->dev, &dev_attr_current);
|
|
|
|
- /* Shut down implementation */
|
|
- ams_info.exit();
|
|
-
|
|
/* Flush interrupt worker
|
|
*
|
|
* We do this after ams_info.exit(), because an interrupt might
|
|
@@ -239,6 +236,12 @@ void ams_exit(void)
|
|
pmf_unregister_irq_client(&ams_freefall_client);
|
|
}
|
|
|
|
+static void __exit ams_exit(void)
|
|
+{
|
|
+ /* Shut down implementation */
|
|
+ ams_info.exit();
|
|
+}
|
|
+
|
|
MODULE_AUTHOR("Stelian Pop, Michael Hanselmann");
|
|
MODULE_DESCRIPTION("Apple Motion Sensor driver");
|
|
MODULE_LICENSE("GPL");
|
|
diff --git a/drivers/hwmon/ams/ams-i2c.c b/drivers/hwmon/ams/ams-i2c.c
|
|
index 2cbf8a6..abeecd2 100644
|
|
--- a/drivers/hwmon/ams/ams-i2c.c
|
|
+++ b/drivers/hwmon/ams/ams-i2c.c
|
|
@@ -238,6 +238,8 @@ static int ams_i2c_probe(struct i2c_client *client,
|
|
static int ams_i2c_remove(struct i2c_client *client)
|
|
{
|
|
if (ams_info.has_device) {
|
|
+ ams_sensor_detach();
|
|
+
|
|
/* Disable interrupts */
|
|
ams_i2c_set_irq(AMS_IRQ_ALL, 0);
|
|
|
|
diff --git a/drivers/hwmon/ams/ams-pmu.c b/drivers/hwmon/ams/ams-pmu.c
|
|
index fb18b3d..4f61b3e 100644
|
|
--- a/drivers/hwmon/ams/ams-pmu.c
|
|
+++ b/drivers/hwmon/ams/ams-pmu.c
|
|
@@ -133,6 +133,8 @@ static void ams_pmu_get_xyz(s8 *x, s8 *y, s8 *z)
|
|
|
|
static void ams_pmu_exit(void)
|
|
{
|
|
+ ams_sensor_detach();
|
|
+
|
|
/* Disable interrupts */
|
|
ams_pmu_set_irq(AMS_IRQ_ALL, 0);
|
|
|
|
diff --git a/drivers/hwmon/ams/ams.h b/drivers/hwmon/ams/ams.h
|
|
index 5ed387b..b28d7e2 100644
|
|
--- a/drivers/hwmon/ams/ams.h
|
|
+++ b/drivers/hwmon/ams/ams.h
|
|
@@ -61,6 +61,7 @@ extern struct ams ams_info;
|
|
|
|
extern void ams_sensors(s8 *x, s8 *y, s8 *z);
|
|
extern int ams_sensor_attach(void);
|
|
+extern void ams_sensor_detach(void);
|
|
|
|
extern int ams_pmu_init(struct device_node *np);
|
|
extern int ams_i2c_init(struct device_node *np);
|
|
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
|
|
index fa07282..0627f7a 100644
|
|
--- a/drivers/hwmon/fschmd.c
|
|
+++ b/drivers/hwmon/fschmd.c
|
|
@@ -267,7 +267,7 @@ struct fschmd_data {
|
|
struct list_head list; /* member of the watchdog_data_list */
|
|
struct kref kref;
|
|
struct miscdevice watchdog_miscdev;
|
|
- int kind;
|
|
+ enum chips kind;
|
|
unsigned long watchdog_is_open;
|
|
char watchdog_expect_close;
|
|
char watchdog_name[10]; /* must be unique to avoid sysfs conflict */
|
|
@@ -325,8 +325,7 @@ static ssize_t show_in_value(struct device *dev,
|
|
int index = to_sensor_dev_attr(devattr)->index;
|
|
struct fschmd_data *data = fschmd_update_device(dev);
|
|
|
|
- /* fscher / fschrc - 1 as data->kind is an array index, not a chips */
|
|
- if (data->kind == (fscher - 1) || data->kind >= (fschrc - 1))
|
|
+ if (data->kind == fscher || data->kind >= fschrc)
|
|
return sprintf(buf, "%d\n", (data->volt[index] * dmi_vref *
|
|
dmi_mult[index]) / 255 + dmi_offset[index]);
|
|
else
|
|
@@ -492,7 +491,7 @@ static ssize_t show_pwm_auto_point1_pwm(struct device *dev,
|
|
int val = data->fan_min[index];
|
|
|
|
/* 0 = allow turning off (except on the syl), 1-255 = 50-100% */
|
|
- if (val || data->kind == fscsyl - 1)
|
|
+ if (val || data->kind == fscsyl)
|
|
val = val / 2 + 128;
|
|
|
|
return sprintf(buf, "%d\n", val);
|
|
@@ -506,7 +505,7 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
|
|
unsigned long v = simple_strtoul(buf, NULL, 10);
|
|
|
|
/* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */
|
|
- if (v || data->kind == fscsyl - 1) {
|
|
+ if (v || data->kind == fscsyl) {
|
|
v = SENSORS_LIMIT(v, 128, 255);
|
|
v = (v - 128) * 2 + 1;
|
|
}
|
|
@@ -1037,7 +1036,7 @@ static int fschmd_detect(struct i2c_client *client,
|
|
else
|
|
return -ENODEV;
|
|
|
|
- strlcpy(info->type, fschmd_id[kind - 1].name, I2C_NAME_SIZE);
|
|
+ strlcpy(info->type, fschmd_id[kind].name, I2C_NAME_SIZE);
|
|
|
|
return 0;
|
|
}
|
|
@@ -1065,6 +1064,7 @@ static int fschmd_probe(struct i2c_client *client,
|
|
(where the client is found through a data ptr instead of the
|
|
otherway around) */
|
|
data->client = client;
|
|
+ data->kind = kind;
|
|
|
|
if (kind == fscpos) {
|
|
/* The Poseidon has hardwired temp limits, fill these
|
|
@@ -1085,9 +1085,6 @@ static int fschmd_probe(struct i2c_client *client,
|
|
}
|
|
}
|
|
|
|
- /* i2c kind goes from 1-6, we want from 0-5 to address arrays */
|
|
- data->kind = kind - 1;
|
|
-
|
|
/* Read in some never changing registers */
|
|
data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
|
|
data->global_control = i2c_smbus_read_byte_data(client,
|
|
diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c
|
|
index a13b30e..d14a1af 100644
|
|
--- a/drivers/hwmon/tmp401.c
|
|
+++ b/drivers/hwmon/tmp401.c
|
|
@@ -134,7 +134,7 @@ struct tmp401_data {
|
|
struct mutex update_lock;
|
|
char valid; /* zero until following fields are valid */
|
|
unsigned long last_updated; /* in jiffies */
|
|
- int kind;
|
|
+ enum chips kind;
|
|
|
|
/* register values */
|
|
u8 status;
|
|
@@ -524,7 +524,7 @@ static int tmp401_detect(struct i2c_client *client,
|
|
if (reg > 15)
|
|
return -ENODEV;
|
|
|
|
- strlcpy(info->type, tmp401_id[kind - 1].name, I2C_NAME_SIZE);
|
|
+ strlcpy(info->type, tmp401_id[kind].name, I2C_NAME_SIZE);
|
|
|
|
return 0;
|
|
}
|
|
@@ -572,8 +572,7 @@ static int tmp401_probe(struct i2c_client *client,
|
|
goto exit_remove;
|
|
}
|
|
|
|
- dev_info(&client->dev, "Detected TI %s chip\n",
|
|
- names[data->kind - 1]);
|
|
+ dev_info(&client->dev, "Detected TI %s chip\n", names[data->kind]);
|
|
|
|
return 0;
|
|
|
|
diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c
|
|
index 4f7c051..738c472 100644
|
|
--- a/drivers/hwmon/tmp421.c
|
|
+++ b/drivers/hwmon/tmp421.c
|
|
@@ -61,9 +61,9 @@ static const u8 TMP421_TEMP_LSB[4] = { 0x10, 0x11, 0x12, 0x13 };
|
|
#define TMP423_DEVICE_ID 0x23
|
|
|
|
static const struct i2c_device_id tmp421_id[] = {
|
|
- { "tmp421", tmp421 },
|
|
- { "tmp422", tmp422 },
|
|
- { "tmp423", tmp423 },
|
|
+ { "tmp421", 2 },
|
|
+ { "tmp422", 3 },
|
|
+ { "tmp423", 4 },
|
|
{ }
|
|
};
|
|
MODULE_DEVICE_TABLE(i2c, tmp421_id);
|
|
@@ -73,21 +73,23 @@ struct tmp421_data {
|
|
struct mutex update_lock;
|
|
char valid;
|
|
unsigned long last_updated;
|
|
- int kind;
|
|
+ int channels;
|
|
u8 config;
|
|
s16 temp[4];
|
|
};
|
|
|
|
static int temp_from_s16(s16 reg)
|
|
{
|
|
- int temp = reg;
|
|
+ /* Mask out status bits */
|
|
+ int temp = reg & ~0xf;
|
|
|
|
return (temp * 1000 + 128) / 256;
|
|
}
|
|
|
|
static int temp_from_u16(u16 reg)
|
|
{
|
|
- int temp = reg;
|
|
+ /* Mask out status bits */
|
|
+ int temp = reg & ~0xf;
|
|
|
|
/* Add offset for extended temperature range. */
|
|
temp -= 64 * 256;
|
|
@@ -107,7 +109,7 @@ static struct tmp421_data *tmp421_update_device(struct device *dev)
|
|
data->config = i2c_smbus_read_byte_data(client,
|
|
TMP421_CONFIG_REG_1);
|
|
|
|
- for (i = 0; i <= data->kind; i++) {
|
|
+ for (i = 0; i < data->channels; i++) {
|
|
data->temp[i] = i2c_smbus_read_byte_data(client,
|
|
TMP421_TEMP_MSB[i]) << 8;
|
|
data->temp[i] |= i2c_smbus_read_byte_data(client,
|
|
@@ -166,7 +168,7 @@ static mode_t tmp421_is_visible(struct kobject *kobj, struct attribute *a,
|
|
devattr = container_of(a, struct device_attribute, attr);
|
|
index = to_sensor_dev_attr(devattr)->index;
|
|
|
|
- if (data->kind > index)
|
|
+ if (index < data->channels)
|
|
return a->mode;
|
|
|
|
return 0;
|
|
@@ -252,9 +254,9 @@ static int tmp421_detect(struct i2c_client *client,
|
|
return -ENODEV;
|
|
}
|
|
|
|
- strlcpy(info->type, tmp421_id[kind - 1].name, I2C_NAME_SIZE);
|
|
+ strlcpy(info->type, tmp421_id[kind].name, I2C_NAME_SIZE);
|
|
dev_info(&adapter->dev, "Detected TI %s chip at 0x%02x\n",
|
|
- names[kind - 1], client->addr);
|
|
+ names[kind], client->addr);
|
|
|
|
return 0;
|
|
}
|
|
@@ -271,7 +273,7 @@ static int tmp421_probe(struct i2c_client *client,
|
|
|
|
i2c_set_clientdata(client, data);
|
|
mutex_init(&data->update_lock);
|
|
- data->kind = id->driver_data;
|
|
+ data->channels = id->driver_data;
|
|
|
|
err = tmp421_init_client(client);
|
|
if (err)
|
|
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
|
|
index 5ff47ba..58809b0 100644
|
|
--- a/drivers/macintosh/therm_adt746x.c
|
|
+++ b/drivers/macintosh/therm_adt746x.c
|
|
@@ -90,6 +90,8 @@ static struct task_struct *thread_therm = NULL;
|
|
|
|
static void write_both_fan_speed(struct thermostat *th, int speed);
|
|
static void write_fan_speed(struct thermostat *th, int speed, int fan);
|
|
+static void thermostat_create_files(void);
|
|
+static void thermostat_remove_files(void);
|
|
|
|
static int
|
|
write_reg(struct thermostat* th, int reg, u8 data)
|
|
@@ -161,6 +163,8 @@ remove_thermostat(struct i2c_client *client)
|
|
struct thermostat *th = i2c_get_clientdata(client);
|
|
int i;
|
|
|
|
+ thermostat_remove_files();
|
|
+
|
|
if (thread_therm != NULL) {
|
|
kthread_stop(thread_therm);
|
|
}
|
|
@@ -449,6 +453,8 @@ static int probe_thermostat(struct i2c_client *client,
|
|
return -ENOMEM;
|
|
}
|
|
|
|
+ thermostat_create_files();
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -566,7 +572,6 @@ thermostat_init(void)
|
|
struct device_node* np;
|
|
const u32 *prop;
|
|
int i = 0, offset = 0;
|
|
- int err;
|
|
|
|
np = of_find_node_by_name(NULL, "fan");
|
|
if (!np)
|
|
@@ -633,6 +638,17 @@ thermostat_init(void)
|
|
return -ENODEV;
|
|
}
|
|
|
|
+#ifndef CONFIG_I2C_POWERMAC
|
|
+ request_module("i2c-powermac");
|
|
+#endif
|
|
+
|
|
+ return i2c_add_driver(&thermostat_driver);
|
|
+}
|
|
+
|
|
+static void thermostat_create_files(void)
|
|
+{
|
|
+ int err;
|
|
+
|
|
err = device_create_file(&of_dev->dev, &dev_attr_sensor1_temperature);
|
|
err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_temperature);
|
|
err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_limit);
|
|
@@ -647,16 +663,9 @@ thermostat_init(void)
|
|
if (err)
|
|
printk(KERN_WARNING
|
|
"Failed to create tempertaure attribute file(s).\n");
|
|
-
|
|
-#ifndef CONFIG_I2C_POWERMAC
|
|
- request_module("i2c-powermac");
|
|
-#endif
|
|
-
|
|
- return i2c_add_driver(&thermostat_driver);
|
|
}
|
|
|
|
-static void __exit
|
|
-thermostat_exit(void)
|
|
+static void thermostat_remove_files(void)
|
|
{
|
|
if (of_dev) {
|
|
device_remove_file(&of_dev->dev, &dev_attr_sensor1_temperature);
|
|
@@ -673,9 +682,14 @@ thermostat_exit(void)
|
|
device_remove_file(&of_dev->dev,
|
|
&dev_attr_sensor2_fan_speed);
|
|
|
|
- of_device_unregister(of_dev);
|
|
}
|
|
+}
|
|
+
|
|
+static void __exit
|
|
+thermostat_exit(void)
|
|
+{
|
|
i2c_del_driver(&thermostat_driver);
|
|
+ of_device_unregister(of_dev);
|
|
}
|
|
|
|
module_init(thermostat_init);
|
|
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
|
|
index 1d66932..e3cf568 100644
|
|
--- a/drivers/md/dm-ioctl.c
|
|
+++ b/drivers/md/dm-ioctl.c
|
|
@@ -897,16 +897,17 @@ static int do_resume(struct dm_ioctl *param)
|
|
set_disk_ro(dm_disk(md), 1);
|
|
}
|
|
|
|
- if (dm_suspended_md(md))
|
|
+ if (dm_suspended_md(md)) {
|
|
r = dm_resume(md);
|
|
+ if (!r)
|
|
+ dm_kobject_uevent(md, KOBJ_CHANGE, param->event_nr);
|
|
+ }
|
|
|
|
if (old_map)
|
|
dm_table_destroy(old_map);
|
|
|
|
- if (!r) {
|
|
- dm_kobject_uevent(md, KOBJ_CHANGE, param->event_nr);
|
|
+ if (!r)
|
|
r = __dev_status(md, param);
|
|
- }
|
|
|
|
dm_put(md);
|
|
return r;
|
|
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
|
|
index aa4e2aa..fa786b9 100644
|
|
--- a/drivers/md/dm.c
|
|
+++ b/drivers/md/dm.c
|
|
@@ -635,8 +635,10 @@ static void dec_pending(struct dm_io *io, int error)
|
|
if (!md->barrier_error && io_error != -EOPNOTSUPP)
|
|
md->barrier_error = io_error;
|
|
end_io_acct(io);
|
|
+ free_io(md, io);
|
|
} else {
|
|
end_io_acct(io);
|
|
+ free_io(md, io);
|
|
|
|
if (io_error != DM_ENDIO_REQUEUE) {
|
|
trace_block_bio_complete(md->queue, bio);
|
|
@@ -644,8 +646,6 @@ static void dec_pending(struct dm_io *io, int error)
|
|
bio_endio(bio, io_error);
|
|
}
|
|
}
|
|
-
|
|
- free_io(md, io);
|
|
}
|
|
}
|
|
|
|
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
|
|
index 8b8558f..b11533f 100644
|
|
--- a/drivers/media/dvb/dvb-core/dvb_net.c
|
|
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
|
|
@@ -504,6 +504,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
|
|
"bytes left in TS. Resyncing.\n", ts_remain);
|
|
priv->ule_sndu_len = 0;
|
|
priv->need_pusi = 1;
|
|
+ ts += TS_SZ;
|
|
continue;
|
|
}
|
|
|
|
diff --git a/drivers/media/video/gspca/mr97310a.c b/drivers/media/video/gspca/mr97310a.c
|
|
index 9154870..0493e40 100644
|
|
--- a/drivers/media/video/gspca/mr97310a.c
|
|
+++ b/drivers/media/video/gspca/mr97310a.c
|
|
@@ -697,6 +697,12 @@ static int start_cif_cam(struct gspca_dev *gspca_dev)
|
|
{0x13, 0x00, {0x01}, 1},
|
|
{0, 0, {0}, 0}
|
|
};
|
|
+ /* Without this command the cam won't work with USB-UHCI */
|
|
+ gspca_dev->usb_buf[0] = 0x0a;
|
|
+ gspca_dev->usb_buf[1] = 0x00;
|
|
+ err_code = mr_write(gspca_dev, 2);
|
|
+ if (err_code < 0)
|
|
+ return err_code;
|
|
err_code = sensor_write_regs(gspca_dev, cif_sensor1_init_data,
|
|
ARRAY_SIZE(cif_sensor1_init_data));
|
|
}
|
|
diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c
|
|
index f8d5c87..a4c0ef4 100644
|
|
--- a/drivers/media/video/soc_mediabus.c
|
|
+++ b/drivers/media/video/soc_mediabus.c
|
|
@@ -134,7 +134,8 @@ EXPORT_SYMBOL(soc_mbus_bytes_per_line);
|
|
const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc(
|
|
enum v4l2_mbus_pixelcode code)
|
|
{
|
|
- if ((unsigned int)(code - V4L2_MBUS_FMT_FIXED) > ARRAY_SIZE(mbus_fmt))
|
|
+ if (code - V4L2_MBUS_FMT_FIXED > ARRAY_SIZE(mbus_fmt) ||
|
|
+ code <= V4L2_MBUS_FMT_FIXED)
|
|
return NULL;
|
|
return mbus_fmt + code - V4L2_MBUS_FMT_FIXED - 1;
|
|
}
|
|
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
|
|
index d96e1ab..2fdf768 100644
|
|
--- a/drivers/mmc/host/s3cmci.c
|
|
+++ b/drivers/mmc/host/s3cmci.c
|
|
@@ -1179,7 +1179,7 @@ static int s3cmci_card_present(struct mmc_host *mmc)
|
|
struct s3c24xx_mci_pdata *pdata = host->pdata;
|
|
int ret;
|
|
|
|
- if (pdata->gpio_detect == 0)
|
|
+ if (pdata->no_detect)
|
|
return -ENOSYS;
|
|
|
|
ret = gpio_get_value(pdata->gpio_detect) ? 0 : 1;
|
|
@@ -1360,6 +1360,8 @@ static struct mmc_host_ops s3cmci_ops = {
|
|
static struct s3c24xx_mci_pdata s3cmci_def_pdata = {
|
|
/* This is currently here to avoid a number of if (host->pdata)
|
|
* checks. Any zero fields to ensure reasonable defaults are picked. */
|
|
+ .no_wprotect = 1,
|
|
+ .no_detect = 1,
|
|
};
|
|
|
|
#ifdef CONFIG_CPU_FREQ
|
|
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
|
|
index 4331d67..2a9f029 100644
|
|
--- a/drivers/net/wireless/airo.c
|
|
+++ b/drivers/net/wireless/airo.c
|
|
@@ -5254,11 +5254,7 @@ static int set_wep_key(struct airo_info *ai, u16 index, const char *key,
|
|
WepKeyRid wkr;
|
|
int rc;
|
|
|
|
- if (keylen == 0) {
|
|
- airo_print_err(ai->dev->name, "%s: key length to set was zero",
|
|
- __func__);
|
|
- return -1;
|
|
- }
|
|
+ WARN_ON(keylen == 0);
|
|
|
|
memset(&wkr, 0, sizeof(wkr));
|
|
wkr.len = cpu_to_le16(sizeof(wkr));
|
|
@@ -6405,11 +6401,7 @@ static int airo_set_encode(struct net_device *dev,
|
|
if (dwrq->length > MIN_KEY_SIZE)
|
|
key.len = MAX_KEY_SIZE;
|
|
else
|
|
- if (dwrq->length > 0)
|
|
- key.len = MIN_KEY_SIZE;
|
|
- else
|
|
- /* Disable the key */
|
|
- key.len = 0;
|
|
+ key.len = MIN_KEY_SIZE;
|
|
/* Check if the key is not marked as invalid */
|
|
if(!(dwrq->flags & IW_ENCODE_NOKEY)) {
|
|
/* Cleanup */
|
|
@@ -6590,12 +6582,22 @@ static int airo_set_encodeext(struct net_device *dev,
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
- /* Send the key to the card */
|
|
- rc = set_wep_key(local, idx, key.key, key.len, perm, 1);
|
|
- if (rc < 0) {
|
|
- airo_print_err(local->dev->name, "failed to set WEP key"
|
|
- " at index %d: %d.", idx, rc);
|
|
- return rc;
|
|
+ if (key.len == 0) {
|
|
+ rc = set_wep_tx_idx(local, idx, perm, 1);
|
|
+ if (rc < 0) {
|
|
+ airo_print_err(local->dev->name,
|
|
+ "failed to set WEP transmit index to %d: %d.",
|
|
+ idx, rc);
|
|
+ return rc;
|
|
+ }
|
|
+ } else {
|
|
+ rc = set_wep_key(local, idx, key.key, key.len, perm, 1);
|
|
+ if (rc < 0) {
|
|
+ airo_print_err(local->dev->name,
|
|
+ "failed to set WEP key at index %d: %d.",
|
|
+ idx, rc);
|
|
+ return rc;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
|
|
index 6a2a967..bbd2f31 100644
|
|
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
|
|
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
|
|
@@ -541,7 +541,6 @@ struct ath5k_txq_info {
|
|
/*
|
|
* Transmit packet types.
|
|
* used on tx control descriptor
|
|
- * TODO: Use them inside base.c corectly
|
|
*/
|
|
enum ath5k_pkt_type {
|
|
AR5K_PKT_TYPE_NORMAL = 0,
|
|
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
|
|
index e63b7c4..d6ee8ac 100644
|
|
--- a/drivers/net/wireless/ath/ath5k/base.c
|
|
+++ b/drivers/net/wireless/ath/ath5k/base.c
|
|
@@ -1246,6 +1246,29 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
|
|
return 0;
|
|
}
|
|
|
|
+static enum ath5k_pkt_type get_hw_packet_type(struct sk_buff *skb)
|
|
+{
|
|
+ struct ieee80211_hdr *hdr;
|
|
+ enum ath5k_pkt_type htype;
|
|
+ __le16 fc;
|
|
+
|
|
+ hdr = (struct ieee80211_hdr *)skb->data;
|
|
+ fc = hdr->frame_control;
|
|
+
|
|
+ if (ieee80211_is_beacon(fc))
|
|
+ htype = AR5K_PKT_TYPE_BEACON;
|
|
+ else if (ieee80211_is_probe_resp(fc))
|
|
+ htype = AR5K_PKT_TYPE_PROBE_RESP;
|
|
+ else if (ieee80211_is_atim(fc))
|
|
+ htype = AR5K_PKT_TYPE_ATIM;
|
|
+ else if (ieee80211_is_pspoll(fc))
|
|
+ htype = AR5K_PKT_TYPE_PSPOLL;
|
|
+ else
|
|
+ htype = AR5K_PKT_TYPE_NORMAL;
|
|
+
|
|
+ return htype;
|
|
+}
|
|
+
|
|
static int
|
|
ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
|
|
struct ath5k_txq *txq)
|
|
@@ -1300,7 +1323,8 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
|
|
sc->vif, pktlen, info));
|
|
}
|
|
ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
|
|
- ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
|
|
+ ieee80211_get_hdrlen_from_skb(skb),
|
|
+ get_hw_packet_type(skb),
|
|
(sc->power_level * 2),
|
|
hw_rate,
|
|
info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags,
|
|
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
|
|
index 1660ef1..06eaaa9 100644
|
|
--- a/drivers/net/wireless/ath/ath9k/beacon.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
|
|
@@ -525,16 +525,13 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
|
|
{
|
|
u32 nexttbtt, intval;
|
|
|
|
- /* Configure the timers only when the TSF has to be reset */
|
|
-
|
|
- if (!(sc->sc_flags & SC_OP_TSF_RESET))
|
|
- return;
|
|
-
|
|
/* NB: the beacon interval is kept internally in TU's */
|
|
intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
|
|
intval /= ATH_BCBUF; /* for staggered beacons */
|
|
nexttbtt = intval;
|
|
- intval |= ATH9K_BEACON_RESET_TSF;
|
|
+
|
|
+ if (sc->sc_flags & SC_OP_TSF_RESET)
|
|
+ intval |= ATH9K_BEACON_RESET_TSF;
|
|
|
|
/*
|
|
* In AP mode we enable the beacon timers and SWBA interrupts to
|
|
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
|
|
index ae37144..7c64aa5 100644
|
|
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
|
@@ -1345,6 +1345,16 @@ static void ath9k_hw_override_ini(struct ath_hw *ah,
|
|
* Necessary to avoid issues on AR5416 2.0
|
|
*/
|
|
REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
|
|
+
|
|
+ /*
|
|
+ * Disable RIFS search on some chips to avoid baseband
|
|
+ * hang issues.
|
|
+ */
|
|
+ if (AR_SREV_9100(ah) || AR_SREV_9160(ah)) {
|
|
+ val = REG_READ(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS);
|
|
+ val &= ~AR_PHY_RIFS_INIT_DELAY;
|
|
+ REG_WRITE(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS, val);
|
|
+ }
|
|
}
|
|
|
|
static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah,
|
|
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
|
|
index 643bea3..4faafbd 100644
|
|
--- a/drivers/net/wireless/ath/ath9k/main.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
|
@@ -928,6 +928,7 @@ static void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf
|
|
|
|
clear_bit(key->hw_key_idx + 64, common->keymap);
|
|
if (common->splitmic) {
|
|
+ ath9k_hw_keyreset(ah, key->hw_key_idx + 32);
|
|
clear_bit(key->hw_key_idx + 32, common->keymap);
|
|
clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
|
|
}
|
|
@@ -1848,6 +1849,8 @@ bad_free_hw:
|
|
|
|
void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|
{
|
|
+ struct ath_hw *ah = sc->sc_ah;
|
|
+
|
|
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
|
|
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
|
|
IEEE80211_HW_SIGNAL_DBM |
|
|
@@ -1865,7 +1868,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|
BIT(NL80211_IFTYPE_ADHOC) |
|
|
BIT(NL80211_IFTYPE_MESH_POINT);
|
|
|
|
- hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
|
|
+ if (AR_SREV_5416(ah))
|
|
+ hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
|
|
|
|
hw->queues = 4;
|
|
hw->max_rates = 4;
|
|
diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h
|
|
index 31de27d..0999a49 100644
|
|
--- a/drivers/net/wireless/ath/ath9k/phy.h
|
|
+++ b/drivers/net/wireless/ath/ath9k/phy.h
|
|
@@ -384,6 +384,9 @@ bool ath9k_hw_set_rf_regs(struct ath_hw *ah,
|
|
|
|
#define AR_PHY_HEAVY_CLIP_ENABLE 0x99E0
|
|
|
|
+#define AR_PHY_HEAVY_CLIP_FACTOR_RIFS 0x99EC
|
|
+#define AR_PHY_RIFS_INIT_DELAY 0x03ff0000
|
|
+
|
|
#define AR_PHY_M_SLEEP 0x99f0
|
|
#define AR_PHY_REFCLKDLY 0x99f4
|
|
#define AR_PHY_REFCLKPD 0x99f8
|
|
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
|
|
index 70fdb9d..1d6cf7d 100644
|
|
--- a/drivers/net/wireless/ath/ath9k/rc.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/rc.c
|
|
@@ -668,7 +668,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
|
|
struct ieee80211_tx_rate *rates = tx_info->control.rates;
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
|
__le16 fc = hdr->frame_control;
|
|
- u8 try_per_rate, i = 0, rix, nrix;
|
|
+ u8 try_per_rate, i = 0, rix;
|
|
int is_probe = 0;
|
|
|
|
if (rate_control_send_low(sta, priv_sta, txrc))
|
|
@@ -688,26 +688,25 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
|
|
|
|
rate_table = sc->cur_rate_table;
|
|
rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe);
|
|
- nrix = rix;
|
|
|
|
if (is_probe) {
|
|
/* set one try for probe rates. For the
|
|
* probes don't enable rts */
|
|
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
|
|
- 1, nrix, 0);
|
|
+ 1, rix, 0);
|
|
|
|
/* Get the next tried/allowed rate. No RTS for the next series
|
|
* after the probe rate
|
|
*/
|
|
- ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix);
|
|
+ ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
|
|
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
|
|
- try_per_rate, nrix, 0);
|
|
+ try_per_rate, rix, 0);
|
|
|
|
tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
|
|
} else {
|
|
/* Set the choosen rate. No RTS for first series entry. */
|
|
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
|
|
- try_per_rate, nrix, 0);
|
|
+ try_per_rate, rix, 0);
|
|
}
|
|
|
|
/* Fill in the other rates for multirate retry */
|
|
@@ -716,10 +715,10 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
|
|
if (i + 1 == 4)
|
|
try_per_rate = 4;
|
|
|
|
- ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix);
|
|
+ ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
|
|
/* All other rates in the series have RTS enabled */
|
|
ath_rc_rate_set_series(rate_table, &rates[i], txrc,
|
|
- try_per_rate, nrix, 1);
|
|
+ try_per_rate, rix, 1);
|
|
}
|
|
|
|
/*
|
|
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
|
|
index 490fb45..b59166c 100644
|
|
--- a/drivers/net/wireless/b43/main.c
|
|
+++ b/drivers/net/wireless/b43/main.c
|
|
@@ -3970,6 +3970,7 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
|
|
}
|
|
|
|
/* We are ready to run. */
|
|
+ ieee80211_wake_queues(dev->wl->hw);
|
|
b43_set_status(dev, B43_STAT_STARTED);
|
|
|
|
/* Start data flow (TX/RX). */
|
|
@@ -4379,8 +4380,6 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
|
|
|
|
ieee80211_wake_queues(dev->wl->hw);
|
|
|
|
- ieee80211_wake_queues(dev->wl->hw);
|
|
-
|
|
b43_set_status(dev, B43_STAT_INITIALIZED);
|
|
|
|
out:
|
|
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
|
|
index 4a905b6..6d21b49 100644
|
|
--- a/drivers/net/wireless/b43legacy/main.c
|
|
+++ b/drivers/net/wireless/b43legacy/main.c
|
|
@@ -2921,6 +2921,7 @@ static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev)
|
|
goto out;
|
|
}
|
|
/* We are ready to run. */
|
|
+ ieee80211_wake_queues(dev->wl->hw);
|
|
b43legacy_set_status(dev, B43legacy_STAT_STARTED);
|
|
|
|
/* Start data flow (TX/RX) */
|
|
@@ -3341,6 +3342,7 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
|
|
b43legacy_security_init(dev);
|
|
b43legacy_rng_init(wl);
|
|
|
|
+ ieee80211_wake_queues(dev->wl->hw);
|
|
b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED);
|
|
|
|
b43legacy_leds_init(dev);
|
|
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
|
|
index a72f7c2..4bf4c21 100644
|
|
--- a/drivers/net/wireless/p54/p54pci.c
|
|
+++ b/drivers/net/wireless/p54/p54pci.c
|
|
@@ -157,6 +157,14 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev,
|
|
skb_tail_pointer(skb),
|
|
priv->common.rx_mtu + 32,
|
|
PCI_DMA_FROMDEVICE);
|
|
+
|
|
+ if (pci_dma_mapping_error(priv->pdev, mapping)) {
|
|
+ dev_kfree_skb_any(skb);
|
|
+ dev_err(&priv->pdev->dev,
|
|
+ "RX DMA Mapping error\n");
|
|
+ break;
|
|
+ }
|
|
+
|
|
desc->host_addr = cpu_to_le32(mapping);
|
|
desc->device_addr = 0; // FIXME: necessary?
|
|
desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
|
|
@@ -325,14 +333,20 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
|
|
u32 device_idx, idx, i;
|
|
|
|
spin_lock_irqsave(&priv->lock, flags);
|
|
-
|
|
device_idx = le32_to_cpu(ring_control->device_idx[1]);
|
|
idx = le32_to_cpu(ring_control->host_idx[1]);
|
|
i = idx % ARRAY_SIZE(ring_control->tx_data);
|
|
|
|
- priv->tx_buf_data[i] = skb;
|
|
mapping = pci_map_single(priv->pdev, skb->data, skb->len,
|
|
PCI_DMA_TODEVICE);
|
|
+ if (pci_dma_mapping_error(priv->pdev, mapping)) {
|
|
+ spin_unlock_irqrestore(&priv->lock, flags);
|
|
+ p54_free_skb(dev, skb);
|
|
+ dev_err(&priv->pdev->dev, "TX DMA mapping error\n");
|
|
+ return ;
|
|
+ }
|
|
+ priv->tx_buf_data[i] = skb;
|
|
+
|
|
desc = &ring_control->tx_data[i];
|
|
desc->host_addr = cpu_to_le32(mapping);
|
|
desc->device_addr = ((struct p54_hdr *)skb->data)->req_id;
|
|
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
|
|
index 92af9b9..8742640 100644
|
|
--- a/drivers/net/wireless/p54/p54usb.c
|
|
+++ b/drivers/net/wireless/p54/p54usb.c
|
|
@@ -60,6 +60,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
|
|
{USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
|
|
{USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
|
|
{USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
|
|
+ {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */
|
|
{USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
|
|
{USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
|
|
{USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
|
|
diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c
|
|
index c1abac8..5becbde 100644
|
|
--- a/drivers/pci/hotplug/ibmphp_ebda.c
|
|
+++ b/drivers/pci/hotplug/ibmphp_ebda.c
|
|
@@ -245,7 +245,7 @@ static void __init print_ebda_hpc (void)
|
|
|
|
int __init ibmphp_access_ebda (void)
|
|
{
|
|
- u8 format, num_ctlrs, rio_complete, hs_complete;
|
|
+ u8 format, num_ctlrs, rio_complete, hs_complete, ebda_sz;
|
|
u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, re, rc_id, re_id, base;
|
|
int rc = 0;
|
|
|
|
@@ -260,7 +260,16 @@ int __init ibmphp_access_ebda (void)
|
|
iounmap (io_mem);
|
|
debug ("returned ebda segment: %x\n", ebda_seg);
|
|
|
|
- io_mem = ioremap(ebda_seg<<4, 1024);
|
|
+ io_mem = ioremap(ebda_seg<<4, 1);
|
|
+ if (!io_mem)
|
|
+ return -ENOMEM;
|
|
+ ebda_sz = readb(io_mem);
|
|
+ iounmap(io_mem);
|
|
+ debug("ebda size: %d(KiB)\n", ebda_sz);
|
|
+ if (ebda_sz == 0)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ io_mem = ioremap(ebda_seg<<4, (ebda_sz * 1024));
|
|
if (!io_mem )
|
|
return -ENOMEM;
|
|
next_offset = 0x180;
|
|
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
|
|
index f526e73..11fce79 100644
|
|
--- a/drivers/platform/x86/Kconfig
|
|
+++ b/drivers/platform/x86/Kconfig
|
|
@@ -319,9 +319,15 @@ config THINKPAD_ACPI_VIDEO
|
|
server running, phase of the moon, and the current mood of
|
|
Schroedinger's cat. If you can use X.org's RandR to control
|
|
your ThinkPad's video output ports instead of this feature,
|
|
- don't think twice: do it and say N here to save some memory.
|
|
+ don't think twice: do it and say N here to save memory and avoid
|
|
+ bad interactions with X.org.
|
|
|
|
- If you are not sure, say Y here.
|
|
+ NOTE: access to this feature is limited to processes with the
|
|
+ CAP_SYS_ADMIN capability, to avoid local DoS issues in platforms
|
|
+ where it interacts badly with X.org.
|
|
+
|
|
+ If you are not sure, say Y here but do try to check if you could
|
|
+ be using X.org RandR instead.
|
|
|
|
config THINKPAD_ACPI_HOTKEY_POLL
|
|
bool "Support NVRAM polling for hot keys"
|
|
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
|
|
index e2be6bb..6a47bb7 100644
|
|
--- a/drivers/platform/x86/eeepc-laptop.c
|
|
+++ b/drivers/platform/x86/eeepc-laptop.c
|
|
@@ -1277,7 +1277,8 @@ static void eeepc_dmi_check(struct eeepc_laptop *eeepc)
|
|
* hotplug code. In fact, current hotplug code seems to unplug another
|
|
* device...
|
|
*/
|
|
- if (strcmp(model, "1005HA") == 0 || strcmp(model, "1201N") == 0) {
|
|
+ if (strcmp(model, "1005HA") == 0 || strcmp(model, "1201N") == 0 ||
|
|
+ strcmp(model, "1005PE") == 0) {
|
|
eeepc->hotplug_disabled = true;
|
|
pr_info("wlan hotplug disabled\n");
|
|
}
|
|
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
|
|
index eb603f1..e7b0c3b 100644
|
|
--- a/drivers/platform/x86/thinkpad_acpi.c
|
|
+++ b/drivers/platform/x86/thinkpad_acpi.c
|
|
@@ -286,6 +286,7 @@ struct ibm_init_struct {
|
|
char param[32];
|
|
|
|
int (*init) (struct ibm_init_struct *);
|
|
+ mode_t base_procfs_mode;
|
|
struct ibm_struct *data;
|
|
};
|
|
|
|
@@ -2082,6 +2083,7 @@ static struct attribute_set *hotkey_dev_attributes;
|
|
|
|
static void tpacpi_driver_event(const unsigned int hkey_event);
|
|
static void hotkey_driver_event(const unsigned int scancode);
|
|
+static void hotkey_poll_setup(const bool may_warn);
|
|
|
|
/* HKEY.MHKG() return bits */
|
|
#define TP_HOTKEY_TABLET_MASK (1 << 3)
|
|
@@ -2264,6 +2266,8 @@ static int tpacpi_hotkey_driver_mask_set(const u32 mask)
|
|
|
|
rc = hotkey_mask_set((hotkey_acpi_mask | hotkey_driver_mask) &
|
|
~hotkey_source_mask);
|
|
+ hotkey_poll_setup(true);
|
|
+
|
|
mutex_unlock(&hotkey_mutex);
|
|
|
|
return rc;
|
|
@@ -2548,7 +2552,7 @@ static void hotkey_poll_stop_sync(void)
|
|
}
|
|
|
|
/* call with hotkey_mutex held */
|
|
-static void hotkey_poll_setup(bool may_warn)
|
|
+static void hotkey_poll_setup(const bool may_warn)
|
|
{
|
|
const u32 poll_driver_mask = hotkey_driver_mask & hotkey_source_mask;
|
|
const u32 poll_user_mask = hotkey_user_mask & hotkey_source_mask;
|
|
@@ -2579,7 +2583,7 @@ static void hotkey_poll_setup(bool may_warn)
|
|
}
|
|
}
|
|
|
|
-static void hotkey_poll_setup_safe(bool may_warn)
|
|
+static void hotkey_poll_setup_safe(const bool may_warn)
|
|
{
|
|
mutex_lock(&hotkey_mutex);
|
|
hotkey_poll_setup(may_warn);
|
|
@@ -2597,7 +2601,11 @@ static void hotkey_poll_set_freq(unsigned int freq)
|
|
|
|
#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
|
|
|
|
-static void hotkey_poll_setup_safe(bool __unused)
|
|
+static void hotkey_poll_setup(const bool __unused)
|
|
+{
|
|
+}
|
|
+
|
|
+static void hotkey_poll_setup_safe(const bool __unused)
|
|
{
|
|
}
|
|
|
|
@@ -2607,16 +2615,11 @@ static int hotkey_inputdev_open(struct input_dev *dev)
|
|
{
|
|
switch (tpacpi_lifecycle) {
|
|
case TPACPI_LIFE_INIT:
|
|
- /*
|
|
- * hotkey_init will call hotkey_poll_setup_safe
|
|
- * at the appropriate moment
|
|
- */
|
|
- return 0;
|
|
- case TPACPI_LIFE_EXITING:
|
|
- return -EBUSY;
|
|
case TPACPI_LIFE_RUNNING:
|
|
hotkey_poll_setup_safe(false);
|
|
return 0;
|
|
+ case TPACPI_LIFE_EXITING:
|
|
+ return -EBUSY;
|
|
}
|
|
|
|
/* Should only happen if tpacpi_lifecycle is corrupt */
|
|
@@ -2627,7 +2630,7 @@ static int hotkey_inputdev_open(struct input_dev *dev)
|
|
static void hotkey_inputdev_close(struct input_dev *dev)
|
|
{
|
|
/* disable hotkey polling when possible */
|
|
- if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING &&
|
|
+ if (tpacpi_lifecycle != TPACPI_LIFE_EXITING &&
|
|
!(hotkey_source_mask & hotkey_driver_mask))
|
|
hotkey_poll_setup_safe(false);
|
|
}
|
|
@@ -3655,13 +3658,19 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
|
|
break;
|
|
case 3:
|
|
/* 0x3000-0x3FFF: bay-related wakeups */
|
|
- if (hkey == TP_HKEY_EV_BAYEJ_ACK) {
|
|
+ switch (hkey) {
|
|
+ case TP_HKEY_EV_BAYEJ_ACK:
|
|
hotkey_autosleep_ack = 1;
|
|
printk(TPACPI_INFO
|
|
"bay ejected\n");
|
|
hotkey_wakeup_hotunplug_complete_notify_change();
|
|
known_ev = true;
|
|
- } else {
|
|
+ break;
|
|
+ case TP_HKEY_EV_OPTDRV_EJ:
|
|
+ /* FIXME: kick libata if SATA link offline */
|
|
+ known_ev = true;
|
|
+ break;
|
|
+ default:
|
|
known_ev = false;
|
|
}
|
|
break;
|
|
@@ -3870,7 +3879,7 @@ enum {
|
|
TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */
|
|
TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */
|
|
TP_ACPI_BLUETOOTH_RESUMECTRL = 0x04, /* Bluetooth state at resume:
|
|
- off / last state */
|
|
+ 0 = disable, 1 = enable */
|
|
};
|
|
|
|
enum {
|
|
@@ -3916,10 +3925,11 @@ static int bluetooth_set_status(enum tpacpi_rfkill_state state)
|
|
}
|
|
#endif
|
|
|
|
- /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */
|
|
- status = TP_ACPI_BLUETOOTH_RESUMECTRL;
|
|
if (state == TPACPI_RFK_RADIO_ON)
|
|
- status |= TP_ACPI_BLUETOOTH_RADIOSSW;
|
|
+ status = TP_ACPI_BLUETOOTH_RADIOSSW
|
|
+ | TP_ACPI_BLUETOOTH_RESUMECTRL;
|
|
+ else
|
|
+ status = 0;
|
|
|
|
if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
|
|
return -EIO;
|
|
@@ -4070,7 +4080,7 @@ enum {
|
|
TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */
|
|
TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */
|
|
TP_ACPI_WANCARD_RESUMECTRL = 0x04, /* Wan state at resume:
|
|
- off / last state */
|
|
+ 0 = disable, 1 = enable */
|
|
};
|
|
|
|
#define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw"
|
|
@@ -4107,10 +4117,11 @@ static int wan_set_status(enum tpacpi_rfkill_state state)
|
|
}
|
|
#endif
|
|
|
|
- /* We make sure to set TP_ACPI_WANCARD_RESUMECTRL */
|
|
- status = TP_ACPI_WANCARD_RESUMECTRL;
|
|
if (state == TPACPI_RFK_RADIO_ON)
|
|
- status |= TP_ACPI_WANCARD_RADIOSSW;
|
|
+ status = TP_ACPI_WANCARD_RADIOSSW
|
|
+ | TP_ACPI_WANCARD_RESUMECTRL;
|
|
+ else
|
|
+ status = 0;
|
|
|
|
if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
|
|
return -EIO;
|
|
@@ -4619,6 +4630,10 @@ static int video_read(struct seq_file *m)
|
|
return 0;
|
|
}
|
|
|
|
+ /* Even reads can crash X.org, so... */
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
+ return -EPERM;
|
|
+
|
|
status = video_outputsw_get();
|
|
if (status < 0)
|
|
return status;
|
|
@@ -4652,6 +4667,10 @@ static int video_write(char *buf)
|
|
if (video_supported == TPACPI_VIDEO_NONE)
|
|
return -ENODEV;
|
|
|
|
+ /* Even reads can crash X.org, let alone writes... */
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
+ return -EPERM;
|
|
+
|
|
enable = 0;
|
|
disable = 0;
|
|
|
|
@@ -6133,13 +6152,13 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = {
|
|
TPACPI_Q_IBM('1', 'Y', TPACPI_BRGHT_Q_EC), /* T43/p ATI */
|
|
|
|
/* Models with ATI GPUs that can use ECNVRAM */
|
|
- TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_EC),
|
|
+ TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_EC), /* R50,51 T40-42 */
|
|
TPACPI_Q_IBM('1', 'Q', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
|
|
- TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
|
|
+ TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_EC), /* R52 */
|
|
TPACPI_Q_IBM('7', '8', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
|
|
|
|
/* Models with Intel Extreme Graphics 2 */
|
|
- TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC),
|
|
+ TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC), /* X40 */
|
|
TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
|
|
TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
|
|
|
|
@@ -6522,7 +6541,8 @@ static int volume_set_status(const u8 status)
|
|
return volume_set_status_ec(status);
|
|
}
|
|
|
|
-static int volume_set_mute_ec(const bool mute)
|
|
+/* returns < 0 on error, 0 on no change, 1 on change */
|
|
+static int __volume_set_mute_ec(const bool mute)
|
|
{
|
|
int rc;
|
|
u8 s, n;
|
|
@@ -6537,22 +6557,37 @@ static int volume_set_mute_ec(const bool mute)
|
|
n = (mute) ? s | TP_EC_AUDIO_MUTESW_MSK :
|
|
s & ~TP_EC_AUDIO_MUTESW_MSK;
|
|
|
|
- if (n != s)
|
|
+ if (n != s) {
|
|
rc = volume_set_status_ec(n);
|
|
+ if (!rc)
|
|
+ rc = 1;
|
|
+ }
|
|
|
|
unlock:
|
|
mutex_unlock(&volume_mutex);
|
|
return rc;
|
|
}
|
|
|
|
+static int volume_alsa_set_mute(const bool mute)
|
|
+{
|
|
+ dbg_printk(TPACPI_DBG_MIXER, "ALSA: trying to %smute\n",
|
|
+ (mute) ? "" : "un");
|
|
+ return __volume_set_mute_ec(mute);
|
|
+}
|
|
+
|
|
static int volume_set_mute(const bool mute)
|
|
{
|
|
+ int rc;
|
|
+
|
|
dbg_printk(TPACPI_DBG_MIXER, "trying to %smute\n",
|
|
(mute) ? "" : "un");
|
|
- return volume_set_mute_ec(mute);
|
|
+
|
|
+ rc = __volume_set_mute_ec(mute);
|
|
+ return (rc < 0) ? rc : 0;
|
|
}
|
|
|
|
-static int volume_set_volume_ec(const u8 vol)
|
|
+/* returns < 0 on error, 0 on no change, 1 on change */
|
|
+static int __volume_set_volume_ec(const u8 vol)
|
|
{
|
|
int rc;
|
|
u8 s, n;
|
|
@@ -6569,19 +6604,22 @@ static int volume_set_volume_ec(const u8 vol)
|
|
|
|
n = (s & ~TP_EC_AUDIO_LVL_MSK) | vol;
|
|
|
|
- if (n != s)
|
|
+ if (n != s) {
|
|
rc = volume_set_status_ec(n);
|
|
+ if (!rc)
|
|
+ rc = 1;
|
|
+ }
|
|
|
|
unlock:
|
|
mutex_unlock(&volume_mutex);
|
|
return rc;
|
|
}
|
|
|
|
-static int volume_set_volume(const u8 vol)
|
|
+static int volume_alsa_set_volume(const u8 vol)
|
|
{
|
|
dbg_printk(TPACPI_DBG_MIXER,
|
|
- "trying to set volume level to %hu\n", vol);
|
|
- return volume_set_volume_ec(vol);
|
|
+ "ALSA: trying to set volume level to %hu\n", vol);
|
|
+ return __volume_set_volume_ec(vol);
|
|
}
|
|
|
|
static void volume_alsa_notify_change(void)
|
|
@@ -6628,7 +6666,7 @@ static int volume_alsa_vol_get(struct snd_kcontrol *kcontrol,
|
|
static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
- return volume_set_volume(ucontrol->value.integer.value[0]);
|
|
+ return volume_alsa_set_volume(ucontrol->value.integer.value[0]);
|
|
}
|
|
|
|
#define volume_alsa_mute_info snd_ctl_boolean_mono_info
|
|
@@ -6651,7 +6689,7 @@ static int volume_alsa_mute_get(struct snd_kcontrol *kcontrol,
|
|
static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
- return volume_set_mute(!ucontrol->value.integer.value[0]);
|
|
+ return volume_alsa_set_mute(!ucontrol->value.integer.value[0]);
|
|
}
|
|
|
|
static struct snd_kcontrol_new volume_alsa_control_vol __devinitdata = {
|
|
@@ -8477,9 +8515,10 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
|
|
"%s installed\n", ibm->name);
|
|
|
|
if (ibm->read) {
|
|
- mode_t mode;
|
|
+ mode_t mode = iibm->base_procfs_mode;
|
|
|
|
- mode = S_IRUGO;
|
|
+ if (!mode)
|
|
+ mode = S_IRUGO;
|
|
if (ibm->write)
|
|
mode |= S_IWUSR;
|
|
entry = proc_create_data(ibm->name, mode, proc_dir,
|
|
@@ -8670,6 +8709,7 @@ static struct ibm_init_struct ibms_init[] __initdata = {
|
|
#ifdef CONFIG_THINKPAD_ACPI_VIDEO
|
|
{
|
|
.init = video_init,
|
|
+ .base_procfs_mode = S_IRUSR,
|
|
.data = &video_driver_data,
|
|
},
|
|
#endif
|
|
@@ -9032,6 +9072,9 @@ static int __init thinkpad_acpi_module_init(void)
|
|
return ret;
|
|
}
|
|
}
|
|
+
|
|
+ tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
|
|
+
|
|
ret = input_register_device(tpacpi_inputdev);
|
|
if (ret < 0) {
|
|
printk(TPACPI_ERR "unable to register input device\n");
|
|
@@ -9041,7 +9084,6 @@ static int __init thinkpad_acpi_module_init(void)
|
|
tp_features.input_device_registered = 1;
|
|
}
|
|
|
|
- tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
|
|
index be5a6b7..40845c7 100644
|
|
--- a/drivers/rtc/class.c
|
|
+++ b/drivers/rtc/class.c
|
|
@@ -226,6 +226,7 @@ static void __exit rtc_exit(void)
|
|
{
|
|
rtc_dev_exit();
|
|
class_destroy(rtc_class);
|
|
+ idr_destroy(&rtc_idr);
|
|
}
|
|
|
|
subsys_initcall(rtc_init);
|
|
diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c
|
|
index 03ea530..44c4399 100644
|
|
--- a/drivers/rtc/rtc-coh901331.c
|
|
+++ b/drivers/rtc/rtc-coh901331.c
|
|
@@ -271,12 +271,13 @@ static int coh901331_resume(struct platform_device *pdev)
|
|
{
|
|
struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev);
|
|
|
|
- if (device_may_wakeup(&pdev->dev))
|
|
+ if (device_may_wakeup(&pdev->dev)) {
|
|
disable_irq_wake(rtap->irq);
|
|
- else
|
|
+ } else {
|
|
clk_enable(rtap->clk);
|
|
writel(rtap->irqmaskstore, rtap->virtbase + COH901331_IRQ_MASK);
|
|
clk_disable(rtap->clk);
|
|
+ }
|
|
return 0;
|
|
}
|
|
#else
|
|
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
|
|
index efabea1..cd55176 100644
|
|
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
|
|
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
|
|
@@ -5998,6 +5998,8 @@ _scsih_remove(struct pci_dev *pdev)
|
|
struct _sas_port *mpt2sas_port;
|
|
struct _sas_device *sas_device;
|
|
struct _sas_node *expander_sibling;
|
|
+ struct _raid_device *raid_device, *next;
|
|
+ struct MPT2SAS_TARGET *sas_target_priv_data;
|
|
struct workqueue_struct *wq;
|
|
unsigned long flags;
|
|
|
|
@@ -6011,6 +6013,21 @@ _scsih_remove(struct pci_dev *pdev)
|
|
if (wq)
|
|
destroy_workqueue(wq);
|
|
|
|
+ /* release all the volumes */
|
|
+ list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list,
|
|
+ list) {
|
|
+ if (raid_device->starget) {
|
|
+ sas_target_priv_data =
|
|
+ raid_device->starget->hostdata;
|
|
+ sas_target_priv_data->deleted = 1;
|
|
+ scsi_remove_target(&raid_device->starget->dev);
|
|
+ }
|
|
+ printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
|
|
+ "(0x%016llx)\n", ioc->name, raid_device->handle,
|
|
+ (unsigned long long) raid_device->wwid);
|
|
+ _scsih_raid_device_remove(ioc, raid_device);
|
|
+ }
|
|
+
|
|
/* free ports attached to the sas_host */
|
|
retry_again:
|
|
list_for_each_entry(mpt2sas_port,
|
|
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
|
|
index 8371d91..49ac414 100644
|
|
--- a/drivers/scsi/qla1280.c
|
|
+++ b/drivers/scsi/qla1280.c
|
|
@@ -1640,8 +1640,10 @@ qla1280_load_firmware_pio(struct scsi_qla_host *ha)
|
|
uint16_t mb[MAILBOX_REGISTER_COUNT], i;
|
|
int err;
|
|
|
|
+ spin_unlock_irq(ha->host->host_lock);
|
|
err = request_firmware(&fw, ql1280_board_tbl[ha->devnum].fwname,
|
|
&ha->pdev->dev);
|
|
+ spin_lock_irq(ha->host->host_lock);
|
|
if (err) {
|
|
printk(KERN_ERR "Failed to load image \"%s\" err %d\n",
|
|
ql1280_board_tbl[ha->devnum].fwname, err);
|
|
@@ -1699,8 +1701,10 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
|
|
return -ENOMEM;
|
|
#endif
|
|
|
|
+ spin_unlock_irq(ha->host->host_lock);
|
|
err = request_firmware(&fw, ql1280_board_tbl[ha->devnum].fwname,
|
|
&ha->pdev->dev);
|
|
+ spin_lock_irq(ha->host->host_lock);
|
|
if (err) {
|
|
printk(KERN_ERR "Failed to load image \"%s\" err %d\n",
|
|
ql1280_board_tbl[ha->devnum].fwname, err);
|
|
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
|
|
index 60d665a..d00fcf8 100644
|
|
--- a/drivers/serial/imx.c
|
|
+++ b/drivers/serial/imx.c
|
|
@@ -1279,7 +1279,7 @@ static int serial_imx_probe(struct platform_device *pdev)
|
|
sport->use_irda = 1;
|
|
#endif
|
|
|
|
- if (pdata->init) {
|
|
+ if (pdata && pdata->init) {
|
|
ret = pdata->init(pdev);
|
|
if (ret)
|
|
goto clkput;
|
|
@@ -1292,7 +1292,7 @@ static int serial_imx_probe(struct platform_device *pdev)
|
|
|
|
return 0;
|
|
deinit:
|
|
- if (pdata->exit)
|
|
+ if (pdata && pdata->exit)
|
|
pdata->exit(pdev);
|
|
clkput:
|
|
clk_put(sport->clk);
|
|
@@ -1321,7 +1321,7 @@ static int serial_imx_remove(struct platform_device *pdev)
|
|
|
|
clk_disable(sport->clk);
|
|
|
|
- if (pdata->exit)
|
|
+ if (pdata && pdata->exit)
|
|
pdata->exit(pdev);
|
|
|
|
iounmap(sport->port.membase);
|
|
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
|
|
index fc2e963..ed77d88 100644
|
|
--- a/drivers/staging/Kconfig
|
|
+++ b/drivers/staging/Kconfig
|
|
@@ -81,8 +81,6 @@ source "drivers/staging/rtl8192u/Kconfig"
|
|
|
|
source "drivers/staging/rtl8192e/Kconfig"
|
|
|
|
-source "drivers/staging/mimio/Kconfig"
|
|
-
|
|
source "drivers/staging/frontier/Kconfig"
|
|
|
|
source "drivers/staging/dream/Kconfig"
|
|
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
|
|
index b5e67b8..6035bff 100644
|
|
--- a/drivers/staging/Makefile
|
|
+++ b/drivers/staging/Makefile
|
|
@@ -23,7 +23,6 @@ obj-$(CONFIG_R8187SE) += rtl8187se/
|
|
obj-$(CONFIG_RTL8192SU) += rtl8192su/
|
|
obj-$(CONFIG_RTL8192U) += rtl8192u/
|
|
obj-$(CONFIG_RTL8192E) += rtl8192e/
|
|
-obj-$(CONFIG_INPUT_MIMIO) += mimio/
|
|
obj-$(CONFIG_TRANZPORT) += frontier/
|
|
obj-$(CONFIG_DREAM) += dream/
|
|
obj-$(CONFIG_POHMELFS) += pohmelfs/
|
|
diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c
|
|
index 894eecf..6acc49a 100644
|
|
--- a/drivers/staging/hv/vmbus_drv.c
|
|
+++ b/drivers/staging/hv/vmbus_drv.c
|
|
@@ -24,6 +24,8 @@
|
|
#include <linux/irq.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/sysctl.h>
|
|
+#include <linux/pci.h>
|
|
+#include <linux/dmi.h>
|
|
#include "osd.h"
|
|
#include "logging.h"
|
|
#include "vmbus.h"
|
|
@@ -946,6 +948,19 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
|
|
}
|
|
}
|
|
|
|
+static struct dmi_system_id __initdata microsoft_hv_dmi_table[] = {
|
|
+ {
|
|
+ .ident = "Hyper-V",
|
|
+ .matches = {
|
|
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
|
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
|
|
+ DMI_MATCH(DMI_BOARD_NAME, "Virtual Machine"),
|
|
+ },
|
|
+ },
|
|
+ { },
|
|
+};
|
|
+MODULE_DEVICE_TABLE(dmi, microsoft_hv_dmi_table);
|
|
+
|
|
static int __init vmbus_init(void)
|
|
{
|
|
int ret = 0;
|
|
@@ -957,6 +972,9 @@ static int __init vmbus_init(void)
|
|
vmbus_loglevel, HIWORD(vmbus_loglevel), LOWORD(vmbus_loglevel));
|
|
/* Todo: it is used for loglevel, to be ported to new kernel. */
|
|
|
|
+ if (!dmi_check_system(microsoft_hv_dmi_table))
|
|
+ return -ENODEV;
|
|
+
|
|
ret = vmbus_bus_init(VmbusInitialize);
|
|
|
|
DPRINT_EXIT(VMBUS_DRV);
|
|
@@ -973,6 +991,18 @@ static void __exit vmbus_exit(void)
|
|
return;
|
|
}
|
|
|
|
+/*
|
|
+ * We use a PCI table to determine if we should autoload this driver This is
|
|
+ * needed by distro tools to determine if the hyperv drivers should be
|
|
+ * installed and/or configured. We don't do anything else with the table, but
|
|
+ * it needs to be present.
|
|
+ */
|
|
+const static struct pci_device_id microsoft_hv_pci_table[] = {
|
|
+ { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */
|
|
+ { 0 }
|
|
+};
|
|
+MODULE_DEVICE_TABLE(pci, microsoft_hv_pci_table);
|
|
+
|
|
MODULE_LICENSE("GPL");
|
|
module_param(vmbus_irq, int, S_IRUGO);
|
|
module_param(vmbus_loglevel, int, S_IRUGO);
|
|
diff --git a/drivers/staging/mimio/Kconfig b/drivers/staging/mimio/Kconfig
|
|
deleted file mode 100644
|
|
index 505dcb2..0000000
|
|
--- a/drivers/staging/mimio/Kconfig
|
|
+++ /dev/null
|
|
@@ -1,10 +0,0 @@
|
|
-config INPUT_MIMIO
|
|
- tristate "Mimio Xi interactive whiteboard support"
|
|
- depends on USB && INPUT
|
|
- default N
|
|
- help
|
|
- Say Y here if you want to use a Mimio Xi interactive
|
|
- whiteboard device.
|
|
-
|
|
- To compile this driver as a module, choose M here: the
|
|
- module will be called mimio.
|
|
diff --git a/drivers/staging/mimio/Makefile b/drivers/staging/mimio/Makefile
|
|
deleted file mode 100644
|
|
index 77807ee..0000000
|
|
--- a/drivers/staging/mimio/Makefile
|
|
+++ /dev/null
|
|
@@ -1 +0,0 @@
|
|
-obj-$(CONFIG_INPUT_MIMIO) += mimio.o
|
|
diff --git a/drivers/staging/mimio/mimio.c b/drivers/staging/mimio/mimio.c
|
|
deleted file mode 100644
|
|
index 1ba8103..0000000
|
|
--- a/drivers/staging/mimio/mimio.c
|
|
+++ /dev/null
|
|
@@ -1,914 +0,0 @@
|
|
-/*
|
|
- * Hardware event => input event mapping:
|
|
- *
|
|
- *
|
|
- *
|
|
- input.h:#define BTN_TOOL_PEN 0x140 black
|
|
- input.h:#define BTN_TOOL_RUBBER 0x141 blue
|
|
- input.h:#define BTN_TOOL_BRUSH 0x142 green
|
|
- input.h:#define BTN_TOOL_PENCIL 0x143 red
|
|
- input.h:#define BTN_TOOL_AIRBRUSH 0x144 eraser
|
|
- input.h:#define BTN_TOOL_FINGER 0x145 small eraser
|
|
- input.h:#define BTN_TOOL_MOUSE 0x146 mimio interactive
|
|
- input.h:#define BTN_TOOL_LENS 0x147 mimio interactive but1
|
|
- input.h:#define LOCALBTN_TOOL_EXTRA1 0x14a mimio interactive but2 == BTN_TOUCH
|
|
- input.h:#define LOCALBTN_TOOL_EXTRA2 0x14b mimio extra pens (orange, brown, yellow, purple) == BTN_STYLUS
|
|
- input.h:#define LOCALBTN_TOOL_EXTRA3 0x14c unused == BTN_STYLUS2
|
|
- input.h:#define BTN_TOOL_DOUBLETAP 0x14d unused
|
|
- input.h:#define BTN_TOOL_TRIPLETAP 0x14e unused
|
|
- *
|
|
- * MIMIO_EV_PENDOWN(MIMIO_PEN_K) => EV_KEY BIT(BTN_TOOL_PEN)
|
|
- * MIMIO_EV_PENDOWN(MIMIO_PEN_B) => EV_KEY BIT(BTN_TOOL_RUBBER)
|
|
- * MIMIO_EV_PENDOWN(MIMIO_PEN_G) => EV_KEY BIT(BTN_TOOL_BRUSH)
|
|
- * MIMIO_EV_PENDOWN(MIMIO_PEN_R) => EV_KEY BIT(BTN_TOOL_PENCIL)
|
|
- * MIMIO_EV_PENDOWN(MIMIO_PEN_E) => EV_KEY BIT(BTN_TOOL_AIRBRUSH)
|
|
- * MIMIO_EV_PENDOWN(MIMIO_PEN_ES) => EV_KEY BIT(BTN_TOOL_FINGER)
|
|
- * MIMIO_EV_PENDOWN(MIMIO_PEN_I) => EV_KEY BIT(BTN_TOOL_MOUSE)
|
|
- * MIMIO_EV_PENDOWN(MIMIO_PEN_IL) => EV_KEY BIT(BTN_TOOL_LENS)
|
|
- * MIMIO_EV_PENDOWN(MIMIO_PEN_IR) => EV_KEY BIT(BTN_TOOL_DOUBLETAP)
|
|
- * MIMIO_EV_PENDOWN(MIMIO_PEN_EX) => EV_KEY BIT(BTN_TOOL_TRIPLETAP)
|
|
- * MIMIO_EV_PENDATA => EV_ABS BIT(ABS_X), BIT(ABS_Y)
|
|
- * MIMIO_EV_MEMRESET => EV_KEY BIT(BTN_0)
|
|
- * MIMIO_EV_ACC(ACC_NEWPAGE) => EV_KEY BIT(BTN_1)
|
|
- * MIMIO_EV_ACC(ACC_TAGPAGE) => EV_KEY BIT(BTN_2)
|
|
- * MIMIO_EV_ACC(ACC_PRINTPAGE) => EV_KEY BIT(BTN_3)
|
|
- * MIMIO_EV_ACC(ACC_MAXIMIZE) => EV_KEY BIT(BTN_4)
|
|
- * MIMIO_EV_ACC(ACC_FINDCTLPNL) => EV_KEY BIT(BTN_5)
|
|
- *
|
|
- *
|
|
- * open issues:
|
|
- * - cold-load of data captured when mimio in standalone mode not yet
|
|
- * supported; need to snoop Win32 box to see datastream for this.
|
|
- * - mimio mouse not yet supported; need to snoop Win32 box to see the
|
|
- * datastream for this.
|
|
- */
|
|
-#include <linux/kernel.h>
|
|
-#include <linux/init.h>
|
|
-#include <linux/slab.h>
|
|
-#include <linux/spinlock.h>
|
|
-#include <linux/input.h>
|
|
-#include <linux/usb.h>
|
|
-
|
|
-#define DRIVER_VERSION "v0.031"
|
|
-#define DRIVER_AUTHOR "mwilder@cs.nmsu.edu"
|
|
-#define DRIVER_DESC "USB mimio-xi driver"
|
|
-
|
|
-enum {UPVALUE, DOWNVALUE, MOVEVALUE};
|
|
-
|
|
-#define MIMIO_XRANGE_MAX 9600
|
|
-#define MIMIO_YRANGE_MAX 4800
|
|
-
|
|
-#define LOCALBTN_TOOL_EXTRA1 BTN_TOUCH
|
|
-#define LOCALBTN_TOOL_EXTRA2 BTN_STYLUS
|
|
-#define LOCALBTN_TOOL_EXTRA3 BTN_STYLUS2
|
|
-
|
|
-#define MIMIO_VENDOR_ID 0x08d3
|
|
-#define MIMIO_PRODUCT_ID 0x0001
|
|
-#define MIMIO_MAXPAYLOAD (8)
|
|
-#define MIMIO_MAXNAMELEN (64)
|
|
-#define MIMIO_TXWAIT (1)
|
|
-#define MIMIO_TXDONE (2)
|
|
-
|
|
-#define MIMIO_EV_PENDOWN (0x22)
|
|
-#define MIMIO_EV_PENDATA (0x24)
|
|
-#define MIMIO_EV_PENUP (0x51)
|
|
-#define MIMIO_EV_MEMRESET (0x45)
|
|
-#define MIMIO_EV_ACC (0xb2)
|
|
-
|
|
-#define MIMIO_PEN_K (1) /* black pen */
|
|
-#define MIMIO_PEN_B (2) /* blue pen */
|
|
-#define MIMIO_PEN_G (3) /* green pen */
|
|
-#define MIMIO_PEN_R (4) /* red pen */
|
|
-/* 5, 6, 7, 8 are extra pens */
|
|
-#define MIMIO_PEN_E (9) /* big eraser */
|
|
-#define MIMIO_PEN_ES (10) /* lil eraser */
|
|
-#define MIMIO_PENJUMP_START (10)
|
|
-#define MIMIO_PENJUMP (6)
|
|
-#define MIMIO_PEN_I (17) /* mimio interactive */
|
|
-#define MIMIO_PEN_IL (18) /* mimio interactive button 1 */
|
|
-#define MIMIO_PEN_IR (19) /* mimio interactive button 2 */
|
|
-
|
|
-#define MIMIO_PEN_MAX (MIMIO_PEN_IR)
|
|
-
|
|
-#define ACC_DONE (0)
|
|
-#define ACC_NEWPAGE (1)
|
|
-#define ACC_TAGPAGE (2)
|
|
-#define ACC_PRINTPAGE (4)
|
|
-#define ACC_MAXIMIZE (8)
|
|
-#define ACC_FINDCTLPNL (16)
|
|
-
|
|
-#define isvalidtxsize(n) ((n) > 0 && (n) <= MIMIO_MAXPAYLOAD)
|
|
-
|
|
-
|
|
-struct pktbuf {
|
|
- unsigned char instr;
|
|
- unsigned char buf[16];
|
|
- unsigned char *p;
|
|
- unsigned char *q;
|
|
-};
|
|
-
|
|
-struct usbintendpt {
|
|
- dma_addr_t dma;
|
|
- struct urb *urb;
|
|
- unsigned char *buf;
|
|
- struct usb_endpoint_descriptor *desc;
|
|
-};
|
|
-
|
|
-struct mimio {
|
|
- struct input_dev *idev;
|
|
- struct usb_device *udev;
|
|
- struct usb_interface *uifc;
|
|
- int open;
|
|
- int present;
|
|
- int greeted;
|
|
- int txflags;
|
|
- char phys[MIMIO_MAXNAMELEN];
|
|
- struct usbintendpt in;
|
|
- struct usbintendpt out;
|
|
- struct pktbuf pktbuf;
|
|
- unsigned char minor;
|
|
- wait_queue_head_t waitq;
|
|
- spinlock_t txlock;
|
|
- void (*rxhandler)(struct mimio *, unsigned char *, unsigned int);
|
|
- int last_pen_down;
|
|
-};
|
|
-
|
|
-static void mimio_close(struct input_dev *);
|
|
-static void mimio_dealloc(struct mimio *);
|
|
-static void mimio_disconnect(struct usb_interface *);
|
|
-static int mimio_greet(struct mimio *);
|
|
-static void mimio_irq_in(struct urb *);
|
|
-static void mimio_irq_out(struct urb *);
|
|
-static int mimio_open(struct input_dev *);
|
|
-static int mimio_probe(struct usb_interface *, const struct usb_device_id *);
|
|
-static void mimio_rx_handler(struct mimio *, unsigned char *, unsigned int);
|
|
-static int mimio_tx(struct mimio *, const char *, int);
|
|
-
|
|
-static char mimio_name[] = "VirtualInk mimio-Xi";
|
|
-static struct usb_device_id mimio_table [] = {
|
|
- { USB_DEVICE(MIMIO_VENDOR_ID, MIMIO_PRODUCT_ID) },
|
|
- { USB_DEVICE(0x0525, 0xa4a0) }, /* gadget zero firmware */
|
|
- { }
|
|
-};
|
|
-
|
|
-MODULE_DEVICE_TABLE(usb, mimio_table);
|
|
-
|
|
-static struct usb_driver mimio_driver = {
|
|
- .name = "mimio",
|
|
- .probe = mimio_probe,
|
|
- .disconnect = mimio_disconnect,
|
|
- .id_table = mimio_table,
|
|
-};
|
|
-
|
|
-static DECLARE_MUTEX(disconnect_sem);
|
|
-
|
|
-static void mimio_close(struct input_dev *idev)
|
|
-{
|
|
- struct mimio *mimio;
|
|
-
|
|
- mimio = input_get_drvdata(idev);
|
|
- if (!mimio) {
|
|
- dev_err(&idev->dev, "null mimio attached to input device\n");
|
|
- return;
|
|
- }
|
|
-
|
|
- if (mimio->open <= 0)
|
|
- dev_err(&idev->dev, "mimio not open.\n");
|
|
- else
|
|
- mimio->open--;
|
|
-
|
|
- if (mimio->present == 0 && mimio->open == 0)
|
|
- mimio_dealloc(mimio);
|
|
-}
|
|
-
|
|
-static void mimio_dealloc(struct mimio *mimio)
|
|
-{
|
|
- if (mimio == NULL)
|
|
- return;
|
|
-
|
|
- usb_kill_urb(mimio->in.urb);
|
|
-
|
|
- usb_kill_urb(mimio->out.urb);
|
|
-
|
|
- if (mimio->idev) {
|
|
- input_unregister_device(mimio->idev);
|
|
- if (mimio->idev->grab)
|
|
- input_close_device(mimio->idev->grab);
|
|
- else
|
|
- dev_dbg(&mimio->idev->dev, "mimio->idev->grab == NULL"
|
|
- " -- didn't call input_close_device\n");
|
|
- }
|
|
-
|
|
- usb_free_urb(mimio->in.urb);
|
|
-
|
|
- usb_free_urb(mimio->out.urb);
|
|
-
|
|
- if (mimio->in.buf) {
|
|
- usb_buffer_free(mimio->udev, MIMIO_MAXPAYLOAD, mimio->in.buf,
|
|
- mimio->in.dma);
|
|
- }
|
|
-
|
|
- if (mimio->out.buf)
|
|
- usb_buffer_free(mimio->udev, MIMIO_MAXPAYLOAD, mimio->out.buf,
|
|
- mimio->out.dma);
|
|
-
|
|
- if (mimio->idev)
|
|
- input_free_device(mimio->idev);
|
|
-
|
|
- kfree(mimio);
|
|
-}
|
|
-
|
|
-static void mimio_disconnect(struct usb_interface *ifc)
|
|
-{
|
|
- struct mimio *mimio;
|
|
-
|
|
- down(&disconnect_sem);
|
|
-
|
|
- mimio = usb_get_intfdata(ifc);
|
|
- usb_set_intfdata(ifc, NULL);
|
|
- dev_dbg(&mimio->idev->dev, "disconnect\n");
|
|
-
|
|
- if (mimio) {
|
|
- mimio->present = 0;
|
|
-
|
|
- if (mimio->open <= 0)
|
|
- mimio_dealloc(mimio);
|
|
- }
|
|
-
|
|
- up(&disconnect_sem);
|
|
-}
|
|
-
|
|
-static int mimio_greet(struct mimio *mimio)
|
|
-{
|
|
- const struct grtpkt {
|
|
- int nbytes;
|
|
- unsigned delay;
|
|
- char data[8];
|
|
- } grtpkts[] = {
|
|
- { 3, 0, { 0x11, 0x55, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
|
- { 5, 0, { 0x53, 0x55, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00 } },
|
|
- { 5, 0, { 0x43, 0x55, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00 } },
|
|
- { 5, 0, { 0x33, 0x55, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00 } },
|
|
- { 5, 0, { 0x13, 0x00, 0x5e, 0x02, 0x4f, 0x00, 0x00, 0x00 } },
|
|
- { 5, 0, { 0x13, 0x00, 0x04, 0x03, 0x14, 0x00, 0x00, 0x00 } },
|
|
- { 5, 2, { 0x13, 0x00, 0x00, 0x04, 0x17, 0x00, 0x00, 0x00 } },
|
|
- { 5, 0, { 0x13, 0x00, 0x0d, 0x08, 0x16, 0x00, 0x00, 0x00 } },
|
|
- { 5, 0, { 0x13, 0x00, 0x4d, 0x01, 0x5f, 0x00, 0x00, 0x00 } },
|
|
- { 3, 0, { 0xf1, 0x55, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
|
- { 7, 2, { 0x52, 0x55, 0x00, 0x07, 0x31, 0x55, 0x64, 0x00 } },
|
|
- { 0, 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
|
- };
|
|
- int rslt;
|
|
- const struct grtpkt *pkt;
|
|
-
|
|
- for (pkt = grtpkts; pkt->nbytes; pkt++) {
|
|
- rslt = mimio_tx(mimio, pkt->data, pkt->nbytes);
|
|
- if (rslt)
|
|
- return rslt;
|
|
- if (pkt->delay)
|
|
- msleep(pkt->delay);
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static void mimio_irq_in(struct urb *urb)
|
|
-{
|
|
- int rslt;
|
|
- char *data;
|
|
- const char *reason = "going down";
|
|
- struct mimio *mimio;
|
|
-
|
|
- mimio = urb->context;
|
|
-
|
|
- if (mimio == NULL)
|
|
- /* paranoia */
|
|
- return;
|
|
-
|
|
- switch (urb->status) {
|
|
- case 0:
|
|
- /* success */
|
|
- break;
|
|
- case -ETIMEDOUT:
|
|
- reason = "timeout -- unplugged?";
|
|
- case -ECONNRESET:
|
|
- case -ENOENT:
|
|
- case -ESHUTDOWN:
|
|
- dev_dbg(&mimio->idev->dev, "%s.\n", reason);
|
|
- return;
|
|
- default:
|
|
- dev_dbg(&mimio->idev->dev, "unknown urb-status: %d.\n",
|
|
- urb->status);
|
|
- goto exit;
|
|
- }
|
|
- data = mimio->in.buf;
|
|
-
|
|
- if (mimio->rxhandler)
|
|
- mimio->rxhandler(mimio, data, urb->actual_length);
|
|
-exit:
|
|
- /*
|
|
- * Keep listening to device on same urb.
|
|
- */
|
|
- rslt = usb_submit_urb(urb, GFP_ATOMIC);
|
|
- if (rslt)
|
|
- dev_err(&mimio->idev->dev, "usb_submit_urb failure: %d.\n",
|
|
- rslt);
|
|
-}
|
|
-
|
|
-static void mimio_irq_out(struct urb *urb)
|
|
-{
|
|
- unsigned long flags;
|
|
- struct mimio *mimio;
|
|
-
|
|
- mimio = urb->context;
|
|
-
|
|
- if (urb->status)
|
|
- dev_dbg(&mimio->idev->dev, "urb-status: %d.\n", urb->status);
|
|
-
|
|
- spin_lock_irqsave(&mimio->txlock, flags);
|
|
- mimio->txflags |= MIMIO_TXDONE;
|
|
- spin_unlock_irqrestore(&mimio->txlock, flags);
|
|
- wmb();
|
|
- wake_up(&mimio->waitq);
|
|
-}
|
|
-
|
|
-static int mimio_open(struct input_dev *idev)
|
|
-{
|
|
- int rslt;
|
|
- struct mimio *mimio;
|
|
-
|
|
- rslt = 0;
|
|
- down(&disconnect_sem);
|
|
- mimio = input_get_drvdata(idev);
|
|
- dev_dbg(&idev->dev, "mimio_open\n");
|
|
-
|
|
- if (mimio == NULL) {
|
|
- dev_err(&idev->dev, "null mimio.\n");
|
|
- rslt = -ENODEV;
|
|
- goto exit;
|
|
- }
|
|
-
|
|
- if (mimio->open++)
|
|
- goto exit;
|
|
-
|
|
- if (mimio->present && !mimio->greeted) {
|
|
- struct urb *urb = mimio->in.urb;
|
|
- mimio->in.urb->dev = mimio->udev;
|
|
- rslt = usb_submit_urb(mimio->in.urb, GFP_KERNEL);
|
|
- if (rslt) {
|
|
- dev_err(&idev->dev, "usb_submit_urb failure "
|
|
- "(res = %d: %s). Not greeting.\n",
|
|
- rslt,
|
|
- (!urb ? "urb is NULL" :
|
|
- (urb->hcpriv ? "urb->hcpriv is non-NULL" :
|
|
- (!urb->complete ? "urb is not complete" :
|
|
- (urb->number_of_packets <= 0 ? "urb has no packets" :
|
|
- (urb->interval <= 0 ? "urb interval too small" :
|
|
- "urb interval too large or some other error"))))));
|
|
- rslt = -EIO;
|
|
- goto exit;
|
|
- }
|
|
- rslt = mimio_greet(mimio);
|
|
- if (rslt == 0) {
|
|
- dev_dbg(&idev->dev, "Mimio greeted OK.\n");
|
|
- mimio->greeted = 1;
|
|
- } else {
|
|
- dev_dbg(&idev->dev, "Mimio greet Failure (%d)\n",
|
|
- rslt);
|
|
- }
|
|
- }
|
|
-
|
|
-exit:
|
|
- up(&disconnect_sem);
|
|
- return rslt;
|
|
-}
|
|
-
|
|
-static int mimio_probe(struct usb_interface *ifc,
|
|
- const struct usb_device_id *id)
|
|
-{
|
|
- char path[64];
|
|
- int pipe, maxp;
|
|
- struct mimio *mimio;
|
|
- struct usb_device *udev;
|
|
- struct usb_host_interface *hostifc;
|
|
- struct input_dev *input_dev;
|
|
- int res = 0;
|
|
- int i;
|
|
-
|
|
- udev = interface_to_usbdev(ifc);
|
|
-
|
|
- mimio = kzalloc(sizeof(struct mimio), GFP_KERNEL);
|
|
- if (!mimio)
|
|
- return -ENOMEM;
|
|
-
|
|
- input_dev = input_allocate_device();
|
|
- if (!input_dev) {
|
|
- mimio_dealloc(mimio);
|
|
- return -ENOMEM;
|
|
- }
|
|
-
|
|
- mimio->uifc = ifc;
|
|
- mimio->udev = udev;
|
|
- mimio->pktbuf.p = mimio->pktbuf.buf;
|
|
- mimio->pktbuf.q = mimio->pktbuf.buf;
|
|
- /* init_input_dev(mimio->idev); */
|
|
- mimio->idev = input_dev;
|
|
- init_waitqueue_head(&mimio->waitq);
|
|
- spin_lock_init(&mimio->txlock);
|
|
- hostifc = ifc->cur_altsetting;
|
|
-
|
|
- if (hostifc->desc.bNumEndpoints != 2) {
|
|
- dev_err(&udev->dev, "Unexpected endpoint count: %d.\n",
|
|
- hostifc->desc.bNumEndpoints);
|
|
- mimio_dealloc(mimio);
|
|
- return -ENODEV;
|
|
- }
|
|
-
|
|
- mimio->in.desc = &(hostifc->endpoint[0].desc);
|
|
- mimio->out.desc = &(hostifc->endpoint[1].desc);
|
|
-
|
|
- mimio->in.buf = usb_buffer_alloc(udev, MIMIO_MAXPAYLOAD, GFP_KERNEL,
|
|
- &mimio->in.dma);
|
|
- mimio->out.buf = usb_buffer_alloc(udev, MIMIO_MAXPAYLOAD, GFP_KERNEL,
|
|
- &mimio->out.dma);
|
|
-
|
|
- if (mimio->in.buf == NULL || mimio->out.buf == NULL) {
|
|
- dev_err(&udev->dev, "usb_buffer_alloc failure.\n");
|
|
- mimio_dealloc(mimio);
|
|
- return -ENOMEM;
|
|
- }
|
|
-
|
|
- mimio->in.urb = usb_alloc_urb(0, GFP_KERNEL);
|
|
- mimio->out.urb = usb_alloc_urb(0, GFP_KERNEL);
|
|
-
|
|
- if (mimio->in.urb == NULL || mimio->out.urb == NULL) {
|
|
- dev_err(&udev->dev, "usb_alloc_urb failure.\n");
|
|
- mimio_dealloc(mimio);
|
|
- return -ENOMEM;
|
|
- }
|
|
-
|
|
- /*
|
|
- * Build the input urb.
|
|
- */
|
|
- pipe = usb_rcvintpipe(udev, mimio->in.desc->bEndpointAddress);
|
|
- maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
|
|
- if (maxp > MIMIO_MAXPAYLOAD)
|
|
- maxp = MIMIO_MAXPAYLOAD;
|
|
- usb_fill_int_urb(mimio->in.urb, udev, pipe, mimio->in.buf, maxp,
|
|
- mimio_irq_in, mimio, mimio->in.desc->bInterval);
|
|
- mimio->in.urb->transfer_dma = mimio->in.dma;
|
|
- mimio->in.urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
|
-
|
|
- /*
|
|
- * Build the output urb.
|
|
- */
|
|
- pipe = usb_sndintpipe(udev, mimio->out.desc->bEndpointAddress);
|
|
- maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
|
|
- if (maxp > MIMIO_MAXPAYLOAD)
|
|
- maxp = MIMIO_MAXPAYLOAD;
|
|
- usb_fill_int_urb(mimio->out.urb, udev, pipe, mimio->out.buf, maxp,
|
|
- mimio_irq_out, mimio, mimio->out.desc->bInterval);
|
|
- mimio->out.urb->transfer_dma = mimio->out.dma;
|
|
- mimio->out.urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
|
-
|
|
- /*
|
|
- * Build input device info
|
|
- */
|
|
- usb_make_path(udev, path, 64);
|
|
- snprintf(mimio->phys, MIMIO_MAXNAMELEN, "%s/input0", path);
|
|
- input_set_drvdata(input_dev, mimio);
|
|
- /* input_dev->dev = &ifc->dev; */
|
|
- input_dev->open = mimio_open;
|
|
- input_dev->close = mimio_close;
|
|
- input_dev->name = mimio_name;
|
|
- input_dev->phys = mimio->phys;
|
|
- input_dev->dev.parent = &ifc->dev;
|
|
-
|
|
- input_dev->id.bustype = BUS_USB;
|
|
- input_dev->id.vendor = le16_to_cpu(udev->descriptor.idVendor);
|
|
- input_dev->id.product = le16_to_cpu(udev->descriptor.idProduct);
|
|
- input_dev->id.version = le16_to_cpu(udev->descriptor.bcdDevice);
|
|
-
|
|
- input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS);
|
|
- for (i = BTN_TOOL_PEN; i <= LOCALBTN_TOOL_EXTRA2; ++i)
|
|
- set_bit(i, input_dev->keybit);
|
|
-
|
|
- input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_0) |
|
|
- BIT_MASK(BTN_1) |
|
|
- BIT_MASK(BTN_2) |
|
|
- BIT_MASK(BTN_3) |
|
|
- BIT_MASK(BTN_4) |
|
|
- BIT_MASK(BTN_5);
|
|
- /* input_dev->keybit[BTN_MOUSE] |= BIT(BTN_LEFT); */
|
|
- input_dev->absbit[0] |= BIT_MASK(ABS_X) | BIT_MASK(ABS_Y);
|
|
- input_set_abs_params(input_dev, ABS_X, 0, MIMIO_XRANGE_MAX, 0, 0);
|
|
- input_set_abs_params(input_dev, ABS_Y, 0, MIMIO_YRANGE_MAX, 0, 0);
|
|
- input_dev->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
|
|
-
|
|
-#if 0
|
|
- input_dev->absmin[ABS_X] = 0;
|
|
- input_dev->absmin[ABS_Y] = 0;
|
|
- input_dev->absmax[ABS_X] = 9600;
|
|
- input_dev->absmax[ABS_Y] = 4800;
|
|
- input_dev->absfuzz[ABS_X] = 0;
|
|
- input_dev->absfuzz[ABS_Y] = 0;
|
|
- input_dev->absflat[ABS_X] = 0;
|
|
- input_dev->absflat[ABS_Y] = 0;
|
|
-#endif
|
|
-
|
|
-#if 0
|
|
- /* this will just reduce the precision */
|
|
- input_dev->absfuzz[ABS_X] = 8; /* experimental; may need to change */
|
|
- input_dev->absfuzz[ABS_Y] = 8; /* experimental; may need to change */
|
|
-#endif
|
|
-
|
|
- /*
|
|
- * Register the input device.
|
|
- */
|
|
- res = input_register_device(mimio->idev);
|
|
- if (res) {
|
|
- dev_err(&udev->dev, "input_register_device failure (%d)\n",
|
|
- res);
|
|
- mimio_dealloc(mimio);
|
|
- return -EIO;
|
|
- }
|
|
- dev_dbg(&mimio->idev->dev, "input: %s on %s (res = %d).\n",
|
|
- input_dev->name, input_dev->phys, res);
|
|
-
|
|
- usb_set_intfdata(ifc, mimio);
|
|
- mimio->present = 1;
|
|
-
|
|
- /*
|
|
- * Submit the input urb to the usb subsystem.
|
|
- */
|
|
- mimio->in.urb->dev = mimio->udev;
|
|
- res = usb_submit_urb(mimio->in.urb, GFP_KERNEL);
|
|
- if (res) {
|
|
- dev_err(&mimio->idev->dev, "usb_submit_urb failure (%d)\n",
|
|
- res);
|
|
- mimio_dealloc(mimio);
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- /*
|
|
- * Attempt to greet the mimio after giving
|
|
- * it some post-init settling time.
|
|
- *
|
|
- * note: sometimes this sleep interval isn't
|
|
- * long enough to permit the device to re-init
|
|
- * after a hot-swap; maybe need to bump it up.
|
|
- *
|
|
- * As it is, this probably breaks module unloading support!
|
|
- */
|
|
- msleep(1024);
|
|
-
|
|
- res = mimio_greet(mimio);
|
|
- if (res == 0) {
|
|
- dev_dbg(&mimio->idev->dev, "Mimio greeted OK.\n");
|
|
- mimio->greeted = 1;
|
|
- mimio->rxhandler = mimio_rx_handler;
|
|
- } else {
|
|
- dev_dbg(&mimio->idev->dev, "Mimio greet Failure (%d)\n", res);
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int handle_mimio_rx_penupdown(struct mimio *mimio,
|
|
- int down,
|
|
- const char *const instr[],
|
|
- const int instr_ofst[])
|
|
-{
|
|
- int penid, x;
|
|
- if (mimio->pktbuf.q - mimio->pktbuf.p < (down ? 4 : 3))
|
|
- return 1; /* partial pkt */
|
|
-
|
|
- if (down) {
|
|
- x = *mimio->pktbuf.p ^ *(mimio->pktbuf.p + 1) ^
|
|
- *(mimio->pktbuf.p + 2);
|
|
- if (x != *(mimio->pktbuf.p + 3)) {
|
|
- dev_dbg(&mimio->idev->dev, "EV_PEN%s: bad xsum.\n",
|
|
- down ? "DOWN":"UP");
|
|
- /* skip this event data */
|
|
- mimio->pktbuf.p += 4;
|
|
- /* decode any remaining events */
|
|
- return 0;
|
|
- }
|
|
- penid = mimio->pktbuf.instr = *(mimio->pktbuf.p + 2);
|
|
- if (penid > MIMIO_PEN_MAX) {
|
|
- dev_dbg(&mimio->idev->dev,
|
|
- "Unmapped penID (not in [0, %d]): %d\n",
|
|
- MIMIO_PEN_MAX, (int)mimio->pktbuf.instr);
|
|
- penid = mimio->pktbuf.instr = 0;
|
|
- }
|
|
- mimio->last_pen_down = penid;
|
|
- } else {
|
|
- penid = mimio->last_pen_down;
|
|
- }
|
|
- dev_dbg(&mimio->idev->dev, "%s (id %d, code %d) %s.\n", instr[penid],
|
|
- instr_ofst[penid], penid, down ? "down" : "up");
|
|
-
|
|
- if (instr_ofst[penid] >= 0) {
|
|
- int code = BTN_TOOL_PEN + instr_ofst[penid];
|
|
- int value = down ? DOWNVALUE : UPVALUE;
|
|
- if (code > KEY_MAX)
|
|
- dev_dbg(&mimio->idev->dev, "input_event will ignore "
|
|
- "-- code (%d) > KEY_MAX\n", code);
|
|
- if (!test_bit(code, mimio->idev->keybit))
|
|
- dev_dbg(&mimio->idev->dev, "input_event will ignore "
|
|
- "-- bit for code (%d) not enabled\n", code);
|
|
- if (!!test_bit(code, mimio->idev->key) == value)
|
|
- dev_dbg(&mimio->idev->dev, "input_event will ignore "
|
|
- "-- bit for code (%d) already set to %d\n",
|
|
- code, value);
|
|
- if (value != DOWNVALUE) {
|
|
- /* input_regs(mimio->idev, regs); */
|
|
- input_report_key(mimio->idev, code, value);
|
|
- input_sync(mimio->idev);
|
|
- } else {
|
|
- /* wait until we get some coordinates */
|
|
- }
|
|
- } else {
|
|
- dev_dbg(&mimio->idev->dev, "penID offset[%d] == %d is < 0 "
|
|
- "- not sending\n", penid, instr_ofst[penid]);
|
|
- }
|
|
- mimio->pktbuf.p += down ? 4 : 3; /* 3 for up, 4 for down */
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/*
|
|
- * Stay tuned for partial-packet excitement.
|
|
- *
|
|
- * This routine buffers data packets received from the mimio device
|
|
- * in the mimio's data space. This buffering is necessary because
|
|
- * the mimio's in endpoint can serve us partial packets of data, and
|
|
- * we want the driver to support the servicing of multiple mimios.
|
|
- * Empirical evidence gathered so far suggests that the method of
|
|
- * buffering packet data in the mimio's data space works. Previous
|
|
- * versions of this driver did not buffer packet data in each mimio's
|
|
- * data-space, and were therefore not able to service multiple mimios.
|
|
- * Note that since the caller of this routine is running in interrupt
|
|
- * context, care needs to be taken to ensure that this routine does not
|
|
- * become bloated, and it may be that another spinlock is needed in each
|
|
- * mimio to guard the buffered packet data properly.
|
|
- */
|
|
-static void mimio_rx_handler(struct mimio *mimio,
|
|
- unsigned char *data,
|
|
- unsigned int nbytes)
|
|
-{
|
|
- struct device *dev = &mimio->idev->dev;
|
|
- unsigned int x;
|
|
- unsigned int y;
|
|
- static const char * const instr[] = {
|
|
- "?0",
|
|
- "black pen", "blue pen", "green pen", "red pen",
|
|
- "brown pen", "orange pen", "purple pen", "yellow pen",
|
|
- "big eraser", "lil eraser",
|
|
- "?11", "?12", "?13", "?14", "?15", "?16",
|
|
- "mimio interactive", "interactive button1",
|
|
- "interactive button2"
|
|
- };
|
|
-
|
|
- /* Mimio Interactive gives:
|
|
- * down: [0x22 0x01 0x11 0x32 0x24]
|
|
- * b1 : [0x22 0x01 0x12 0x31 0x24]
|
|
- * b2 : [0x22 0x01 0x13 0x30 0x24]
|
|
- */
|
|
- static const int instr_ofst[] = {
|
|
- -1,
|
|
- 0, 1, 2, 3,
|
|
- 9, 9, 9, 9,
|
|
- 4, 5,
|
|
- -1, -1, -1, -1, -1, -1,
|
|
- 6, 7, 8,
|
|
- };
|
|
-
|
|
- memcpy(mimio->pktbuf.q, data, nbytes);
|
|
- mimio->pktbuf.q += nbytes;
|
|
-
|
|
- while (mimio->pktbuf.p < mimio->pktbuf.q) {
|
|
- int t = *mimio->pktbuf.p;
|
|
- switch (t) {
|
|
- case MIMIO_EV_PENUP:
|
|
- case MIMIO_EV_PENDOWN:
|
|
- if (handle_mimio_rx_penupdown(mimio,
|
|
- t == MIMIO_EV_PENDOWN,
|
|
- instr, instr_ofst))
|
|
- return; /* partial packet */
|
|
- break;
|
|
-
|
|
- case MIMIO_EV_PENDATA:
|
|
- if (mimio->pktbuf.q - mimio->pktbuf.p < 6)
|
|
- /* partial pkt */
|
|
- return;
|
|
- x = *mimio->pktbuf.p ^ *(mimio->pktbuf.p + 1) ^
|
|
- *(mimio->pktbuf.p + 2) ^
|
|
- *(mimio->pktbuf.p + 3) ^
|
|
- *(mimio->pktbuf.p + 4);
|
|
- if (x != *(mimio->pktbuf.p + 5)) {
|
|
- dev_dbg(dev, "EV_PENDATA: bad xsum.\n");
|
|
- mimio->pktbuf.p += 6; /* skip this event data */
|
|
- break; /* decode any remaining events */
|
|
- }
|
|
- x = *(mimio->pktbuf.p + 1);
|
|
- x <<= 8;
|
|
- x |= *(mimio->pktbuf.p + 2);
|
|
- y = *(mimio->pktbuf.p + 3);
|
|
- y <<= 8;
|
|
- y |= *(mimio->pktbuf.p + 4);
|
|
- dev_dbg(dev, "coord: (%d, %d)\n", x, y);
|
|
- if (instr_ofst[mimio->pktbuf.instr] >= 0) {
|
|
- int code = BTN_TOOL_PEN +
|
|
- instr_ofst[mimio->last_pen_down];
|
|
-#if 0
|
|
- /* Utter hack to ensure we get forwarded _AND_
|
|
- * so we can identify when a complete signal is
|
|
- * received */
|
|
- mimio->idev->abs[ABS_Y] = -1;
|
|
- mimio->idev->abs[ABS_X] = -1;
|
|
-#endif
|
|
- /* input_regs(mimio->idev, regs); */
|
|
- input_report_abs(mimio->idev, ABS_X, x);
|
|
- input_report_abs(mimio->idev, ABS_Y, y);
|
|
- /* fake a penup */
|
|
- change_bit(code, mimio->idev->key);
|
|
- input_report_key(mimio->idev,
|
|
- code,
|
|
- DOWNVALUE);
|
|
- /* always sync here */
|
|
- mimio->idev->sync = 0;
|
|
- input_sync(mimio->idev);
|
|
- }
|
|
- mimio->pktbuf.p += 6;
|
|
- break;
|
|
- case MIMIO_EV_MEMRESET:
|
|
- if (mimio->pktbuf.q - mimio->pktbuf.p < 7)
|
|
- /* partial pkt */
|
|
- return;
|
|
- dev_dbg(dev, "mem-reset.\n");
|
|
- /* input_regs(mimio->idev, regs); */
|
|
- input_event(mimio->idev, EV_KEY, BTN_0, 1);
|
|
- input_event(mimio->idev, EV_KEY, BTN_0, 0);
|
|
- input_sync(mimio->idev);
|
|
- mimio->pktbuf.p += 7;
|
|
- break;
|
|
- case MIMIO_EV_ACC:
|
|
- if (mimio->pktbuf.q - mimio->pktbuf.p < 4)
|
|
- /* partial pkt */
|
|
- return;
|
|
- x = *mimio->pktbuf.p ^ *(mimio->pktbuf.p + 1) ^
|
|
- *(mimio->pktbuf.p + 2);
|
|
- if (x != *(mimio->pktbuf.p + 3)) {
|
|
- dev_dbg(dev, "EV_ACC: bad xsum.\n");
|
|
- mimio->pktbuf.p += 4; /* skip this event data */
|
|
- break; /* decode any remaining events */
|
|
- }
|
|
- switch (*(mimio->pktbuf.p + 2)) {
|
|
- case ACC_NEWPAGE:
|
|
- dev_dbg(&mimio->idev->dev, "new-page.\n");
|
|
- /* input_regs(mimio->idev, regs); */
|
|
- input_event(mimio->idev, EV_KEY, BTN_1, 1);
|
|
- input_event(mimio->idev, EV_KEY, BTN_1, 0);
|
|
- input_sync(mimio->idev);
|
|
- break;
|
|
- case ACC_TAGPAGE:
|
|
- dev_dbg(&mimio->idev->dev, "tag-page.\n");
|
|
- /* input_regs(mimio->idev, regs); */
|
|
- input_event(mimio->idev, EV_KEY, BTN_2, 1);
|
|
- input_event(mimio->idev, EV_KEY, BTN_2, 0);
|
|
- input_sync(mimio->idev);
|
|
- break;
|
|
- case ACC_PRINTPAGE:
|
|
- dev_dbg(&mimio->idev->dev, "print-page.\n");
|
|
- /* input_regs(mimio->idev, regs);*/
|
|
- input_event(mimio->idev, EV_KEY, BTN_3, 1);
|
|
- input_event(mimio->idev, EV_KEY, BTN_3, 0);
|
|
- input_sync(mimio->idev);
|
|
- break;
|
|
- case ACC_MAXIMIZE:
|
|
- dev_dbg(&mimio->idev->dev,
|
|
- "maximize-window.\n");
|
|
- /* input_regs(mimio->idev, regs); */
|
|
- input_event(mimio->idev, EV_KEY, BTN_4, 1);
|
|
- input_event(mimio->idev, EV_KEY, BTN_4, 0);
|
|
- input_sync(mimio->idev);
|
|
- break;
|
|
- case ACC_FINDCTLPNL:
|
|
- dev_dbg(&mimio->idev->dev, "find-ctl-panel.\n");
|
|
- /* input_regs(mimio->idev, regs); */
|
|
- input_event(mimio->idev, EV_KEY, BTN_5, 1);
|
|
- input_event(mimio->idev, EV_KEY, BTN_5, 0);
|
|
- input_sync(mimio->idev);
|
|
- break;
|
|
- case ACC_DONE:
|
|
- dev_dbg(&mimio->idev->dev, "acc-done.\n");
|
|
- /* no event is dispatched to the input
|
|
- * subsystem for this device event.
|
|
- */
|
|
- break;
|
|
- default:
|
|
- dev_dbg(dev, "unknown acc event.\n");
|
|
- break;
|
|
- }
|
|
- mimio->pktbuf.p += 4;
|
|
- break;
|
|
- default:
|
|
- mimio->pktbuf.p++;
|
|
- break;
|
|
- }
|
|
- }
|
|
-
|
|
- /*
|
|
- * No partial event was received, so reset mimio's pktbuf ptrs.
|
|
- */
|
|
- mimio->pktbuf.p = mimio->pktbuf.q = mimio->pktbuf.buf;
|
|
-}
|
|
-
|
|
-static int mimio_tx(struct mimio *mimio, const char *buf, int nbytes)
|
|
-{
|
|
- int rslt;
|
|
- int timeout;
|
|
- unsigned long flags;
|
|
- DECLARE_WAITQUEUE(wait, current);
|
|
-
|
|
- if (!(isvalidtxsize(nbytes))) {
|
|
- dev_err(&mimio->idev->dev, "invalid arg: nbytes: %d.\n",
|
|
- nbytes);
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- /*
|
|
- * Init the out urb and copy the data to send.
|
|
- */
|
|
- mimio->out.urb->dev = mimio->udev;
|
|
- mimio->out.urb->transfer_buffer_length = nbytes;
|
|
- memcpy(mimio->out.urb->transfer_buffer, buf, nbytes);
|
|
-
|
|
- /*
|
|
- * Send the data.
|
|
- */
|
|
- spin_lock_irqsave(&mimio->txlock, flags);
|
|
- mimio->txflags = MIMIO_TXWAIT;
|
|
- rslt = usb_submit_urb(mimio->out.urb, GFP_ATOMIC);
|
|
- spin_unlock_irqrestore(&mimio->txlock, flags);
|
|
- dev_dbg(&mimio->idev->dev, "rslt: %d.\n", rslt);
|
|
-
|
|
- if (rslt) {
|
|
- dev_err(&mimio->idev->dev, "usb_submit_urb failure: %d.\n",
|
|
- rslt);
|
|
- return rslt;
|
|
- }
|
|
-
|
|
- /*
|
|
- * Wait for completion to be signalled (the mimio_irq_out
|
|
- * completion routine will or MIMIO_TXDONE in with txflags).
|
|
- */
|
|
- timeout = HZ;
|
|
- set_current_state(TASK_INTERRUPTIBLE);
|
|
- add_wait_queue(&mimio->waitq, &wait);
|
|
-
|
|
- while (timeout && ((mimio->txflags & MIMIO_TXDONE) == 0)) {
|
|
- timeout = schedule_timeout(timeout);
|
|
- rmb();
|
|
- }
|
|
-
|
|
- if ((mimio->txflags & MIMIO_TXDONE) == 0)
|
|
- dev_dbg(&mimio->idev->dev, "tx timed out.\n");
|
|
-
|
|
- /*
|
|
- * Now that completion has been signalled,
|
|
- * unlink the urb so that it can be recycled.
|
|
- */
|
|
- set_current_state(TASK_RUNNING);
|
|
- remove_wait_queue(&mimio->waitq, &wait);
|
|
- usb_unlink_urb(mimio->out.urb);
|
|
-
|
|
- return rslt;
|
|
-}
|
|
-
|
|
-static int __init mimio_init(void)
|
|
-{
|
|
- int rslt;
|
|
-
|
|
- rslt = usb_register(&mimio_driver);
|
|
- if (rslt != 0) {
|
|
- err("%s: usb_register failure: %d", __func__, rslt);
|
|
- return rslt;
|
|
- }
|
|
-
|
|
- printk(KERN_INFO KBUILD_MODNAME ":"
|
|
- DRIVER_DESC " " DRIVER_VERSION "\n");
|
|
- return rslt;
|
|
-}
|
|
-
|
|
-static void __exit mimio_exit(void)
|
|
-{
|
|
- usb_deregister(&mimio_driver);
|
|
-}
|
|
-
|
|
-module_init(mimio_init);
|
|
-module_exit(mimio_exit);
|
|
-
|
|
-MODULE_AUTHOR(DRIVER_AUTHOR);
|
|
-MODULE_DESCRIPTION(DRIVER_DESC);
|
|
-MODULE_LICENSE("GPL");
|
|
diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c
|
|
index f69b778..cd25811 100644
|
|
--- a/drivers/staging/pohmelfs/inode.c
|
|
+++ b/drivers/staging/pohmelfs/inode.c
|
|
@@ -36,6 +36,7 @@
|
|
#define POHMELFS_MAGIC_NUM 0x504f482e
|
|
|
|
static struct kmem_cache *pohmelfs_inode_cache;
|
|
+static atomic_t psb_bdi_num = ATOMIC_INIT(0);
|
|
|
|
/*
|
|
* Removes inode from all trees, drops local name cache and removes all queued
|
|
@@ -1331,6 +1332,8 @@ static void pohmelfs_put_super(struct super_block *sb)
|
|
pohmelfs_crypto_exit(psb);
|
|
pohmelfs_state_exit(psb);
|
|
|
|
+ bdi_destroy(&psb->bdi);
|
|
+
|
|
kfree(psb);
|
|
sb->s_fs_info = NULL;
|
|
}
|
|
@@ -1815,11 +1818,22 @@ static int pohmelfs_fill_super(struct super_block *sb, void *data, int silent)
|
|
if (!psb)
|
|
goto err_out_exit;
|
|
|
|
+ err = bdi_init(&psb->bdi);
|
|
+ if (err)
|
|
+ goto err_out_free_sb;
|
|
+
|
|
+ err = bdi_register(&psb->bdi, NULL, "pfs-%d", atomic_inc_return(&psb_bdi_num));
|
|
+ if (err) {
|
|
+ bdi_destroy(&psb->bdi);
|
|
+ goto err_out_free_sb;
|
|
+ }
|
|
+
|
|
sb->s_fs_info = psb;
|
|
sb->s_op = &pohmelfs_sb_ops;
|
|
sb->s_magic = POHMELFS_MAGIC_NUM;
|
|
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
|
sb->s_blocksize = PAGE_SIZE;
|
|
+ sb->s_bdi = &psb->bdi;
|
|
|
|
psb->sb = sb;
|
|
|
|
@@ -1863,11 +1877,11 @@ static int pohmelfs_fill_super(struct super_block *sb, void *data, int silent)
|
|
|
|
err = pohmelfs_parse_options((char *) data, psb, 0);
|
|
if (err)
|
|
- goto err_out_free_sb;
|
|
+ goto err_out_free_bdi;
|
|
|
|
err = pohmelfs_copy_crypto(psb);
|
|
if (err)
|
|
- goto err_out_free_sb;
|
|
+ goto err_out_free_bdi;
|
|
|
|
err = pohmelfs_state_init(psb);
|
|
if (err)
|
|
@@ -1916,6 +1930,8 @@ err_out_state_exit:
|
|
err_out_free_strings:
|
|
kfree(psb->cipher_string);
|
|
kfree(psb->hash_string);
|
|
+err_out_free_bdi:
|
|
+ bdi_destroy(&psb->bdi);
|
|
err_out_free_sb:
|
|
kfree(psb);
|
|
err_out_exit:
|
|
diff --git a/drivers/staging/pohmelfs/netfs.h b/drivers/staging/pohmelfs/netfs.h
|
|
index 623a07d..01cba00 100644
|
|
--- a/drivers/staging/pohmelfs/netfs.h
|
|
+++ b/drivers/staging/pohmelfs/netfs.h
|
|
@@ -18,6 +18,7 @@
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/connector.h>
|
|
+#include <linux/backing-dev.h>
|
|
|
|
#define POHMELFS_CN_IDX 5
|
|
#define POHMELFS_CN_VAL 0
|
|
@@ -624,6 +625,8 @@ struct pohmelfs_sb {
|
|
|
|
struct super_block *sb;
|
|
|
|
+ struct backing_dev_info bdi;
|
|
+
|
|
/*
|
|
* Algorithm strings.
|
|
*/
|
|
diff --git a/drivers/staging/wlan-ng/Kconfig b/drivers/staging/wlan-ng/Kconfig
|
|
index f44294b..f1af507 100644
|
|
--- a/drivers/staging/wlan-ng/Kconfig
|
|
+++ b/drivers/staging/wlan-ng/Kconfig
|
|
@@ -1,6 +1,7 @@
|
|
config PRISM2_USB
|
|
tristate "Prism2.5/3 USB driver"
|
|
depends on WLAN && USB && WIRELESS_EXT
|
|
+ select WEXT_PRIV
|
|
default n
|
|
---help---
|
|
This is the wlan-ng prism 2.5/3 USB driver for a wide range of
|
|
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
|
|
index 60a45f1..ca479a7 100644
|
|
--- a/drivers/usb/core/driver.c
|
|
+++ b/drivers/usb/core/driver.c
|
|
@@ -691,9 +691,6 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|
{
|
|
struct usb_device *usb_dev;
|
|
|
|
- /* driver is often null here; dev_dbg() would oops */
|
|
- pr_debug("usb %s: uevent\n", dev_name(dev));
|
|
-
|
|
if (is_usb_device(dev)) {
|
|
usb_dev = to_usb_device(dev);
|
|
} else if (is_usb_interface(dev)) {
|
|
@@ -705,6 +702,7 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|
}
|
|
|
|
if (usb_dev->devnum < 0) {
|
|
+ /* driver is often null here; dev_dbg() would oops */
|
|
pr_debug("usb %s: already deleted?\n", dev_name(dev));
|
|
return -ENODEV;
|
|
}
|
|
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
|
|
index 80995ef..0477616 100644
|
|
--- a/drivers/usb/core/hcd.c
|
|
+++ b/drivers/usb/core/hcd.c
|
|
@@ -141,7 +141,7 @@ static const u8 usb3_rh_dev_descriptor[18] = {
|
|
0x09, /* __u8 bMaxPacketSize0; 2^9 = 512 Bytes */
|
|
|
|
0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */
|
|
- 0x02, 0x00, /* __le16 idProduct; device 0x0002 */
|
|
+ 0x03, 0x00, /* __le16 idProduct; device 0x0003 */
|
|
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
|
|
|
|
0x03, /* __u8 iManufacturer; */
|
|
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
|
|
index bbe2b92..89613a7 100644
|
|
--- a/drivers/usb/core/hcd.h
|
|
+++ b/drivers/usb/core/hcd.h
|
|
@@ -248,7 +248,7 @@ struct hc_driver {
|
|
/* xHCI specific functions */
|
|
/* Called by usb_alloc_dev to alloc HC device structures */
|
|
int (*alloc_dev)(struct usb_hcd *, struct usb_device *);
|
|
- /* Called by usb_release_dev to free HC device structures */
|
|
+ /* Called by usb_disconnect to free HC device structures */
|
|
void (*free_dev)(struct usb_hcd *, struct usb_device *);
|
|
|
|
/* Bandwidth computation functions */
|
|
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
|
|
index 35cc8b9..9cc0aba 100644
|
|
--- a/drivers/usb/core/hub.c
|
|
+++ b/drivers/usb/core/hub.c
|
|
@@ -1554,6 +1554,15 @@ static inline void usb_stop_pm(struct usb_device *udev)
|
|
|
|
#endif
|
|
|
|
+static void hub_free_dev(struct usb_device *udev)
|
|
+{
|
|
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
|
|
+
|
|
+ /* Root hubs aren't real devices, so don't free HCD resources */
|
|
+ if (hcd->driver->free_dev && udev->parent)
|
|
+ hcd->driver->free_dev(hcd, udev);
|
|
+}
|
|
+
|
|
/**
|
|
* usb_disconnect - disconnect a device (usbcore-internal)
|
|
* @pdev: pointer to device being disconnected
|
|
@@ -1624,6 +1633,8 @@ void usb_disconnect(struct usb_device **pdev)
|
|
|
|
usb_stop_pm(udev);
|
|
|
|
+ hub_free_dev(udev);
|
|
+
|
|
put_device(&udev->dev);
|
|
}
|
|
|
|
@@ -3191,6 +3202,7 @@ loop_disable:
|
|
loop:
|
|
usb_ep0_reinit(udev);
|
|
release_address(udev);
|
|
+ hub_free_dev(udev);
|
|
usb_put_dev(udev);
|
|
if ((status == -ENOTCONN) || (status == -ENOTSUPP))
|
|
break;
|
|
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
|
|
index 0daff0d..ced0776 100644
|
|
--- a/drivers/usb/core/usb.c
|
|
+++ b/drivers/usb/core/usb.c
|
|
@@ -228,9 +228,6 @@ static void usb_release_dev(struct device *dev)
|
|
hcd = bus_to_hcd(udev->bus);
|
|
|
|
usb_destroy_configuration(udev);
|
|
- /* Root hubs aren't real devices, so don't free HCD resources */
|
|
- if (hcd->driver->free_dev && udev->parent)
|
|
- hcd->driver->free_dev(hcd, udev);
|
|
usb_put_hcd(hcd);
|
|
kfree(udev->product);
|
|
kfree(udev->manufacturer);
|
|
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
|
|
index a37640e..73f9bbd 100644
|
|
--- a/drivers/usb/gadget/f_mass_storage.c
|
|
+++ b/drivers/usb/gadget/f_mass_storage.c
|
|
@@ -2852,7 +2852,6 @@ error_release:
|
|
/* Call fsg_common_release() directly, ref might be not
|
|
* initialised */
|
|
fsg_common_release(&common->ref);
|
|
- complete(&common->thread_notifier);
|
|
return ERR_PTR(rc);
|
|
}
|
|
|
|
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
|
|
index 2769326..cd74bbd 100644
|
|
--- a/drivers/usb/host/ohci-pnx4008.c
|
|
+++ b/drivers/usb/host/ohci-pnx4008.c
|
|
@@ -327,7 +327,7 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
|
|
}
|
|
i2c_adap = i2c_get_adapter(2);
|
|
memset(&i2c_info, 0, sizeof(struct i2c_board_info));
|
|
- strlcpy(i2c_info.name, "isp1301_pnx", I2C_NAME_SIZE);
|
|
+ strlcpy(i2c_info.type, "isp1301_pnx", I2C_NAME_SIZE);
|
|
isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
|
|
normal_i2c);
|
|
i2c_put_adapter(i2c_adap);
|
|
@@ -411,7 +411,7 @@ out3:
|
|
out2:
|
|
clk_put(usb_clk);
|
|
out1:
|
|
- i2c_unregister_client(isp1301_i2c_client);
|
|
+ i2c_unregister_device(isp1301_i2c_client);
|
|
isp1301_i2c_client = NULL;
|
|
out_i2c_driver:
|
|
i2c_del_driver(&isp1301_driver);
|
|
@@ -430,7 +430,7 @@ static int usb_hcd_pnx4008_remove(struct platform_device *pdev)
|
|
pnx4008_unset_usb_bits();
|
|
clk_disable(usb_clk);
|
|
clk_put(usb_clk);
|
|
- i2c_unregister_client(isp1301_i2c_client);
|
|
+ i2c_unregister_device(isp1301_i2c_client);
|
|
isp1301_i2c_client = NULL;
|
|
i2c_del_driver(&isp1301_driver);
|
|
|
|
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
|
|
index 99cd00f..0919706 100644
|
|
--- a/drivers/usb/host/uhci-hcd.c
|
|
+++ b/drivers/usb/host/uhci-hcd.c
|
|
@@ -735,6 +735,7 @@ static void uhci_stop(struct usb_hcd *hcd)
|
|
uhci_hc_died(uhci);
|
|
uhci_scan_schedule(uhci);
|
|
spin_unlock_irq(&uhci->lock);
|
|
+ synchronize_irq(hcd->irq);
|
|
|
|
del_timer_sync(&uhci->fsbr_timer);
|
|
release_uhci(uhci);
|
|
diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h
|
|
index ecc131c..78c4eda 100644
|
|
--- a/drivers/usb/host/xhci-ext-caps.h
|
|
+++ b/drivers/usb/host/xhci-ext-caps.h
|
|
@@ -101,12 +101,15 @@ static inline int xhci_find_next_cap_offset(void __iomem *base, int ext_offset)
|
|
|
|
next = readl(base + ext_offset);
|
|
|
|
- if (ext_offset == XHCI_HCC_PARAMS_OFFSET)
|
|
+ if (ext_offset == XHCI_HCC_PARAMS_OFFSET) {
|
|
/* Find the first extended capability */
|
|
next = XHCI_HCC_EXT_CAPS(next);
|
|
- else
|
|
+ ext_offset = 0;
|
|
+ } else {
|
|
/* Find the next extended capability */
|
|
next = XHCI_EXT_CAPS_NEXT(next);
|
|
+ }
|
|
+
|
|
if (!next)
|
|
return 0;
|
|
/*
|
|
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
|
|
index bd254ec..7d920f2 100644
|
|
--- a/drivers/usb/serial/cp210x.c
|
|
+++ b/drivers/usb/serial/cp210x.c
|
|
@@ -91,11 +91,12 @@ static struct usb_device_id id_table [] = {
|
|
{ USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
|
|
{ USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */
|
|
{ USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */
|
|
+ { USB_DEVICE(0x10C4, 0x81E8) }, /* Zephyr Bioharness */
|
|
{ USB_DEVICE(0x10C4, 0x81F2) }, /* C1007 HF band RFID controller */
|
|
{ USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
|
|
{ USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */
|
|
{ USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demostration module */
|
|
- { USB_DEVICE(0x10c4, 0x8293) }, /* Telegesys ETRX2USB */
|
|
+ { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesys ETRX2USB */
|
|
{ USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */
|
|
{ USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
|
|
{ USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */
|
|
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
|
|
index 7638828..34acf6c 100644
|
|
--- a/drivers/usb/serial/ftdi_sio.c
|
|
+++ b/drivers/usb/serial/ftdi_sio.c
|
|
@@ -614,6 +614,7 @@ static struct usb_device_id id_table_combined [] = {
|
|
{ USB_DEVICE(FTDI_VID, FTDI_OCEANIC_PID) },
|
|
{ USB_DEVICE(TTI_VID, TTI_QL355P_PID) },
|
|
{ USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
|
|
+ { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) },
|
|
{ USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
|
|
{ USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
|
|
{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
|
|
@@ -737,6 +738,10 @@ static struct usb_device_id id_table_combined [] = {
|
|
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
|
|
{ USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) },
|
|
{ USB_DEVICE(FTDI_VID, HAMEG_HO870_PID) },
|
|
+ { USB_DEVICE(FTDI_VID, MJSG_GENERIC_PID) },
|
|
+ { USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) },
|
|
+ { USB_DEVICE(FTDI_VID, MJSG_HD_RADIO_PID) },
|
|
+ { USB_DEVICE(FTDI_VID, MJSG_XM_RADIO_PID) },
|
|
{ }, /* Optional parameter entry */
|
|
{ } /* Terminating entry */
|
|
};
|
|
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
|
|
index c8951ae..d10b5a8 100644
|
|
--- a/drivers/usb/serial/ftdi_sio_ids.h
|
|
+++ b/drivers/usb/serial/ftdi_sio_ids.h
|
|
@@ -494,6 +494,13 @@
|
|
#define RATOC_PRODUCT_ID_USB60F 0xb020
|
|
|
|
/*
|
|
+ * Contec products (http://www.contec.com)
|
|
+ * Submitted by Daniel Sangorrin
|
|
+ */
|
|
+#define CONTEC_VID 0x06CE /* Vendor ID */
|
|
+#define CONTEC_COM1USBH_PID 0x8311 /* COM-1(USB)H */
|
|
+
|
|
+/*
|
|
* Definitions for B&B Electronics products.
|
|
*/
|
|
#define BANDB_VID 0x0856 /* B&B Electronics Vendor ID */
|
|
@@ -1002,3 +1009,11 @@
|
|
#define EVO_8U232AM_PID 0x02FF /* Evolution robotics RCM2 (FT232AM)*/
|
|
#define EVO_HYBRID_PID 0x0302 /* Evolution robotics RCM4 PID (FT232BM)*/
|
|
#define EVO_RCM4_PID 0x0303 /* Evolution robotics RCM4 PID */
|
|
+
|
|
+/*
|
|
+ * MJS Gadgets HD Radio / XM Radio / Sirius Radio interfaces (using VID 0x0403)
|
|
+ */
|
|
+#define MJSG_GENERIC_PID 0x9378
|
|
+#define MJSG_SR_RADIO_PID 0x9379
|
|
+#define MJSG_XM_RADIO_PID 0x937A
|
|
+#define MJSG_HD_RADIO_PID 0x937C
|
|
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
|
|
index 3eb6143..0cfd621 100644
|
|
--- a/drivers/usb/serial/sierra.c
|
|
+++ b/drivers/usb/serial/sierra.c
|
|
@@ -604,14 +604,17 @@ static void sierra_indat_callback(struct urb *urb)
|
|
} else {
|
|
if (urb->actual_length) {
|
|
tty = tty_port_tty_get(&port->port);
|
|
-
|
|
- tty_buffer_request_room(tty, urb->actual_length);
|
|
- tty_insert_flip_string(tty, data, urb->actual_length);
|
|
- tty_flip_buffer_push(tty);
|
|
-
|
|
- tty_kref_put(tty);
|
|
- usb_serial_debug_data(debug, &port->dev, __func__,
|
|
- urb->actual_length, data);
|
|
+ if (tty) {
|
|
+ tty_buffer_request_room(tty,
|
|
+ urb->actual_length);
|
|
+ tty_insert_flip_string(tty, data,
|
|
+ urb->actual_length);
|
|
+ tty_flip_buffer_push(tty);
|
|
+
|
|
+ tty_kref_put(tty);
|
|
+ usb_serial_debug_data(debug, &port->dev,
|
|
+ __func__, urb->actual_length, data);
|
|
+ }
|
|
} else {
|
|
dev_dbg(&port->dev, "%s: empty read urb"
|
|
" received\n", __func__);
|
|
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
|
|
index 49575fb..98b549b 100644
|
|
--- a/drivers/usb/storage/unusual_devs.h
|
|
+++ b/drivers/usb/storage/unusual_devs.h
|
|
@@ -1147,8 +1147,8 @@ UNUSUAL_DEV( 0x0af0, 0x7401, 0x0000, 0x0000,
|
|
0 ),
|
|
|
|
/* Reported by Jan Dumon <j.dumon@option.com>
|
|
- * This device (wrongly) has a vendor-specific device descriptor.
|
|
- * The entry is needed so usb-storage can bind to it's mass-storage
|
|
+ * These devices (wrongly) have a vendor-specific device descriptor.
|
|
+ * These entries are needed so usb-storage can bind to their mass-storage
|
|
* interface as an interface driver */
|
|
UNUSUAL_DEV( 0x0af0, 0x7501, 0x0000, 0x0000,
|
|
"Option",
|
|
@@ -1156,6 +1156,90 @@ UNUSUAL_DEV( 0x0af0, 0x7501, 0x0000, 0x0000,
|
|
US_SC_DEVICE, US_PR_DEVICE, NULL,
|
|
0 ),
|
|
|
|
+UNUSUAL_DEV( 0x0af0, 0x7701, 0x0000, 0x0000,
|
|
+ "Option",
|
|
+ "GI 0451 SD-Card",
|
|
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
|
|
+ 0 ),
|
|
+
|
|
+UNUSUAL_DEV( 0x0af0, 0x7706, 0x0000, 0x0000,
|
|
+ "Option",
|
|
+ "GI 0451 SD-Card",
|
|
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
|
|
+ 0 ),
|
|
+
|
|
+UNUSUAL_DEV( 0x0af0, 0x7901, 0x0000, 0x0000,
|
|
+ "Option",
|
|
+ "GI 0452 SD-Card",
|
|
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
|
|
+ 0 ),
|
|
+
|
|
+UNUSUAL_DEV( 0x0af0, 0x7A01, 0x0000, 0x0000,
|
|
+ "Option",
|
|
+ "GI 0461 SD-Card",
|
|
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
|
|
+ 0 ),
|
|
+
|
|
+UNUSUAL_DEV( 0x0af0, 0x7A05, 0x0000, 0x0000,
|
|
+ "Option",
|
|
+ "GI 0461 SD-Card",
|
|
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
|
|
+ 0 ),
|
|
+
|
|
+UNUSUAL_DEV( 0x0af0, 0x8300, 0x0000, 0x0000,
|
|
+ "Option",
|
|
+ "GI 033x SD-Card",
|
|
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
|
|
+ 0 ),
|
|
+
|
|
+UNUSUAL_DEV( 0x0af0, 0x8302, 0x0000, 0x0000,
|
|
+ "Option",
|
|
+ "GI 033x SD-Card",
|
|
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
|
|
+ 0 ),
|
|
+
|
|
+UNUSUAL_DEV( 0x0af0, 0x8304, 0x0000, 0x0000,
|
|
+ "Option",
|
|
+ "GI 033x SD-Card",
|
|
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
|
|
+ 0 ),
|
|
+
|
|
+UNUSUAL_DEV( 0x0af0, 0xc100, 0x0000, 0x0000,
|
|
+ "Option",
|
|
+ "GI 070x SD-Card",
|
|
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
|
|
+ 0 ),
|
|
+
|
|
+UNUSUAL_DEV( 0x0af0, 0xd057, 0x0000, 0x0000,
|
|
+ "Option",
|
|
+ "GI 1505 SD-Card",
|
|
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
|
|
+ 0 ),
|
|
+
|
|
+UNUSUAL_DEV( 0x0af0, 0xd058, 0x0000, 0x0000,
|
|
+ "Option",
|
|
+ "GI 1509 SD-Card",
|
|
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
|
|
+ 0 ),
|
|
+
|
|
+UNUSUAL_DEV( 0x0af0, 0xd157, 0x0000, 0x0000,
|
|
+ "Option",
|
|
+ "GI 1515 SD-Card",
|
|
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
|
|
+ 0 ),
|
|
+
|
|
+UNUSUAL_DEV( 0x0af0, 0xd257, 0x0000, 0x0000,
|
|
+ "Option",
|
|
+ "GI 1215 SD-Card",
|
|
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
|
|
+ 0 ),
|
|
+
|
|
+UNUSUAL_DEV( 0x0af0, 0xd357, 0x0000, 0x0000,
|
|
+ "Option",
|
|
+ "GI 1505 SD-Card",
|
|
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
|
|
+ 0 ),
|
|
+
|
|
/* Reported by Ben Efros <ben@pc-doctor.com> */
|
|
UNUSUAL_DEV( 0x0bc2, 0x3010, 0x0000, 0x0000,
|
|
"Seagate",
|
|
diff --git a/drivers/video/sunxvr500.c b/drivers/video/sunxvr500.c
|
|
index 18b9507..4cd5049 100644
|
|
--- a/drivers/video/sunxvr500.c
|
|
+++ b/drivers/video/sunxvr500.c
|
|
@@ -400,6 +400,7 @@ static void __devexit e3d_pci_unregister(struct pci_dev *pdev)
|
|
|
|
static struct pci_device_id e3d_pci_table[] = {
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x7a0), },
|
|
+ { PCI_DEVICE(0x1091, 0x7a0), },
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x7a2), },
|
|
{ .vendor = PCI_VENDOR_ID_3DLABS,
|
|
.device = PCI_ANY_ID,
|
|
diff --git a/fs/file_table.c b/fs/file_table.c
|
|
index b98404b..32d12b7 100644
|
|
--- a/fs/file_table.c
|
|
+++ b/fs/file_table.c
|
|
@@ -393,7 +393,9 @@ retry:
|
|
continue;
|
|
if (!(f->f_mode & FMODE_WRITE))
|
|
continue;
|
|
+ spin_lock(&f->f_lock);
|
|
f->f_mode &= ~FMODE_WRITE;
|
|
+ spin_unlock(&f->f_lock);
|
|
if (file_check_writeable(f) != 0)
|
|
continue;
|
|
file_release_write(f);
|
|
diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c
|
|
index 95e1ca7..3f0cd4d 100644
|
|
--- a/fs/nfs/dns_resolve.c
|
|
+++ b/fs/nfs/dns_resolve.c
|
|
@@ -36,6 +36,19 @@ struct nfs_dns_ent {
|
|
};
|
|
|
|
|
|
+static void nfs_dns_ent_update(struct cache_head *cnew,
|
|
+ struct cache_head *ckey)
|
|
+{
|
|
+ struct nfs_dns_ent *new;
|
|
+ struct nfs_dns_ent *key;
|
|
+
|
|
+ new = container_of(cnew, struct nfs_dns_ent, h);
|
|
+ key = container_of(ckey, struct nfs_dns_ent, h);
|
|
+
|
|
+ memcpy(&new->addr, &key->addr, key->addrlen);
|
|
+ new->addrlen = key->addrlen;
|
|
+}
|
|
+
|
|
static void nfs_dns_ent_init(struct cache_head *cnew,
|
|
struct cache_head *ckey)
|
|
{
|
|
@@ -49,8 +62,7 @@ static void nfs_dns_ent_init(struct cache_head *cnew,
|
|
new->hostname = kstrndup(key->hostname, key->namelen, GFP_KERNEL);
|
|
if (new->hostname) {
|
|
new->namelen = key->namelen;
|
|
- memcpy(&new->addr, &key->addr, key->addrlen);
|
|
- new->addrlen = key->addrlen;
|
|
+ nfs_dns_ent_update(cnew, ckey);
|
|
} else {
|
|
new->namelen = 0;
|
|
new->addrlen = 0;
|
|
@@ -234,7 +246,7 @@ static struct cache_detail nfs_dns_resolve = {
|
|
.cache_show = nfs_dns_show,
|
|
.match = nfs_dns_match,
|
|
.init = nfs_dns_ent_init,
|
|
- .update = nfs_dns_ent_init,
|
|
+ .update = nfs_dns_ent_update,
|
|
.alloc = nfs_dns_ent_alloc,
|
|
};
|
|
|
|
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
|
|
index f19ed86..fcafe60 100644
|
|
--- a/fs/nfsd/nfs4state.c
|
|
+++ b/fs/nfsd/nfs4state.c
|
|
@@ -1998,7 +1998,9 @@ nfs4_file_downgrade(struct file *filp, unsigned int share_access)
|
|
{
|
|
if (share_access & NFS4_SHARE_ACCESS_WRITE) {
|
|
drop_file_write_access(filp);
|
|
+ spin_lock(&filp->f_lock);
|
|
filp->f_mode = (filp->f_mode | FMODE_READ) & ~FMODE_WRITE;
|
|
+ spin_unlock(&filp->f_lock);
|
|
}
|
|
}
|
|
|
|
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
|
|
index 7e9df11..4c2a6d2 100644
|
|
--- a/fs/ocfs2/aops.c
|
|
+++ b/fs/ocfs2/aops.c
|
|
@@ -577,8 +577,9 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
|
|
goto bail;
|
|
}
|
|
|
|
- /* We should already CoW the refcounted extent. */
|
|
- BUG_ON(ext_flags & OCFS2_EXT_REFCOUNTED);
|
|
+ /* We should already CoW the refcounted extent in case of create. */
|
|
+ BUG_ON(create && (ext_flags & OCFS2_EXT_REFCOUNTED));
|
|
+
|
|
/*
|
|
* get_more_blocks() expects us to describe a hole by clearing
|
|
* the mapped bit on bh_result().
|
|
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
|
|
index 699f371..5c4703d 100644
|
|
--- a/fs/sysfs/dir.c
|
|
+++ b/fs/sysfs/dir.c
|
|
@@ -837,11 +837,46 @@ static inline unsigned char dt_type(struct sysfs_dirent *sd)
|
|
return (sd->s_mode >> 12) & 15;
|
|
}
|
|
|
|
+static int sysfs_dir_release(struct inode *inode, struct file *filp)
|
|
+{
|
|
+ sysfs_put(filp->private_data);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct sysfs_dirent *sysfs_dir_pos(struct sysfs_dirent *parent_sd,
|
|
+ ino_t ino, struct sysfs_dirent *pos)
|
|
+{
|
|
+ if (pos) {
|
|
+ int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) &&
|
|
+ pos->s_parent == parent_sd &&
|
|
+ ino == pos->s_ino;
|
|
+ sysfs_put(pos);
|
|
+ if (valid)
|
|
+ return pos;
|
|
+ }
|
|
+ pos = NULL;
|
|
+ if ((ino > 1) && (ino < INT_MAX)) {
|
|
+ pos = parent_sd->s_dir.children;
|
|
+ while (pos && (ino > pos->s_ino))
|
|
+ pos = pos->s_sibling;
|
|
+ }
|
|
+ return pos;
|
|
+}
|
|
+
|
|
+static struct sysfs_dirent *sysfs_dir_next_pos(struct sysfs_dirent *parent_sd,
|
|
+ ino_t ino, struct sysfs_dirent *pos)
|
|
+{
|
|
+ pos = sysfs_dir_pos(parent_sd, ino, pos);
|
|
+ if (pos)
|
|
+ pos = pos->s_sibling;
|
|
+ return pos;
|
|
+}
|
|
+
|
|
static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
|
|
{
|
|
struct dentry *dentry = filp->f_path.dentry;
|
|
struct sysfs_dirent * parent_sd = dentry->d_fsdata;
|
|
- struct sysfs_dirent *pos;
|
|
+ struct sysfs_dirent *pos = filp->private_data;
|
|
ino_t ino;
|
|
|
|
if (filp->f_pos == 0) {
|
|
@@ -857,29 +892,31 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
|
|
if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0)
|
|
filp->f_pos++;
|
|
}
|
|
- if ((filp->f_pos > 1) && (filp->f_pos < INT_MAX)) {
|
|
- mutex_lock(&sysfs_mutex);
|
|
-
|
|
- /* Skip the dentries we have already reported */
|
|
- pos = parent_sd->s_dir.children;
|
|
- while (pos && (filp->f_pos > pos->s_ino))
|
|
- pos = pos->s_sibling;
|
|
-
|
|
- for ( ; pos; pos = pos->s_sibling) {
|
|
- const char * name;
|
|
- int len;
|
|
-
|
|
- name = pos->s_name;
|
|
- len = strlen(name);
|
|
- filp->f_pos = ino = pos->s_ino;
|
|
+ mutex_lock(&sysfs_mutex);
|
|
+ for (pos = sysfs_dir_pos(parent_sd, filp->f_pos, pos);
|
|
+ pos;
|
|
+ pos = sysfs_dir_next_pos(parent_sd, filp->f_pos, pos)) {
|
|
+ const char * name;
|
|
+ unsigned int type;
|
|
+ int len, ret;
|
|
+
|
|
+ name = pos->s_name;
|
|
+ len = strlen(name);
|
|
+ ino = pos->s_ino;
|
|
+ type = dt_type(pos);
|
|
+ filp->f_pos = ino;
|
|
+ filp->private_data = sysfs_get(pos);
|
|
|
|
- if (filldir(dirent, name, len, filp->f_pos, ino,
|
|
- dt_type(pos)) < 0)
|
|
- break;
|
|
- }
|
|
- if (!pos)
|
|
- filp->f_pos = INT_MAX;
|
|
mutex_unlock(&sysfs_mutex);
|
|
+ ret = filldir(dirent, name, len, filp->f_pos, ino, type);
|
|
+ mutex_lock(&sysfs_mutex);
|
|
+ if (ret < 0)
|
|
+ break;
|
|
+ }
|
|
+ mutex_unlock(&sysfs_mutex);
|
|
+ if ((filp->f_pos > 1) && !pos) { /* EOF */
|
|
+ filp->f_pos = INT_MAX;
|
|
+ filp->private_data = NULL;
|
|
}
|
|
return 0;
|
|
}
|
|
@@ -888,5 +925,6 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
|
|
const struct file_operations sysfs_dir_operations = {
|
|
.read = generic_read_dir,
|
|
.readdir = sysfs_readdir,
|
|
+ .release = sysfs_dir_release,
|
|
.llseek = generic_file_llseek,
|
|
};
|
|
diff --git a/include/linux/fs.h b/include/linux/fs.h
|
|
index ebb1cd5..f2f68ce 100644
|
|
--- a/include/linux/fs.h
|
|
+++ b/include/linux/fs.h
|
|
@@ -87,6 +87,9 @@ struct inodes_stat_t {
|
|
*/
|
|
#define FMODE_NOCMTIME ((__force fmode_t)2048)
|
|
|
|
+/* Expect random access pattern */
|
|
+#define FMODE_RANDOM ((__force fmode_t)4096)
|
|
+
|
|
/*
|
|
* The below are the various read and write types that we support. Some of
|
|
* them include behavioral modifiers that send information down to the
|
|
diff --git a/include/linux/irq.h b/include/linux/irq.h
|
|
index 451481c..4d9b26e 100644
|
|
--- a/include/linux/irq.h
|
|
+++ b/include/linux/irq.h
|
|
@@ -400,7 +400,9 @@ static inline int irq_has_action(unsigned int irq)
|
|
|
|
/* Dynamic irq helper functions */
|
|
extern void dynamic_irq_init(unsigned int irq);
|
|
+void dynamic_irq_init_keep_chip_data(unsigned int irq);
|
|
extern void dynamic_irq_cleanup(unsigned int irq);
|
|
+void dynamic_irq_cleanup_keep_chip_data(unsigned int irq);
|
|
|
|
/* Set/get chip/data for an IRQ: */
|
|
extern int set_irq_chip(unsigned int irq, struct irq_chip *chip);
|
|
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
|
|
index a3fccc8..99914e6 100644
|
|
--- a/include/linux/netdevice.h
|
|
+++ b/include/linux/netdevice.h
|
|
@@ -136,7 +136,7 @@ static inline bool dev_xmit_complete(int rc)
|
|
* used.
|
|
*/
|
|
|
|
-#if defined(CONFIG_WLAN_80211) || defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
|
|
+#if defined(CONFIG_WLAN) || defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
|
|
# if defined(CONFIG_MAC80211_MESH)
|
|
# define LL_MAX_HEADER 128
|
|
# else
|
|
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
|
|
index a177698..c8ea0c7 100644
|
|
--- a/include/linux/perf_event.h
|
|
+++ b/include/linux/perf_event.h
|
|
@@ -496,9 +496,8 @@ struct hw_perf_event {
|
|
atomic64_t period_left;
|
|
u64 interrupts;
|
|
|
|
- u64 freq_count;
|
|
- u64 freq_interrupts;
|
|
- u64 freq_stamp;
|
|
+ u64 freq_time_stamp;
|
|
+ u64 freq_count_stamp;
|
|
#endif
|
|
};
|
|
|
|
diff --git a/include/linux/sched.h b/include/linux/sched.h
|
|
index 78efe7c..1f5fa53 100644
|
|
--- a/include/linux/sched.h
|
|
+++ b/include/linux/sched.h
|
|
@@ -878,7 +878,10 @@ static inline int sd_balance_for_mc_power(void)
|
|
if (sched_smt_power_savings)
|
|
return SD_POWERSAVINGS_BALANCE;
|
|
|
|
- return SD_PREFER_SIBLING;
|
|
+ if (!sched_mc_power_savings)
|
|
+ return SD_PREFER_SIBLING;
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
static inline int sd_balance_for_package_power(void)
|
|
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
|
|
index ae836fd..ec226a2 100644
|
|
--- a/include/linux/skbuff.h
|
|
+++ b/include/linux/skbuff.h
|
|
@@ -315,22 +315,23 @@ struct sk_buff {
|
|
struct sk_buff *next;
|
|
struct sk_buff *prev;
|
|
|
|
- struct sock *sk;
|
|
ktime_t tstamp;
|
|
+
|
|
+ struct sock *sk;
|
|
struct net_device *dev;
|
|
|
|
- unsigned long _skb_dst;
|
|
-#ifdef CONFIG_XFRM
|
|
- struct sec_path *sp;
|
|
-#endif
|
|
/*
|
|
* This is the control buffer. It is free to use for every
|
|
* layer. Please put your private variables there. If you
|
|
* want to keep them across layers you have to do a skb_clone()
|
|
* first. This is owned by whoever has the skb queued ATM.
|
|
*/
|
|
- char cb[48];
|
|
+ char cb[48] __aligned(8);
|
|
|
|
+ unsigned long _skb_dst;
|
|
+#ifdef CONFIG_XFRM
|
|
+ struct sec_path *sp;
|
|
+#endif
|
|
unsigned int len,
|
|
data_len;
|
|
__u16 mac_len,
|
|
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
|
|
index 207466a..2540770 100644
|
|
--- a/include/linux/syscalls.h
|
|
+++ b/include/linux/syscalls.h
|
|
@@ -132,7 +132,8 @@ struct perf_event_attr;
|
|
|
|
#define SYSCALL_TRACE_ENTER_EVENT(sname) \
|
|
static const struct syscall_metadata __syscall_meta_##sname; \
|
|
- static struct ftrace_event_call event_enter_##sname; \
|
|
+ static struct ftrace_event_call \
|
|
+ __attribute__((__aligned__(4))) event_enter_##sname; \
|
|
static struct trace_event enter_syscall_print_##sname = { \
|
|
.trace = print_syscall_enter, \
|
|
}; \
|
|
@@ -154,7 +155,8 @@ struct perf_event_attr;
|
|
|
|
#define SYSCALL_TRACE_EXIT_EVENT(sname) \
|
|
static const struct syscall_metadata __syscall_meta_##sname; \
|
|
- static struct ftrace_event_call event_exit_##sname; \
|
|
+ static struct ftrace_event_call \
|
|
+ __attribute__((__aligned__(4))) event_exit_##sname; \
|
|
static struct trace_event exit_syscall_print_##sname = { \
|
|
.trace = print_syscall_exit, \
|
|
}; \
|
|
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
|
|
index c6fe03e..1ca4990 100644
|
|
--- a/include/trace/ftrace.h
|
|
+++ b/include/trace/ftrace.h
|
|
@@ -65,7 +65,8 @@
|
|
};
|
|
#undef DEFINE_EVENT
|
|
#define DEFINE_EVENT(template, name, proto, args) \
|
|
- static struct ftrace_event_call event_##name
|
|
+ static struct ftrace_event_call \
|
|
+ __attribute__((__aligned__(4))) event_##name
|
|
|
|
#undef DEFINE_EVENT_PRINT
|
|
#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
|
|
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
|
|
index ecc3fa2..d70394f 100644
|
|
--- a/kernel/irq/chip.c
|
|
+++ b/kernel/irq/chip.c
|
|
@@ -18,11 +18,7 @@
|
|
|
|
#include "internals.h"
|
|
|
|
-/**
|
|
- * dynamic_irq_init - initialize a dynamically allocated irq
|
|
- * @irq: irq number to initialize
|
|
- */
|
|
-void dynamic_irq_init(unsigned int irq)
|
|
+static void dynamic_irq_init_x(unsigned int irq, bool keep_chip_data)
|
|
{
|
|
struct irq_desc *desc;
|
|
unsigned long flags;
|
|
@@ -41,7 +37,8 @@ void dynamic_irq_init(unsigned int irq)
|
|
desc->depth = 1;
|
|
desc->msi_desc = NULL;
|
|
desc->handler_data = NULL;
|
|
- desc->chip_data = NULL;
|
|
+ if (!keep_chip_data)
|
|
+ desc->chip_data = NULL;
|
|
desc->action = NULL;
|
|
desc->irq_count = 0;
|
|
desc->irqs_unhandled = 0;
|
|
@@ -55,10 +52,26 @@ void dynamic_irq_init(unsigned int irq)
|
|
}
|
|
|
|
/**
|
|
- * dynamic_irq_cleanup - cleanup a dynamically allocated irq
|
|
+ * dynamic_irq_init - initialize a dynamically allocated irq
|
|
* @irq: irq number to initialize
|
|
*/
|
|
-void dynamic_irq_cleanup(unsigned int irq)
|
|
+void dynamic_irq_init(unsigned int irq)
|
|
+{
|
|
+ dynamic_irq_init_x(irq, false);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * dynamic_irq_init_keep_chip_data - initialize a dynamically allocated irq
|
|
+ * @irq: irq number to initialize
|
|
+ *
|
|
+ * does not set irq_to_desc(irq)->chip_data to NULL
|
|
+ */
|
|
+void dynamic_irq_init_keep_chip_data(unsigned int irq)
|
|
+{
|
|
+ dynamic_irq_init_x(irq, true);
|
|
+}
|
|
+
|
|
+static void dynamic_irq_cleanup_x(unsigned int irq, bool keep_chip_data)
|
|
{
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
|
unsigned long flags;
|
|
@@ -77,7 +90,8 @@ void dynamic_irq_cleanup(unsigned int irq)
|
|
}
|
|
desc->msi_desc = NULL;
|
|
desc->handler_data = NULL;
|
|
- desc->chip_data = NULL;
|
|
+ if (!keep_chip_data)
|
|
+ desc->chip_data = NULL;
|
|
desc->handle_irq = handle_bad_irq;
|
|
desc->chip = &no_irq_chip;
|
|
desc->name = NULL;
|
|
@@ -85,6 +99,26 @@ void dynamic_irq_cleanup(unsigned int irq)
|
|
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
|
}
|
|
|
|
+/**
|
|
+ * dynamic_irq_cleanup - cleanup a dynamically allocated irq
|
|
+ * @irq: irq number to initialize
|
|
+ */
|
|
+void dynamic_irq_cleanup(unsigned int irq)
|
|
+{
|
|
+ dynamic_irq_cleanup_x(irq, false);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * dynamic_irq_cleanup_keep_chip_data - cleanup a dynamically allocated irq
|
|
+ * @irq: irq number to initialize
|
|
+ *
|
|
+ * does not set irq_to_desc(irq)->chip_data to NULL
|
|
+ */
|
|
+void dynamic_irq_cleanup_keep_chip_data(unsigned int irq)
|
|
+{
|
|
+ dynamic_irq_cleanup_x(irq, true);
|
|
+}
|
|
+
|
|
|
|
/**
|
|
* set_irq_chip - set the irq chip for an irq
|
|
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
|
|
index 2ae7409..b707465 100644
|
|
--- a/kernel/perf_event.c
|
|
+++ b/kernel/perf_event.c
|
|
@@ -248,7 +248,7 @@ static void perf_unpin_context(struct perf_event_context *ctx)
|
|
|
|
static inline u64 perf_clock(void)
|
|
{
|
|
- return cpu_clock(smp_processor_id());
|
|
+ return cpu_clock(raw_smp_processor_id());
|
|
}
|
|
|
|
/*
|
|
@@ -1350,14 +1350,83 @@ static void perf_event_cpu_sched_in(struct perf_cpu_context *cpuctx, int cpu)
|
|
|
|
static void perf_log_throttle(struct perf_event *event, int enable);
|
|
|
|
-static void perf_adjust_period(struct perf_event *event, u64 events)
|
|
+static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count)
|
|
+{
|
|
+ u64 frequency = event->attr.sample_freq;
|
|
+ u64 sec = NSEC_PER_SEC;
|
|
+ u64 divisor, dividend;
|
|
+
|
|
+ int count_fls, nsec_fls, frequency_fls, sec_fls;
|
|
+
|
|
+ count_fls = fls64(count);
|
|
+ nsec_fls = fls64(nsec);
|
|
+ frequency_fls = fls64(frequency);
|
|
+ sec_fls = 30;
|
|
+
|
|
+ /*
|
|
+ * We got @count in @nsec, with a target of sample_freq HZ
|
|
+ * the target period becomes:
|
|
+ *
|
|
+ * @count * 10^9
|
|
+ * period = -------------------
|
|
+ * @nsec * sample_freq
|
|
+ *
|
|
+ */
|
|
+
|
|
+ /*
|
|
+ * Reduce accuracy by one bit such that @a and @b converge
|
|
+ * to a similar magnitude.
|
|
+ */
|
|
+#define REDUCE_FLS(a, b) \
|
|
+do { \
|
|
+ if (a##_fls > b##_fls) { \
|
|
+ a >>= 1; \
|
|
+ a##_fls--; \
|
|
+ } else { \
|
|
+ b >>= 1; \
|
|
+ b##_fls--; \
|
|
+ } \
|
|
+} while (0)
|
|
+
|
|
+ /*
|
|
+ * Reduce accuracy until either term fits in a u64, then proceed with
|
|
+ * the other, so that finally we can do a u64/u64 division.
|
|
+ */
|
|
+ while (count_fls + sec_fls > 64 && nsec_fls + frequency_fls > 64) {
|
|
+ REDUCE_FLS(nsec, frequency);
|
|
+ REDUCE_FLS(sec, count);
|
|
+ }
|
|
+
|
|
+ if (count_fls + sec_fls > 64) {
|
|
+ divisor = nsec * frequency;
|
|
+
|
|
+ while (count_fls + sec_fls > 64) {
|
|
+ REDUCE_FLS(count, sec);
|
|
+ divisor >>= 1;
|
|
+ }
|
|
+
|
|
+ dividend = count * sec;
|
|
+ } else {
|
|
+ dividend = count * sec;
|
|
+
|
|
+ while (nsec_fls + frequency_fls > 64) {
|
|
+ REDUCE_FLS(nsec, frequency);
|
|
+ dividend >>= 1;
|
|
+ }
|
|
+
|
|
+ divisor = nsec * frequency;
|
|
+ }
|
|
+
|
|
+ return div64_u64(dividend, divisor);
|
|
+}
|
|
+
|
|
+static void perf_adjust_period(struct perf_event *event, u64 nsec, u64 count)
|
|
{
|
|
struct hw_perf_event *hwc = &event->hw;
|
|
u64 period, sample_period;
|
|
s64 delta;
|
|
|
|
- events *= hwc->sample_period;
|
|
- period = div64_u64(events, event->attr.sample_freq);
|
|
+ period = perf_calculate_period(event, nsec, count);
|
|
|
|
delta = (s64)(period - hwc->sample_period);
|
|
delta = (delta + 7) / 8; /* low pass filter */
|
|
@@ -1368,13 +1437,22 @@ static void perf_adjust_period(struct perf_event *event, u64 events)
|
|
sample_period = 1;
|
|
|
|
hwc->sample_period = sample_period;
|
|
+
|
|
+ if (atomic64_read(&hwc->period_left) > 8*sample_period) {
|
|
+ perf_disable();
|
|
+ event->pmu->disable(event);
|
|
+ atomic64_set(&hwc->period_left, 0);
|
|
+ event->pmu->enable(event);
|
|
+ perf_enable();
|
|
+ }
|
|
}
|
|
|
|
static void perf_ctx_adjust_freq(struct perf_event_context *ctx)
|
|
{
|
|
struct perf_event *event;
|
|
struct hw_perf_event *hwc;
|
|
- u64 interrupts, freq;
|
|
+ u64 interrupts, now;
|
|
+ s64 delta;
|
|
|
|
raw_spin_lock(&ctx->lock);
|
|
list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
|
|
@@ -1395,44 +1473,18 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx)
|
|
if (interrupts == MAX_INTERRUPTS) {
|
|
perf_log_throttle(event, 1);
|
|
event->pmu->unthrottle(event);
|
|
- interrupts = 2*sysctl_perf_event_sample_rate/HZ;
|
|
}
|
|
|
|
if (!event->attr.freq || !event->attr.sample_freq)
|
|
continue;
|
|
|
|
- /*
|
|
- * if the specified freq < HZ then we need to skip ticks
|
|
- */
|
|
- if (event->attr.sample_freq < HZ) {
|
|
- freq = event->attr.sample_freq;
|
|
-
|
|
- hwc->freq_count += freq;
|
|
- hwc->freq_interrupts += interrupts;
|
|
-
|
|
- if (hwc->freq_count < HZ)
|
|
- continue;
|
|
-
|
|
- interrupts = hwc->freq_interrupts;
|
|
- hwc->freq_interrupts = 0;
|
|
- hwc->freq_count -= HZ;
|
|
- } else
|
|
- freq = HZ;
|
|
-
|
|
- perf_adjust_period(event, freq * interrupts);
|
|
+ event->pmu->read(event);
|
|
+ now = atomic64_read(&event->count);
|
|
+ delta = now - hwc->freq_count_stamp;
|
|
+ hwc->freq_count_stamp = now;
|
|
|
|
- /*
|
|
- * In order to avoid being stalled by an (accidental) huge
|
|
- * sample period, force reset the sample period if we didn't
|
|
- * get any events in this freq period.
|
|
- */
|
|
- if (!interrupts) {
|
|
- perf_disable();
|
|
- event->pmu->disable(event);
|
|
- atomic64_set(&hwc->period_left, 0);
|
|
- event->pmu->enable(event);
|
|
- perf_enable();
|
|
- }
|
|
+ if (delta > 0)
|
|
+ perf_adjust_period(event, TICK_NSEC, delta);
|
|
}
|
|
raw_spin_unlock(&ctx->lock);
|
|
}
|
|
@@ -3688,12 +3740,12 @@ static int __perf_event_overflow(struct perf_event *event, int nmi,
|
|
|
|
if (event->attr.freq) {
|
|
u64 now = perf_clock();
|
|
- s64 delta = now - hwc->freq_stamp;
|
|
+ s64 delta = now - hwc->freq_time_stamp;
|
|
|
|
- hwc->freq_stamp = now;
|
|
+ hwc->freq_time_stamp = now;
|
|
|
|
- if (delta > 0 && delta < TICK_NSEC)
|
|
- perf_adjust_period(event, NSEC_PER_SEC / (int)delta);
|
|
+ if (delta > 0 && delta < 2*TICK_NSEC)
|
|
+ perf_adjust_period(event, delta, hwc->last_period);
|
|
}
|
|
|
|
/*
|
|
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
|
|
index 36cb168..fc9ed15 100644
|
|
--- a/kernel/power/snapshot.c
|
|
+++ b/kernel/power/snapshot.c
|
|
@@ -1181,7 +1181,7 @@ static void free_unnecessary_pages(void)
|
|
|
|
memory_bm_position_reset(©_bm);
|
|
|
|
- while (to_free_normal > 0 && to_free_highmem > 0) {
|
|
+ while (to_free_normal > 0 || to_free_highmem > 0) {
|
|
unsigned long pfn = memory_bm_next_pfn(©_bm);
|
|
struct page *page = pfn_to_page(pfn);
|
|
|
|
diff --git a/kernel/sched.c b/kernel/sched.c
|
|
index 3a8fb30..00a59b0 100644
|
|
--- a/kernel/sched.c
|
|
+++ b/kernel/sched.c
|
|
@@ -4119,12 +4119,23 @@ find_busiest_queue(struct sched_group *group, enum cpu_idle_type idle,
|
|
continue;
|
|
|
|
rq = cpu_rq(i);
|
|
- wl = weighted_cpuload(i) * SCHED_LOAD_SCALE;
|
|
- wl /= power;
|
|
+ wl = weighted_cpuload(i);
|
|
|
|
+ /*
|
|
+ * When comparing with imbalance, use weighted_cpuload()
|
|
+ * which is not scaled with the cpu power.
|
|
+ */
|
|
if (capacity && rq->nr_running == 1 && wl > imbalance)
|
|
continue;
|
|
|
|
+ /*
|
|
+ * For the load comparisons with the other cpu's, consider
|
|
+ * the weighted_cpuload() scaled with the cpu power, so that
|
|
+ * the load can be moved away from the cpu that is potentially
|
|
+ * running at a lower capacity.
|
|
+ */
|
|
+ wl = (wl * SCHED_LOAD_SCALE) / power;
|
|
+
|
|
if (wl > max_load) {
|
|
max_load = wl;
|
|
busiest = rq;
|
|
@@ -6054,7 +6065,7 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
|
|
unsigned long flags;
|
|
int oldprio, on_rq, running;
|
|
struct rq *rq;
|
|
- const struct sched_class *prev_class = p->sched_class;
|
|
+ const struct sched_class *prev_class;
|
|
|
|
BUG_ON(prio < 0 || prio > MAX_PRIO);
|
|
|
|
@@ -6062,6 +6073,7 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
|
|
update_rq_clock(rq);
|
|
|
|
oldprio = p->prio;
|
|
+ prev_class = p->sched_class;
|
|
on_rq = p->se.on_rq;
|
|
running = task_current(rq, p);
|
|
if (on_rq)
|
|
@@ -6281,7 +6293,7 @@ static int __sched_setscheduler(struct task_struct *p, int policy,
|
|
{
|
|
int retval, oldprio, oldpolicy = -1, on_rq, running;
|
|
unsigned long flags;
|
|
- const struct sched_class *prev_class = p->sched_class;
|
|
+ const struct sched_class *prev_class;
|
|
struct rq *rq;
|
|
int reset_on_fork;
|
|
|
|
@@ -6395,6 +6407,7 @@ recheck:
|
|
p->sched_reset_on_fork = reset_on_fork;
|
|
|
|
oldprio = p->prio;
|
|
+ prev_class = p->sched_class;
|
|
__setscheduler(rq, p, policy, param->sched_priority);
|
|
|
|
if (running)
|
|
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
|
|
index 4df6a77..a1edaa8 100644
|
|
--- a/kernel/trace/trace.h
|
|
+++ b/kernel/trace/trace.h
|
|
@@ -791,7 +791,8 @@ extern const char *__stop___trace_bprintk_fmt[];
|
|
|
|
#undef FTRACE_ENTRY
|
|
#define FTRACE_ENTRY(call, struct_name, id, tstruct, print) \
|
|
- extern struct ftrace_event_call event_##call;
|
|
+ extern struct ftrace_event_call \
|
|
+ __attribute__((__aligned__(4))) event_##call;
|
|
#undef FTRACE_ENTRY_DUP
|
|
#define FTRACE_ENTRY_DUP(call, struct_name, id, tstruct, print) \
|
|
FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print))
|
|
diff --git a/mm/fadvise.c b/mm/fadvise.c
|
|
index e433592..8d723c9 100644
|
|
--- a/mm/fadvise.c
|
|
+++ b/mm/fadvise.c
|
|
@@ -77,12 +77,20 @@ SYSCALL_DEFINE(fadvise64_64)(int fd, loff_t offset, loff_t len, int advice)
|
|
switch (advice) {
|
|
case POSIX_FADV_NORMAL:
|
|
file->f_ra.ra_pages = bdi->ra_pages;
|
|
+ spin_lock(&file->f_lock);
|
|
+ file->f_mode &= ~FMODE_RANDOM;
|
|
+ spin_unlock(&file->f_lock);
|
|
break;
|
|
case POSIX_FADV_RANDOM:
|
|
- file->f_ra.ra_pages = 0;
|
|
+ spin_lock(&file->f_lock);
|
|
+ file->f_mode |= FMODE_RANDOM;
|
|
+ spin_unlock(&file->f_lock);
|
|
break;
|
|
case POSIX_FADV_SEQUENTIAL:
|
|
file->f_ra.ra_pages = bdi->ra_pages * 2;
|
|
+ spin_lock(&file->f_lock);
|
|
+ file->f_mode &= ~FMODE_RANDOM;
|
|
+ spin_unlock(&file->f_lock);
|
|
break;
|
|
case POSIX_FADV_WILLNEED:
|
|
if (!mapping->a_ops->readpage) {
|
|
diff --git a/mm/readahead.c b/mm/readahead.c
|
|
index 033bc13..337b20e 100644
|
|
--- a/mm/readahead.c
|
|
+++ b/mm/readahead.c
|
|
@@ -501,6 +501,12 @@ void page_cache_sync_readahead(struct address_space *mapping,
|
|
if (!ra->ra_pages)
|
|
return;
|
|
|
|
+ /* be dumb */
|
|
+ if (filp->f_mode & FMODE_RANDOM) {
|
|
+ force_page_cache_readahead(mapping, filp, offset, req_size);
|
|
+ return;
|
|
+ }
|
|
+
|
|
/* do read-ahead */
|
|
ondemand_readahead(mapping, ra, filp, false, offset, req_size);
|
|
}
|
|
diff --git a/mm/slab.c b/mm/slab.c
|
|
index 7451bda..ff44eb2 100644
|
|
--- a/mm/slab.c
|
|
+++ b/mm/slab.c
|
|
@@ -983,13 +983,11 @@ static struct array_cache **alloc_alien_cache(int node, int limit, gfp_t gfp)
|
|
|
|
if (limit > 1)
|
|
limit = 12;
|
|
- ac_ptr = kmalloc_node(memsize, gfp, node);
|
|
+ ac_ptr = kzalloc_node(memsize, gfp, node);
|
|
if (ac_ptr) {
|
|
for_each_node(i) {
|
|
- if (i == node || !node_online(i)) {
|
|
- ac_ptr[i] = NULL;
|
|
+ if (i == node || !node_online(i))
|
|
continue;
|
|
- }
|
|
ac_ptr[i] = alloc_arraycache(node, limit, 0xbaadf00d, gfp);
|
|
if (!ac_ptr[i]) {
|
|
for (i--; i >= 0; i--)
|
|
diff --git a/net/core/scm.c b/net/core/scm.c
|
|
index b7ba91b..9b26463 100644
|
|
--- a/net/core/scm.c
|
|
+++ b/net/core/scm.c
|
|
@@ -156,6 +156,8 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
|
|
switch (cmsg->cmsg_type)
|
|
{
|
|
case SCM_RIGHTS:
|
|
+ if (!sock->ops || sock->ops->family != PF_UNIX)
|
|
+ goto error;
|
|
err=scm_fp_copy(cmsg, &p->fp);
|
|
if (err<0)
|
|
goto error;
|
|
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
|
|
index 5e3a7ec..304b0b6 100644
|
|
--- a/net/mac80211/agg-tx.c
|
|
+++ b/net/mac80211/agg-tx.c
|
|
@@ -179,7 +179,8 @@ static void sta_addba_resp_timer_expired(unsigned long data)
|
|
|
|
/* check if the TID waits for addBA response */
|
|
spin_lock_bh(&sta->lock);
|
|
- if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK)) !=
|
|
+ if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK |
|
|
+ HT_AGG_STATE_REQ_STOP_BA_MSK)) !=
|
|
HT_ADDBA_REQUESTED_MSK) {
|
|
spin_unlock_bh(&sta->lock);
|
|
*state = HT_AGG_STATE_IDLE;
|
|
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
|
|
index 82a30c1..da92cde 100644
|
|
--- a/net/mac80211/rx.c
|
|
+++ b/net/mac80211/rx.c
|
|
@@ -1788,6 +1788,7 @@ static ieee80211_rx_result debug_noinline
|
|
ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
|
|
{
|
|
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
|
+ struct ieee80211_local *local = rx->local;
|
|
struct net_device *dev = sdata->dev;
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
|
|
__le16 fc = hdr->frame_control;
|
|
@@ -1819,6 +1820,13 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
|
|
dev->stats.rx_packets++;
|
|
dev->stats.rx_bytes += rx->skb->len;
|
|
|
|
+ if (ieee80211_is_data(hdr->frame_control) &&
|
|
+ !is_multicast_ether_addr(hdr->addr1) &&
|
|
+ local->hw.conf.dynamic_ps_timeout > 0 && local->ps_sdata) {
|
|
+ mod_timer(&local->dynamic_ps_timer, jiffies +
|
|
+ msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
|
|
+ }
|
|
+
|
|
ieee80211_deliver_skb(rx);
|
|
|
|
return RX_QUEUED;
|
|
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
|
|
index ac210b5..70c79c3 100644
|
|
--- a/net/mac80211/tx.c
|
|
+++ b/net/mac80211/tx.c
|
|
@@ -1052,8 +1052,11 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
|
|
|
|
hdr = (struct ieee80211_hdr *) skb->data;
|
|
|
|
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
|
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
|
|
tx->sta = rcu_dereference(sdata->u.vlan.sta);
|
|
+ if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr)
|
|
+ return TX_DROP;
|
|
+ }
|
|
if (!tx->sta)
|
|
tx->sta = sta_info_get(local, hdr->addr1);
|
|
|
|
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
|
|
index fc70a49..43e83a4 100644
|
|
--- a/net/netfilter/xt_recent.c
|
|
+++ b/net/netfilter/xt_recent.c
|
|
@@ -173,10 +173,10 @@ recent_entry_init(struct recent_table *t, const union nf_inet_addr *addr,
|
|
|
|
static void recent_entry_update(struct recent_table *t, struct recent_entry *e)
|
|
{
|
|
+ e->index %= ip_pkt_list_tot;
|
|
e->stamps[e->index++] = jiffies;
|
|
if (e->index > e->nstamps)
|
|
e->nstamps = e->index;
|
|
- e->index %= ip_pkt_list_tot;
|
|
list_move_tail(&e->lru_list, &t->lru_list);
|
|
}
|
|
|
|
@@ -260,7 +260,7 @@ recent_mt(const struct sk_buff *skb, const struct xt_match_param *par)
|
|
for (i = 0; i < e->nstamps; i++) {
|
|
if (info->seconds && time_after(time, e->stamps[i]))
|
|
continue;
|
|
- if (++hits >= info->hit_count) {
|
|
+ if (info->hit_count && ++hits >= info->hit_count) {
|
|
ret = !ret;
|
|
break;
|
|
}
|
|
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
|
|
index 7d1f9e9..4f30336 100644
|
|
--- a/net/sunrpc/svc_xprt.c
|
|
+++ b/net/sunrpc/svc_xprt.c
|
|
@@ -889,11 +889,8 @@ void svc_delete_xprt(struct svc_xprt *xprt)
|
|
if (test_bit(XPT_TEMP, &xprt->xpt_flags))
|
|
serv->sv_tmpcnt--;
|
|
|
|
- for (dr = svc_deferred_dequeue(xprt); dr;
|
|
- dr = svc_deferred_dequeue(xprt)) {
|
|
- svc_xprt_put(xprt);
|
|
+ while ((dr = svc_deferred_dequeue(xprt)) != NULL)
|
|
kfree(dr);
|
|
- }
|
|
|
|
svc_xprt_put(xprt);
|
|
spin_unlock_bh(&serv->sv_lock);
|
|
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
|
|
index 3d739e5..4df801d 100644
|
|
--- a/net/sunrpc/xprtsock.c
|
|
+++ b/net/sunrpc/xprtsock.c
|
|
@@ -1912,6 +1912,11 @@ static void xs_tcp_setup_socket(struct rpc_xprt *xprt,
|
|
case -EALREADY:
|
|
xprt_clear_connecting(xprt);
|
|
return;
|
|
+ case -EINVAL:
|
|
+ /* Happens, for instance, if the user specified a link
|
|
+ * local IPv6 address without a scope-id.
|
|
+ */
|
|
+ goto out;
|
|
}
|
|
out_eagain:
|
|
status = -EAGAIN;
|
|
diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
|
|
index 2f3230d..049c419 100755
|
|
--- a/scripts/get_maintainer.pl
|
|
+++ b/scripts/get_maintainer.pl
|
|
@@ -314,6 +314,7 @@ foreach my $file (@files) {
|
|
if ($type eq 'X') {
|
|
if (file_match_pattern($file, $value)) {
|
|
$exclude = 1;
|
|
+ last;
|
|
}
|
|
}
|
|
}
|
|
@@ -340,8 +341,7 @@ foreach my $file (@files) {
|
|
}
|
|
}
|
|
|
|
- $tvi += ($end - $start);
|
|
-
|
|
+ $tvi = $end + 1;
|
|
}
|
|
|
|
foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
|
|
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c
|
|
index 0d83edc..2d4d05d 100644
|
|
--- a/security/integrity/ima/ima_iint.c
|
|
+++ b/security/integrity/ima/ima_iint.c
|
|
@@ -63,12 +63,11 @@ int ima_inode_alloc(struct inode *inode)
|
|
spin_lock(&ima_iint_lock);
|
|
rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint);
|
|
spin_unlock(&ima_iint_lock);
|
|
+ radix_tree_preload_end();
|
|
out:
|
|
if (rc < 0)
|
|
kmem_cache_free(iint_cache, iint);
|
|
|
|
- radix_tree_preload_end();
|
|
-
|
|
return rc;
|
|
}
|
|
|
|
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
|
|
index 68c7348..04b6145 100644
|
|
--- a/security/selinux/ss/ebitmap.c
|
|
+++ b/security/selinux/ss/ebitmap.c
|
|
@@ -128,7 +128,7 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
|
|
cmap_idx = delta / NETLBL_CATMAP_MAPSIZE;
|
|
cmap_sft = delta % NETLBL_CATMAP_MAPSIZE;
|
|
c_iter->bitmap[cmap_idx]
|
|
- |= e_iter->maps[cmap_idx] << cmap_sft;
|
|
+ |= e_iter->maps[i] << cmap_sft;
|
|
}
|
|
e_iter = e_iter->next;
|
|
}
|
|
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
|
|
index 25b0641..f7e1c9f 100644
|
|
--- a/sound/core/pcm_native.c
|
|
+++ b/sound/core/pcm_native.c
|
|
@@ -315,10 +315,10 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
|
|
if (!params->info)
|
|
params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES;
|
|
if (!params->fifo_size) {
|
|
- if (snd_mask_min(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT]) ==
|
|
- snd_mask_max(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT]) &&
|
|
- snd_mask_min(¶ms->masks[SNDRV_PCM_HW_PARAM_CHANNELS]) ==
|
|
- snd_mask_max(¶ms->masks[SNDRV_PCM_HW_PARAM_CHANNELS])) {
|
|
+ m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
|
|
+ i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
|
|
+ if (snd_mask_min(m) == snd_mask_max(m) &&
|
|
+ snd_interval_min(i) == snd_interval_max(i)) {
|
|
changed = substream->ops->ioctl(substream,
|
|
SNDRV_PCM_IOCTL1_FIFO_SIZE, params);
|
|
if (changed < 0)
|
|
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
|
|
index ff6da6f..6d6e307 100644
|
|
--- a/sound/pci/hda/hda_intel.c
|
|
+++ b/sound/pci/hda/hda_intel.c
|
|
@@ -2261,9 +2261,12 @@ static int azx_dev_free(struct snd_device *device)
|
|
static struct snd_pci_quirk position_fix_list[] __devinitdata = {
|
|
SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
|
|
SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
|
|
+ SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB),
|
|
SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
|
|
+ SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
|
|
SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
|
|
SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
|
|
+ SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB),
|
|
{}
|
|
};
|
|
|
|
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
|
|
index 69a941c..7069441 100644
|
|
--- a/sound/pci/hda/patch_analog.c
|
|
+++ b/sound/pci/hda/patch_analog.c
|
|
@@ -1008,7 +1008,7 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
|
|
SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
|
|
SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
|
|
SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
|
|
- SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
|
|
+ SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK),
|
|
SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
|
|
SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
|
|
SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
|
|
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
|
|
index 8a332d2..03d6aea 100644
|
|
--- a/sound/pci/via82xx.c
|
|
+++ b/sound/pci/via82xx.c
|
|
@@ -1791,6 +1791,12 @@ static struct ac97_quirk ac97_quirks[] = {
|
|
.type = AC97_TUNE_HP_ONLY
|
|
},
|
|
{
|
|
+ .subvendor = 0x110a,
|
|
+ .subdevice = 0x0079,
|
|
+ .name = "Fujitsu Siemens D1289",
|
|
+ .type = AC97_TUNE_HP_ONLY
|
|
+ },
|
|
+ {
|
|
.subvendor = 0x1019,
|
|
.subdevice = 0x0a81,
|
|
.name = "ECS K7VTA3",
|
|
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
|
|
index 3a14c6f..0f439ab 100644
|
|
--- a/sound/soc/codecs/ak4104.c
|
|
+++ b/sound/soc/codecs/ak4104.c
|
|
@@ -90,12 +90,10 @@ static int ak4104_spi_write(struct snd_soc_codec *codec, unsigned int reg,
|
|
if (reg >= codec->reg_cache_size)
|
|
return -EINVAL;
|
|
|
|
- reg &= AK4104_REG_MASK;
|
|
- reg |= AK4104_WRITE;
|
|
-
|
|
/* only write to the hardware if value has changed */
|
|
if (cache[reg] != value) {
|
|
- u8 tmp[2] = { reg, value };
|
|
+ u8 tmp[2] = { (reg & AK4104_REG_MASK) | AK4104_WRITE, value };
|
|
+
|
|
if (spi_write(spi, tmp, sizeof(tmp))) {
|
|
dev_err(&spi->dev, "SPI write failed\n");
|
|
return -EIO;
|
|
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
|
|
index 9edef46..3c81add 100644
|
|
--- a/sound/usb/usbaudio.c
|
|
+++ b/sound/usb/usbaudio.c
|
|
@@ -3327,6 +3327,32 @@ static int snd_usb_cm6206_boot_quirk(struct usb_device *dev)
|
|
}
|
|
|
|
/*
|
|
+ * This call will put the synth in "USB send" mode, i.e it will send MIDI
|
|
+ * messages through USB (this is disabled at startup). The synth will
|
|
+ * acknowledge by sending a sysex on endpoint 0x85 and by displaying a USB
|
|
+ * sign on its LCD. Values here are chosen based on sniffing USB traffic
|
|
+ * under Windows.
|
|
+ */
|
|
+static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev)
|
|
+{
|
|
+ int err, actual_length;
|
|
+
|
|
+ /* "midi send" enable */
|
|
+ static const u8 seq[] = { 0x4e, 0x73, 0x52, 0x01 };
|
|
+
|
|
+ void *buf = kmemdup(seq, ARRAY_SIZE(seq), GFP_KERNEL);
|
|
+ if (!buf)
|
|
+ return -ENOMEM;
|
|
+ err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x05), buf,
|
|
+ ARRAY_SIZE(seq), &actual_length, 1000);
|
|
+ kfree(buf);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
* Setup quirks
|
|
*/
|
|
#define AUDIOPHILE_SET 0x01 /* if set, parse device_setup */
|
|
@@ -3624,6 +3650,12 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
|
|
goto __err_val;
|
|
}
|
|
|
|
+ /* Access Music VirusTI Desktop */
|
|
+ if (id == USB_ID(0x133e, 0x0815)) {
|
|
+ if (snd_usb_accessmusic_boot_quirk(dev) < 0)
|
|
+ goto __err_val;
|
|
+ }
|
|
+
|
|
/*
|
|
* found a config. now register to ALSA
|
|
*/
|
|
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
|
|
index 6e89b83..b2da478 100644
|
|
--- a/sound/usb/usbmidi.c
|
|
+++ b/sound/usb/usbmidi.c
|
|
@@ -1162,10 +1162,22 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi,
|
|
pipe = usb_sndintpipe(umidi->dev, ep_info->out_ep);
|
|
else
|
|
pipe = usb_sndbulkpipe(umidi->dev, ep_info->out_ep);
|
|
- if (umidi->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */
|
|
- ep->max_transfer = 4;
|
|
- else
|
|
+ switch (umidi->usb_id) {
|
|
+ default:
|
|
ep->max_transfer = usb_maxpacket(umidi->dev, pipe, 1);
|
|
+ break;
|
|
+ /*
|
|
+ * Various chips declare a packet size larger than 4 bytes, but
|
|
+ * do not actually work with larger packets:
|
|
+ */
|
|
+ case USB_ID(0x0a92, 0x1020): /* ESI M4U */
|
|
+ case USB_ID(0x1430, 0x474b): /* RedOctane GH MIDI INTERFACE */
|
|
+ case USB_ID(0x15ca, 0x0101): /* Textech USB Midi Cable */
|
|
+ case USB_ID(0x15ca, 0x1806): /* Textech USB Midi Cable */
|
|
+ case USB_ID(0x1a86, 0x752d): /* QinHeng CH345 "USB2.0-MIDI" */
|
|
+ ep->max_transfer = 4;
|
|
+ break;
|
|
+ }
|
|
for (i = 0; i < OUTPUT_URBS; ++i) {
|
|
buffer = usb_buffer_alloc(umidi->dev,
|
|
ep->max_transfer, GFP_KERNEL,
|
|
@@ -1407,6 +1419,12 @@ static struct port_info {
|
|
EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"),
|
|
EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"),
|
|
EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"),
|
|
+ /* Access Music Virus TI */
|
|
+ EXTERNAL_PORT(0x133e, 0x0815, 0, "%s MIDI"),
|
|
+ PORT_INFO(0x133e, 0x0815, 1, "%s Synth", 0,
|
|
+ SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
|
|
+ SNDRV_SEQ_PORT_TYPE_HARDWARE |
|
|
+ SNDRV_SEQ_PORT_TYPE_SYNTHESIZER),
|
|
};
|
|
|
|
static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number)
|
|
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
|
|
index a892bda..406b74b 100644
|
|
--- a/sound/usb/usbquirks.h
|
|
+++ b/sound/usb/usbquirks.h
|
|
@@ -2073,6 +2073,33 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
|
}
|
|
},
|
|
|
|
+/* Access Music devices */
|
|
+{
|
|
+ /* VirusTI Desktop */
|
|
+ USB_DEVICE_VENDOR_SPEC(0x133e, 0x0815),
|
|
+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
|
|
+ .ifnum = QUIRK_ANY_INTERFACE,
|
|
+ .type = QUIRK_COMPOSITE,
|
|
+ .data = &(const struct snd_usb_audio_quirk[]) {
|
|
+ {
|
|
+ .ifnum = 3,
|
|
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
|
|
+ .data = &(const struct snd_usb_midi_endpoint_info) {
|
|
+ .out_cables = 0x0003,
|
|
+ .in_cables = 0x0003
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ .ifnum = 4,
|
|
+ .type = QUIRK_IGNORE_INTERFACE
|
|
+ },
|
|
+ {
|
|
+ .ifnum = -1
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+},
|
|
+
|
|
/* */
|
|
{
|
|
/* aka. Serato Scratch Live DJ Box */
|
|
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
|
|
index ab92763..72547b9 100644
|
|
--- a/tools/perf/util/symbol.c
|
|
+++ b/tools/perf/util/symbol.c
|
|
@@ -503,7 +503,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
|
|
return -1;
|
|
|
|
curr_map = map__new2(pos->start, dso, map->type);
|
|
- if (map == NULL) {
|
|
+ if (curr_map == NULL) {
|
|
dso__delete(dso);
|
|
return -1;
|
|
}
|