* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (41 commits)
ACPICA: hw: Don't carry spinlock over suspend
ACPICA: hw: remove use_lock flag from acpi_hw_register_{read, write}
ACPI: cpuidle: port idle timer suspend/resume workaround to cpuidle
ACPI: clean up acpi_enter_sleep_state_prep
Hibernation: Make sure that ACPI is enabled in acpi_hibernation_finish
ACPI: suppress uninitialized var warning
cpuidle: consolidate 2.6.22 cpuidle branch into one patch
ACPI: thinkpad-acpi: skip blanks before the data when parsing sysfs
ACPI: AC: Add sysfs interface
ACPI: SBS: Add sysfs alarm
ACPI: SBS: Add ACPI_PROCFS around procfs handling code.
ACPI: SBS: Add support for power_supply class (and sysfs)
ACPI: SBS: Make SBS reads table-driven.
ACPI: SBS: Simplify data structures in SBS
ACPI: SBS: Split host controller (ACPI0001) from SBS driver (ACPI0002)
ACPI: EC: Add new query handler to list head.
ACPI: Add acpi_bus_generate_event4() function
ACPI: Battery: add sysfs alarm
ACPI: Battery: Add sysfs support
ACPI: Battery: Misc clean-ups, no functional changes
...
Fix up conflicts in drivers/misc/thinkpad_acpi.[ch] manually
config X86_VOYAGER
bool "Voyager (NCR)"
+ select SMP if !BROKEN
help
Voyager is an MCA-based 32-way capable SMP architecture proprietary
to NCR Corp. Machine classes 345x/35xx/4100/51xx are Voyager-based.
endchoice
+config SCHED_NO_NO_OMIT_FRAME_POINTER
+ bool "Single-depth WCHAN output"
+ default y
+ help
+ Calculate simpler /proc/<PID>/wchan values. If this option
+ is disabled then wchan values will recurse back to the
+ caller function. This provides more accurate wchan values,
+ at the expense of slightly more scheduling overhead.
+
+ If in doubt, say "Y".
+
config PARAVIRT
bool "Paravirtualization support (EXPERIMENTAL)"
depends on EXPERIMENTAL
However, when run without a hypervisor the kernel is
theoretically slower. If in doubt, say N.
-source "arch/i386/xen/Kconfig"
+source "arch/x86/xen/Kconfig"
config VMI
bool "VMI Paravirt-ops support"
intend to use this kernel on different machines.
More information about the internals of the Linux math coprocessor
- emulation can be found in <file:arch/i386/math-emu/README>.
+ emulation can be found in <file:arch/x86/math-emu/README>.
If you are not sure, say Y; apart from resulting in a 66 KB bigger
kernel, it won't hurt.
depends on HIGHMEM
help
Generate crash dump after being started by kexec.
- This should be normally only set in special crash dump kernels
+ This should be normally only set in special crash dump kernels
which are loaded in the main kernel with kexec-tools into
a specially reserved region and then later executed after
a crash by kdump/kexec. The crash dump kernel must be compiled
- to a memory address not used by the main kernel or BIOS using
- PHYSICAL_START.
+ to a memory address not used by the main kernel or BIOS using
+ PHYSICAL_START, or it must be built as a relocatable image
+ (CONFIG_RELOCATABLE=y).
For more details see Documentation/kdump/kdump.txt
config PHYSICAL_START
Don't change this unless you know what you are doing.
config RELOCATABLE
- bool "Build a relocatable kernel(EXPERIMENTAL)"
+ bool "Build a relocatable kernel (EXPERIMENTAL)"
depends on EXPERIMENTAL
help
This builds a kernel image that retains relocation information
- so it can be loaded someplace besides the default 1MB.
+ so it can be loaded someplace besides the default 1MB.
The relocations tend to make the kernel binary about 10% larger,
- but are discarded at runtime.
+ but are discarded at runtime.
One use is for the kexec on panic case where the recovery kernel
- must live at a different physical address than the primary
- kernel.
+ must live at a different physical address than the primary
+ kernel.
config PHYSICAL_ALIGN
hex "Alignment value to which kernel should be aligned"
endif # APM
-source "arch/i386/kernel/cpu/cpufreq/Kconfig"
+source "arch/x86/kernel/cpu/cpufreq/Kconfig"
+ source "drivers/cpuidle/Kconfig"
+
endmenu
menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
default y
+config PCI_DOMAINS
+ bool
+ depends on PCI
+ default y
+
source "drivers/pci/pcie/Kconfig"
source "drivers/pci/Kconfig"
processor goes idle (as is done by the scheduler). The
other workaround is idle=poll boot option.
+config GEODE_MFGPT_TIMER
+ bool "Geode Multi-Function General Purpose Timer (MFGPT) events"
+ depends on MGEODE_LX && GENERIC_TIME && GENERIC_CLOCKEVENTS
+ default y
+ help
+ This driver provides a clock event source based on the MFGPT
+ timer(s) in the CS5535 and CS5536 companion chip for the geode.
+ MFGPTs have a better resolution and max interval than the
+ generic PIT, and are suitable for use as high-res timers.
+
config K8_NB
def_bool y
depends on AGP_AMD64
source "fs/Kconfig"
-menuconfig INSTRUMENTATION
- bool "Instrumentation Support"
- depends on EXPERIMENTAL
- default y
- ---help---
- Say Y here to get to see options related to performance measurement,
- debugging, and testing. This option alone does not add any kernel code.
-
- If you say N, all options in this submenu will be skipped and disabled.
-
-if INSTRUMENTATION
-
-source "arch/i386/oprofile/Kconfig"
-
-config KPROBES
- bool "Kprobes"
- depends on KALLSYMS && MODULES
- help
- Kprobes allows you to trap at almost any kernel address and
- execute a callback function. register_kprobe() establishes
- a probepoint and specifies the callback. Kprobes is useful
- for kernel debugging, non-intrusive instrumentation and testing.
- If in doubt, say "N".
-
-endif # INSTRUMENTATION
-
source "arch/i386/Kconfig.debug"
source "security/Kconfig"
bool
default y
+config CLOCKSOURCE_WATCHDOG
+ bool
+ default y
+
+config GENERIC_CLOCKEVENTS
+ bool
+ default y
+
+config GENERIC_CLOCKEVENTS_BROADCAST
+ bool
+ default y
+
config ZONE_DMA32
bool
default y
menu "Processor type and features"
+source "kernel/time/Kconfig"
+
choice
prompt "Subarchitecture Type"
default X86_PC
config MPSC
bool "Intel P4 / older Netburst based Xeon"
help
- Optimize for Intel Pentium 4 and older Nocona/Dempsey Xeon CPUs
- with Intel Extended Memory 64 Technology(EM64T). For details see
- <http://www.intel.com/technology/64bitextensions/>.
+ Optimize for Intel Pentium 4, Pentium D and older Nocona/Dempsey
+ Xeon CPUs with Intel 64bit which is compatible with x86-64.
Note that the latest Xeons (Xeon 51xx and 53xx) are not based on the
Netburst core and shouldn't use this option. You can distinguish them
using the cpu family field
- in /proc/cpuinfo. Family 15 is an older Xeon, Family 6 a newer one
- (this rule only applies to systems that support EM64T)
+ in /proc/cpuinfo. Family 15 is an older Xeon, Family 6 a newer one.
config MCORE2
bool "Intel Core2 / newer Xeon"
Optimize for Intel Core2 and newer Xeons (51xx)
You can distinguish the newer Xeons from the older ones using
the cpu family field in /proc/cpuinfo. 15 is an older Xeon
- (use CONFIG_MPSC then), 6 is a newer one. This rule only
- applies to CPUs that support EM64T.
+ (use CONFIG_MPSC then), 6 is a newer one.
config GENERIC_CPU
bool "Generic-x86-64"
config ARCH_SPARSEMEM_ENABLE
def_bool y
depends on (NUMA || EXPERIMENTAL)
+ select SPARSEMEM_VMEMMAP_ENABLE
config ARCH_MEMORY_PROBE
def_bool y
<http://www.intel.com/hardwaredesign/hpetspec.htm>.
config HPET_EMULATE_RTC
- bool "Provide RTC interrupt"
+ bool
depends on HPET_TIMER && RTC=y
+ default y
# Mark as embedded because too many people got it wrong.
# The code disables itself when not needed.
bool "kernel crash dumps (EXPERIMENTAL)"
depends on EXPERIMENTAL
help
- Generate crash dump after being started by kexec.
- This should be normally only set in special crash dump kernels
- which are loaded in the main kernel with kexec-tools into
- a specially reserved region and then later executed after
- a crash by kdump/kexec. The crash dump kernel must be compiled
+ Generate crash dump after being started by kexec.
+ This should be normally only set in special crash dump kernels
+ which are loaded in the main kernel with kexec-tools into
+ a specially reserved region and then later executed after
+ a crash by kdump/kexec. The crash dump kernel must be compiled
to a memory address not used by the main kernel or BIOS using
- PHYSICAL_START.
- For more details see Documentation/kdump/kdump.txt
+ PHYSICAL_START, or it must be built as a relocatable image
+ (CONFIG_RELOCATABLE=y).
+ For more details see Documentation/kdump/kdump.txt
config RELOCATABLE
- bool "Build a relocatable kernel(EXPERIMENTAL)"
+ bool "Build a relocatable kernel (EXPERIMENTAL)"
depends on EXPERIMENTAL
help
Builds a relocatable kernel. This enables loading and running
must live at a different physical address than the primary
kernel.
- Note: If CONFIG_RELOCATABLE=y, then kernel run from the address
- it has been loaded at and compile time physical address
+ Note: If CONFIG_RELOCATABLE=y, then the kernel runs from the address
+ it has been loaded at and the compile time physical address
(CONFIG_PHYSICAL_START) is ignored.
config PHYSICAL_START
source kernel/power/Kconfig
+config ARCH_HIBERNATION_HEADER
+ bool
+ depends on HIBERNATION
+ default y
+
source "drivers/acpi/Kconfig"
-source "arch/x86_64/kernel/cpufreq/Kconfig"
+source "arch/x86/kernel/cpufreq/Kconfig"
+ source "drivers/cpuidle/Kconfig"
+
endmenu
menu "Bus options (PCI etc.)"
bool "Support mmconfig PCI config space access"
depends on PCI && ACPI
+config PCI_DOMAINS
+ bool
+ depends on PCI
+ default y
+
source "drivers/pci/pcie/Kconfig"
source "drivers/pci/Kconfig"
source fs/Kconfig
-menu "Instrumentation Support"
- depends on EXPERIMENTAL
-
-source "arch/x86_64/oprofile/Kconfig"
-
-config KPROBES
- bool "Kprobes"
- depends on KALLSYMS && MODULES
- help
- Kprobes allows you to trap at almost any kernel address and
- execute a callback function. register_kprobe() establishes
- a probepoint and specifies the callback. Kprobes is useful
- for kernel debugging, non-intrusive instrumentation and testing.
- If in doubt, say "N".
-endmenu
-
source "arch/x86_64/Kconfig.debug"
source "security/Kconfig"
obj-$(CONFIG_W1) += w1/
obj-$(CONFIG_POWER_SUPPLY) += power/
obj-$(CONFIG_HWMON) += hwmon/
-obj-$(CONFIG_WATCHDOG) += char/watchdog/
+obj-$(CONFIG_WATCHDOG) += watchdog/
obj-$(CONFIG_PHONE) += telephony/
obj-$(CONFIG_MD) += md/
obj-$(CONFIG_BT) += bluetooth/
obj-$(CONFIG_EISA) += eisa/
obj-$(CONFIG_LGUEST_GUEST) += lguest/
obj-$(CONFIG_CPU_FREQ) += cpufreq/
+ obj-$(CONFIG_CPU_IDLE) += cpuidle/
obj-$(CONFIG_MMC) += mmc/
obj-$(CONFIG_NEW_LEDS) += leds/
obj-$(CONFIG_INFINIBAND) += infiniband/
obj-$(CONFIG_SUPERH) += sh/
obj-$(CONFIG_GENERIC_TIME) += clocksource/
obj-$(CONFIG_DMA_ENGINE) += dma/
+obj-$(CONFIG_DCA) += dca/
obj-$(CONFIG_HID) += hid/
obj-$(CONFIG_PPC_PS3) += ps3/
obj-$(CONFIG_OF) += of/
+obj-$(CONFIG_SSB) += ssb/
if (!device->flags.power_manageable) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
- device->dev.kobj.name));
+ kobject_name(&device->dev.kobj)));
return -ENODEV;
}
/*
printk(KERN_WARNING PREFIX
"Transitioning device [%s] to D%d\n",
device->pnp.bus_id, state);
- else
+ else {
+ device->power.state = state;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device [%s] transitioned to D%d\n",
device->pnp.bus_id, state));
+ }
return result;
}
extern int event_is_open;
- int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
+ int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id, u8 type, int data)
{
- struct acpi_bus_event *event = NULL;
+ struct acpi_bus_event *event;
unsigned long flags = 0;
-
- if (!device)
- return -EINVAL;
-
/* drop event on the floor if no one's listening */
if (!event_is_open)
return 0;
if (!event)
return -ENOMEM;
- strcpy(event->device_class, device->pnp.device_class);
- strcpy(event->bus_id, device->pnp.bus_id);
+ strcpy(event->device_class, device_class);
+ strcpy(event->bus_id, bus_id);
event->type = type;
event->data = data;
wake_up_interruptible(&acpi_bus_event_queue);
return 0;
+
+ }
+
+ EXPORT_SYMBOL_GPL(acpi_bus_generate_proc_event4);
+
+ int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
+ {
+ if (!device)
+ return -EINVAL;
+ return acpi_bus_generate_proc_event4(device->pnp.device_class,
+ device->pnp.bus_id, type, data);
}
EXPORT_SYMBOL(acpi_bus_generate_proc_event);
__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup);
- /*
- * max_cstate is defined in the base kernel so modules can
- * change it w/o depending on the state of the processor module.
- */
- unsigned int max_cstate = ACPI_PROCESSOR_MAX_POWER;
-
- EXPORT_SYMBOL(max_cstate);
-
/*
* Acquire a spinlock.
*
}
#ifdef CONFIG_DMI
-static int dmi_osi_linux(struct dmi_system_id *d)
+static int dmi_osi_linux(const struct dmi_system_id *d)
{
printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident);
enable_osi_linux(1);
#include <linux/sched.h> /* need_resched() */
#include <linux/latency.h>
#include <linux/clockchips.h>
+ #include <linux/cpuidle.h>
/*
* Include the apic definitions for x86 to have the APIC timer related defines
#define ACPI_PROCESSOR_FILE_POWER "power"
#define US_TO_PM_TIMER_TICKS(t) ((t * (PM_TIMER_FREQUENCY/1000)) / 1000)
#define PM_TIMER_TICK_NS (1000000000ULL/PM_TIMER_FREQUENCY)
+ #ifndef CONFIG_CPU_IDLE
#define C2_OVERHEAD 4 /* 1us (3.579 ticks per us) */
#define C3_OVERHEAD 4 /* 1us (3.579 ticks per us) */
static void (*pm_idle_save) (void) __read_mostly;
- module_param(max_cstate, uint, 0644);
+ #else
+ #define C2_OVERHEAD 1 /* 1us */
+ #define C3_OVERHEAD 1 /* 1us */
+ #endif
+ #define PM_TIMER_TICKS_TO_US(p) (((p) * 1000)/(PM_TIMER_FREQUENCY/1000))
+ static unsigned int max_cstate __read_mostly = ACPI_PROCESSOR_MAX_POWER;
+ module_param(max_cstate, uint, 0000);
static unsigned int nocst __read_mostly;
module_param(nocst, uint, 0000);
+ #ifndef CONFIG_CPU_IDLE
/*
* bm_history -- bit-mask with a bit per jiffy of bus-master activity
* 1000 HZ: 0xFFFFFFFF: 32 jiffies = 32ms
static unsigned int bm_history __read_mostly =
(HZ >= 800 ? 0xFFFFFFFF : ((1U << (HZ / 25)) - 1));
module_param(bm_history, uint, 0644);
- /* --------------------------------------------------------------------------
- Power Management
- -------------------------------------------------------------------------- */
+
+ static int acpi_processor_set_power_policy(struct acpi_processor *pr);
+
+ #endif
/*
* IBM ThinkPad R40e crashes mysteriously when going into C2 or C3.
*
* To skip this limit, boot/load with a large max_cstate limit.
*/
-static int set_max_cstate(struct dmi_system_id *id)
+static int set_max_cstate(const struct dmi_system_id *id)
{
if (max_cstate > ACPI_PROCESSOR_MAX_POWER)
return 0;
return ((0xFFFFFFFF - t1) + t2);
}
+ static inline u32 ticks_elapsed_in_us(u32 t1, u32 t2)
+ {
+ if (t2 >= t1)
+ return PM_TIMER_TICKS_TO_US(t2 - t1);
+ else if (!(acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER))
+ return PM_TIMER_TICKS_TO_US(((0x00FFFFFF - t1) + t2) & 0x00FFFFFF);
+ else
+ return PM_TIMER_TICKS_TO_US((0xFFFFFFFF - t1) + t2);
+ }
+
+ #ifndef CONFIG_CPU_IDLE
+
static void
acpi_processor_power_activate(struct acpi_processor *pr,
struct acpi_processor_cx *new)
unused = inl(acpi_gbl_FADT.xpm_timer_block.address);
}
}
+ #endif /* !CONFIG_CPU_IDLE */
#ifdef ARCH_APICTIMER_STOPS_ON_C3
static void acpi_propagate_timer_broadcast(struct acpi_processor *pr)
{
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
unsigned long reason;
reason = pr->power.timer_broadcast_on_state < INT_MAX ?
CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
clockevents_notify(reason, &pr->id);
-#else
- cpumask_t mask = cpumask_of_cpu(pr->id);
-
- if (pr->power.timer_broadcast_on_state < INT_MAX)
- on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1);
- else
- on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1);
-#endif
}
/* Power(C) State timer broadcast control */
struct acpi_processor_cx *cx,
int broadcast)
{
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
-
int state = cx - pr->power.states;
if (state >= pr->power.timer_broadcast_on_state) {
CLOCK_EVT_NOTIFY_BROADCAST_EXIT;
clockevents_notify(reason, &pr->id);
}
-#endif
}
#else
return 0;
}
+ #ifndef CONFIG_CPU_IDLE
static void acpi_processor_idle(void)
{
struct acpi_processor *pr = NULL;
* an SMP system. We do it here instead of doing it at _CST/P_LVL
* detection phase, to work cleanly with logical CPU hotplug.
*/
- if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
+ if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
!pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
cx = &pr->power.states[ACPI_STATE_C1];
#endif
return 0;
}
+ #endif /* !CONFIG_CPU_IDLE */
static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
{
#ifndef CONFIG_HOTPLUG_CPU
/*
* Check for P_LVL2_UP flag before entering C2 and above on
- * an SMP system.
+ * an SMP system.
*/
if ((num_online_cpus() > 1) &&
!(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
* Normalize the C2 latency to expidite policy
*/
cx->valid = 1;
+
+ #ifndef CONFIG_CPU_IDLE
cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency);
+ #else
+ cx->latency_ticks = cx->latency;
+ #endif
return;
}
* use this in our C3 policy
*/
cx->valid = 1;
+
+ #ifndef CONFIG_CPU_IDLE
cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency);
+ #else
+ cx->latency_ticks = cx->latency;
+ #endif
return;
}
pr->power.count = acpi_processor_power_verify(pr);
+ #ifndef CONFIG_CPU_IDLE
/*
* Set Default Policy
* ------------------
result = acpi_processor_set_power_policy(pr);
if (result)
return result;
+ #endif
/*
* if one state of type C2 or C3 is available, mark this
return 0;
}
- int acpi_processor_cst_has_changed(struct acpi_processor *pr)
- {
- int result = 0;
-
-
- if (!pr)
- return -EINVAL;
-
- if (nocst) {
- return -ENODEV;
- }
-
- if (!pr->flags.power_setup_done)
- return -ENODEV;
-
- /* Fall back to the default idle loop */
- pm_idle = pm_idle_save;
- synchronize_sched(); /* Relies on interrupts forcing exit from idle. */
-
- pr->flags.power = 0;
- result = acpi_processor_get_power_info(pr);
- if ((pr->flags.power == 1) && (pr->flags.power_setup_done))
- pm_idle = acpi_processor_idle;
-
- return result;
- }
-
- /* proc interface */
-
static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_processor *pr = seq->private;
.release = single_release,
};
+ #ifndef CONFIG_CPU_IDLE
+
+ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
+ {
+ int result = 0;
+
+
+ if (!pr)
+ return -EINVAL;
+
+ if (nocst) {
+ return -ENODEV;
+ }
+
+ if (!pr->flags.power_setup_done)
+ return -ENODEV;
+
+ /* Fall back to the default idle loop */
+ pm_idle = pm_idle_save;
+ synchronize_sched(); /* Relies on interrupts forcing exit from idle. */
+
+ pr->flags.power = 0;
+ result = acpi_processor_get_power_info(pr);
+ if ((pr->flags.power == 1) && (pr->flags.power_setup_done))
+ pm_idle = acpi_processor_idle;
+
+ return result;
+ }
+
#ifdef CONFIG_SMP
static void smp_callback(void *v)
{
static struct notifier_block acpi_processor_latency_notifier = {
.notifier_call = acpi_processor_latency_notify,
};
+
+ #endif
+
+ #else /* CONFIG_CPU_IDLE */
+
+ /**
+ * acpi_idle_bm_check - checks if bus master activity was detected
+ */
+ static int acpi_idle_bm_check(void)
+ {
+ u32 bm_status = 0;
+
+ acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status);
+ if (bm_status)
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, 1);
+ /*
+ * PIIX4 Erratum #18: Note that BM_STS doesn't always reflect
+ * the true state of bus mastering activity; forcing us to
+ * manually check the BMIDEA bit of each IDE channel.
+ */
+ else if (errata.piix4.bmisx) {
+ if ((inb_p(errata.piix4.bmisx + 0x02) & 0x01)
+ || (inb_p(errata.piix4.bmisx + 0x0A) & 0x01))
+ bm_status = 1;
+ }
+ return bm_status;
+ }
+
+ /**
+ * acpi_idle_update_bm_rld - updates the BM_RLD bit depending on target state
+ * @pr: the processor
+ * @target: the new target state
+ */
+ static inline void acpi_idle_update_bm_rld(struct acpi_processor *pr,
+ struct acpi_processor_cx *target)
+ {
+ if (pr->flags.bm_rld_set && target->type != ACPI_STATE_C3) {
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
+ pr->flags.bm_rld_set = 0;
+ }
+
+ if (!pr->flags.bm_rld_set && target->type == ACPI_STATE_C3) {
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1);
+ pr->flags.bm_rld_set = 1;
+ }
+ }
+
+ /**
+ * acpi_idle_do_entry - a helper function that does C2 and C3 type entry
+ * @cx: cstate data
+ */
+ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
+ {
+ if (cx->space_id == ACPI_CSTATE_FFH) {
+ /* Call into architectural FFH based C-state */
+ acpi_processor_ffh_cstate_enter(cx);
+ } else {
+ int unused;
+ /* IO port based C-state */
+ inb(cx->address);
+ /* Dummy wait op - must do something useless after P_LVL2 read
+ because chipsets cannot guarantee that STPCLK# signal
+ gets asserted in time to freeze execution properly. */
+ unused = inl(acpi_gbl_FADT.xpm_timer_block.address);
+ }
+ }
+
+ /**
+ * acpi_idle_enter_c1 - enters an ACPI C1 state-type
+ * @dev: the target CPU
+ * @state: the state data
+ *
+ * This is equivalent to the HALT instruction.
+ */
+ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
+ struct cpuidle_state *state)
+ {
+ struct acpi_processor *pr;
+ struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+ pr = processors[smp_processor_id()];
+
+ if (unlikely(!pr))
+ return 0;
+
+ if (pr->flags.bm_check)
+ acpi_idle_update_bm_rld(pr, cx);
+
+ current_thread_info()->status &= ~TS_POLLING;
+ /*
+ * TS_POLLING-cleared state must be visible before we test
+ * NEED_RESCHED:
+ */
+ smp_mb();
+ if (!need_resched())
+ safe_halt();
+ current_thread_info()->status |= TS_POLLING;
+
+ cx->usage++;
+
+ return 0;
+ }
+
+ /**
+ * acpi_idle_enter_simple - enters an ACPI state without BM handling
+ * @dev: the target CPU
+ * @state: the state data
+ */
+ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
+ struct cpuidle_state *state)
+ {
+ struct acpi_processor *pr;
+ struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+ u32 t1, t2;
+ pr = processors[smp_processor_id()];
+
+ if (unlikely(!pr))
+ return 0;
+
+ if (acpi_idle_suspend)
+ return(acpi_idle_enter_c1(dev, state));
+
+ if (pr->flags.bm_check)
+ acpi_idle_update_bm_rld(pr, cx);
+
+ local_irq_disable();
+ current_thread_info()->status &= ~TS_POLLING;
+ /*
+ * TS_POLLING-cleared state must be visible before we test
+ * NEED_RESCHED:
+ */
+ smp_mb();
+
+ if (unlikely(need_resched())) {
+ current_thread_info()->status |= TS_POLLING;
+ local_irq_enable();
+ return 0;
+ }
+
+ if (cx->type == ACPI_STATE_C3)
+ ACPI_FLUSH_CPU_CACHE();
+
+ t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+ acpi_state_timer_broadcast(pr, cx, 1);
+ acpi_idle_do_entry(cx);
+ t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+
+ #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
+ /* TSC could halt in idle, so notify users */
+ mark_tsc_unstable("TSC halts in idle");;
+ #endif
+
+ local_irq_enable();
+ current_thread_info()->status |= TS_POLLING;
+
+ cx->usage++;
+
+ acpi_state_timer_broadcast(pr, cx, 0);
+ cx->time += ticks_elapsed(t1, t2);
+ return ticks_elapsed_in_us(t1, t2);
+ }
+
+ static int c3_cpu_count;
+ static DEFINE_SPINLOCK(c3_lock);
+
+ /**
+ * acpi_idle_enter_bm - enters C3 with proper BM handling
+ * @dev: the target CPU
+ * @state: the state data
+ *
+ * If BM is detected, the deepest non-C3 idle state is entered instead.
+ */
+ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
+ struct cpuidle_state *state)
+ {
+ struct acpi_processor *pr;
+ struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+ u32 t1, t2;
+ pr = processors[smp_processor_id()];
+
+ if (unlikely(!pr))
+ return 0;
+
+ if (acpi_idle_suspend)
+ return(acpi_idle_enter_c1(dev, state));
+
+ local_irq_disable();
+ current_thread_info()->status &= ~TS_POLLING;
+ /*
+ * TS_POLLING-cleared state must be visible before we test
+ * NEED_RESCHED:
+ */
+ smp_mb();
+
+ if (unlikely(need_resched())) {
+ current_thread_info()->status |= TS_POLLING;
+ local_irq_enable();
+ return 0;
+ }
+
+ /*
+ * Must be done before busmaster disable as we might need to
+ * access HPET !
+ */
+ acpi_state_timer_broadcast(pr, cx, 1);
+
+ if (acpi_idle_bm_check()) {
+ cx = pr->power.bm_state;
+
+ acpi_idle_update_bm_rld(pr, cx);
+
+ t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+ acpi_idle_do_entry(cx);
+ t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+ } else {
+ acpi_idle_update_bm_rld(pr, cx);
+
+ spin_lock(&c3_lock);
+ c3_cpu_count++;
+ /* Disable bus master arbitration when all CPUs are in C3 */
+ if (c3_cpu_count == num_online_cpus())
+ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
+ spin_unlock(&c3_lock);
+
+ t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+ acpi_idle_do_entry(cx);
+ t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+
+ spin_lock(&c3_lock);
+ /* Re-enable bus master arbitration */
+ if (c3_cpu_count == num_online_cpus())
+ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
+ c3_cpu_count--;
+ spin_unlock(&c3_lock);
+ }
+
+ #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
+ /* TSC could halt in idle, so notify users */
+ mark_tsc_unstable("TSC halts in idle");
+ #endif
+
+ local_irq_enable();
+ current_thread_info()->status |= TS_POLLING;
+
+ cx->usage++;
+
+ acpi_state_timer_broadcast(pr, cx, 0);
+ cx->time += ticks_elapsed(t1, t2);
+ return ticks_elapsed_in_us(t1, t2);
+ }
+
+ struct cpuidle_driver acpi_idle_driver = {
+ .name = "acpi_idle",
+ .owner = THIS_MODULE,
+ };
+
+ /**
+ * acpi_processor_setup_cpuidle - prepares and configures CPUIDLE
+ * @pr: the ACPI processor
+ */
+ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
+ {
+ int i, count = 0;
+ struct acpi_processor_cx *cx;
+ struct cpuidle_state *state;
+ struct cpuidle_device *dev = &pr->power.dev;
+
+ if (!pr->flags.power_setup_done)
+ return -EINVAL;
+
+ if (pr->flags.power == 0) {
+ return -EINVAL;
+ }
+
+ for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) {
+ cx = &pr->power.states[i];
+ state = &dev->states[count];
+
+ if (!cx->valid)
+ continue;
+
+ #ifdef CONFIG_HOTPLUG_CPU
+ if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
+ !pr->flags.has_cst &&
+ !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
+ continue;
#endif
+ cpuidle_set_statedata(state, cx);
+
+ snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
+ state->exit_latency = cx->latency;
+ state->target_residency = cx->latency * 6;
+ state->power_usage = cx->power;
+
+ state->flags = 0;
+ switch (cx->type) {
+ case ACPI_STATE_C1:
+ state->flags |= CPUIDLE_FLAG_SHALLOW;
+ state->enter = acpi_idle_enter_c1;
+ break;
+
+ case ACPI_STATE_C2:
+ state->flags |= CPUIDLE_FLAG_BALANCED;
+ state->flags |= CPUIDLE_FLAG_TIME_VALID;
+ state->enter = acpi_idle_enter_simple;
+ break;
+
+ case ACPI_STATE_C3:
+ state->flags |= CPUIDLE_FLAG_DEEP;
+ state->flags |= CPUIDLE_FLAG_TIME_VALID;
+ state->flags |= CPUIDLE_FLAG_CHECK_BM;
+ state->enter = pr->flags.bm_check ?
+ acpi_idle_enter_bm :
+ acpi_idle_enter_simple;
+ break;
+ }
+
+ count++;
+ }
+
+ dev->state_count = count;
+
+ if (!count)
+ return -EINVAL;
+
+ /* find the deepest state that can handle active BM */
+ if (pr->flags.bm_check) {
+ for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++)
+ if (pr->power.states[i].type == ACPI_STATE_C3)
+ break;
+ pr->power.bm_state = &pr->power.states[i-1];
+ }
+
+ return 0;
+ }
+
+ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
+ {
+ int ret;
+
+ if (!pr)
+ return -EINVAL;
+
+ if (nocst) {
+ return -ENODEV;
+ }
+
+ if (!pr->flags.power_setup_done)
+ return -ENODEV;
+
+ cpuidle_pause_and_lock();
+ cpuidle_disable_device(&pr->power.dev);
+ acpi_processor_get_power_info(pr);
+ acpi_processor_setup_cpuidle(pr);
+ ret = cpuidle_enable_device(&pr->power.dev);
+ cpuidle_resume_and_unlock();
+
+ return ret;
+ }
+
+ #endif /* CONFIG_CPU_IDLE */
int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
struct acpi_device *device)
"ACPI: processor limited to max C-state %d\n",
max_cstate);
first_run++;
- #ifdef CONFIG_SMP
+ #if !defined (CONFIG_CPU_IDLE) && defined (CONFIG_SMP)
register_latency_notifier(&acpi_processor_latency_notifier);
#endif
}
}
acpi_processor_get_power_info(pr);
+ pr->flags.power_setup_done = 1;
/*
* Install the idle handler if processor power management is supported.
* platforms that only support C1.
*/
if ((pr->flags.power) && (!boot_option_idle_override)) {
+ #ifdef CONFIG_CPU_IDLE
+ acpi_processor_setup_cpuidle(pr);
+ pr->power.dev.cpu = pr->id;
+ if (cpuidle_register_device(&pr->power.dev))
+ return -EIO;
+ #endif
+
printk(KERN_INFO PREFIX "CPU%d (power states:", pr->id);
for (i = 1; i <= pr->power.count; i++)
if (pr->power.states[i].valid)
pr->power.states[i].type);
printk(")\n");
+ #ifndef CONFIG_CPU_IDLE
if (pr->id == 0) {
pm_idle_save = pm_idle;
pm_idle = acpi_processor_idle;
}
+ #endif
}
/* 'power' [R] */
entry->owner = THIS_MODULE;
}
- pr->flags.power_setup_done = 1;
-
return 0;
}
int acpi_processor_power_exit(struct acpi_processor *pr,
struct acpi_device *device)
{
-
+ #ifdef CONFIG_CPU_IDLE
+ if ((pr->flags.power) && (!boot_option_idle_override))
+ cpuidle_unregister_device(&pr->power.dev);
+ #endif
pr->flags.power_setup_done = 0;
if (acpi_device_dir(device))
remove_proc_entry(ACPI_PROCESSOR_FILE_POWER,
acpi_device_dir(device));
+ #ifndef CONFIG_CPU_IDLE
+
/* Unregister the idle handler when processor #0 is removed. */
if (pr->id == 0) {
pm_idle = pm_idle_save;
unregister_latency_notifier(&acpi_processor_latency_notifier);
#endif
}
+ #endif
return 0;
}
ACPI_FLUSH_CPU_CACHE();
acpi_enable_wakeup_device_prep(acpi_state);
#endif
- acpi_gpe_sleep_prepare(acpi_state);
acpi_enter_sleep_state_prep(acpi_state);
return 0;
}
#ifdef CONFIG_SUSPEND
-static struct pm_ops acpi_pm_ops;
+static struct platform_suspend_ops acpi_pm_ops;
extern void do_suspend_lowlevel(void);
/**
* acpi_pm_prepare - Do preliminary suspend work.
- * @pm_state: ignored
*
* If necessary, set the firmware waking vector and do arch-specific
* nastiness to get the wakeup code to the waking vector.
*/
-static int acpi_pm_prepare(suspend_state_t pm_state)
+static int acpi_pm_prepare(void)
{
int error = acpi_sleep_prepare(acpi_target_sleep_state);
/**
* acpi_pm_finish - Finish up suspend sequence.
- * @pm_state: ignored
*
* This is called after we wake back up (or if entering the sleep state
* failed).
*/
-static int acpi_pm_finish(suspend_state_t pm_state)
+static void acpi_pm_finish(void)
{
u32 acpi_state = acpi_target_sleep_state;
init_8259A(0);
}
#endif
- return 0;
}
static int acpi_pm_state_valid(suspend_state_t pm_state)
}
}
-static struct pm_ops acpi_pm_ops = {
+static struct platform_suspend_ops acpi_pm_ops = {
.valid = acpi_pm_state_valid,
.set_target = acpi_pm_set_target,
.prepare = acpi_pm_prepare,
* Toshiba fails to preserve interrupts over S1, reinitialization
* of 8259 is needed after S1 resume.
*/
-static int __init init_ints_after_s1(struct dmi_system_id *d)
+static int __init init_ints_after_s1(const struct dmi_system_id *d)
{
printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident);
init_8259A_after_S1 = 1;
#endif /* CONFIG_SUSPEND */
#ifdef CONFIG_HIBERNATION
+static int acpi_hibernation_start(void)
+{
+ acpi_target_sleep_state = ACPI_STATE_S4;
+ return 0;
+}
+
static int acpi_hibernation_prepare(void)
{
return acpi_sleep_prepare(ACPI_STATE_S4);
return ACPI_SUCCESS(status) ? 0 : -EFAULT;
}
+static void acpi_hibernation_leave(void)
+{
+ /*
+ * If ACPI is not enabled by the BIOS and the boot kernel, we need to
+ * enable it here.
+ */
+ acpi_enable();
+}
+
static void acpi_hibernation_finish(void)
{
+ /*
+ * If ACPI is not enabled by the BIOS and the boot kernel, we need to
+ * enable it here.
+ */
+ acpi_enable();
acpi_leave_sleep_state(ACPI_STATE_S4);
acpi_disable_wakeup_device(ACPI_STATE_S4);
/* reset firmware waking vector */
acpi_set_firmware_waking_vector((acpi_physical_address) 0);
+
+ acpi_target_sleep_state = ACPI_STATE_S0;
}
static int acpi_hibernation_pre_restore(void)
acpi_hw_enable_all_runtime_gpes();
}
-static struct hibernation_ops acpi_hibernation_ops = {
+static struct platform_hibernation_ops acpi_hibernation_ops = {
+ .start = acpi_hibernation_start,
+ .pre_snapshot = acpi_hibernation_prepare,
+ .finish = acpi_hibernation_finish,
.prepare = acpi_hibernation_prepare,
.enter = acpi_hibernation_enter,
- .finish = acpi_hibernation_finish,
+ .leave = acpi_hibernation_leave,
.pre_restore = acpi_hibernation_pre_restore,
.restore_cleanup = acpi_hibernation_restore_cleanup,
};
}
}
- pm_set_ops(&acpi_pm_ops);
+ suspend_set_ops(&acpi_pm_ops);
#endif
#ifdef CONFIG_HIBERNATION
struct acpi_thermal_trips trips;
struct acpi_handle_list devices;
struct timer_list timer;
+ struct mutex lock;
};
static const struct file_operations acpi_thermal_state_fops = {
int result = 0;
struct acpi_thermal *tz = data;
unsigned long sleep_time = 0;
+ unsigned long timeout_jiffies = 0;
int i = 0;
struct acpi_thermal_state state;
return;
}
+ /* Check if someone else is already running */
+ if (!mutex_trylock(&tz->lock))
+ return;
+
state = tz->state;
result = acpi_thermal_get_temperature(tz);
if (result)
- return;
+ goto unlock;
memset(&tz->state, 0, sizeof(tz->state));
* a thermal event occurs). Note that _TSP and _TZD values are
* given in 1/10th seconds (we must covert to milliseconds).
*/
- if (tz->state.passive)
+ if (tz->state.passive) {
sleep_time = tz->trips.passive.tsp * 100;
- else if (tz->polling_frequency > 0)
+ timeout_jiffies = jiffies + (HZ * sleep_time) / 1000;
+ } else if (tz->polling_frequency > 0) {
sleep_time = tz->polling_frequency * 100;
+ timeout_jiffies = round_jiffies(jiffies + (HZ * sleep_time) / 1000);
+ }
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: temperature[%lu] sleep[%lu]\n",
tz->name, tz->temperature, sleep_time));
del_timer(&(tz->timer));
} else {
if (timer_pending(&(tz->timer)))
- mod_timer(&(tz->timer),
- jiffies + (HZ * sleep_time) / 1000);
+ mod_timer(&(tz->timer), timeout_jiffies);
else {
tz->timer.data = (unsigned long)tz;
tz->timer.function = acpi_thermal_run;
- tz->timer.expires = jiffies + (HZ * sleep_time) / 1000;
+ tz->timer.expires = timeout_jiffies;
add_timer(&(tz->timer));
}
}
-
- return;
+ unlock:
+ mutex_unlock(&tz->lock);
}
/* --------------------------------------------------------------------------
strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
acpi_driver_data(device) = tz;
-
+ mutex_init(&tz->lock);
result = acpi_thermal_get_info(tz);
if (result)
goto end;
}
acpi_thermal_remove_fs(device);
-
+ mutex_destroy(&tz->lock);
kfree(tz);
return 0;
}
}
#ifdef CONFIG_DMI
-static int thermal_act(struct dmi_system_id *d) {
+static int thermal_act(const struct dmi_system_id *d) {
if (act == 0) {
printk(KERN_NOTICE "ACPI: %s detected: "
}
return 0;
}
-static int thermal_nocrt(struct dmi_system_id *d) {
+static int thermal_nocrt(const struct dmi_system_id *d) {
printk(KERN_NOTICE "ACPI: %s detected: "
"disabling all critical thermal trip point actions.\n", d->ident);
nocrt = 1;
return 0;
}
-static int thermal_tzp(struct dmi_system_id *d) {
+static int thermal_tzp(const struct dmi_system_id *d) {
if (tzp == 0) {
printk(KERN_NOTICE "ACPI: %s detected: "
}
return 0;
}
-static int thermal_psv(struct dmi_system_id *d) {
+static int thermal_psv(const struct dmi_system_id *d) {
if (psv == 0) {
printk(KERN_NOTICE "ACPI: %s detected: "
{
unsigned long state;
struct acpi_video_device *vd =
- (struct acpi_video_device *)class_get_devdata(&od->class_dev);
+ (struct acpi_video_device *)dev_get_drvdata(&od->dev);
acpi_video_device_get_state(vd, &state);
return (int)state;
}
{
unsigned long state = od->request_state;
struct acpi_video_device *vd=
- (struct acpi_video_device *)class_get_devdata(&od->class_dev);
+ (struct acpi_video_device *)dev_get_drvdata(&od->dev);
return acpi_video_device_set_state(vd, state);
}
static int
acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
{
- int status;
+ int status = AE_OK;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
arg0.integer.value = level;
- status = acpi_evaluate_object(device->dev->handle, "_BCM", &args, NULL);
+ if (device->cap._BCM)
+ status = acpi_evaluate_object(device->dev->handle, "_BCM",
+ &args, NULL);
+ device->brightness->curr = level;
return status;
}
acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
unsigned long *level)
{
- int status;
-
- status = acpi_evaluate_integer(device->dev->handle, "_BQC", NULL, level);
-
- return status;
+ if (device->cap._BQC)
+ return acpi_evaluate_integer(device->dev->handle, "_BQC", NULL,
+ level);
+ *level = device->brightness->curr;
+ return AE_OK;
}
static int
acpi_video_get_next_level(struct acpi_video_device *device,
u32 level_current, u32 event)
{
- int min, max, min_above, max_below, i, l;
+ int min, max, min_above, max_below, i, l, delta = 255;
max = max_below = 0;
min = min_above = 255;
+ /* Find closest level to level_current */
+ for (i = 0; i < device->brightness->count; i++) {
+ l = device->brightness->levels[i];
+ if (abs(l - level_current) < abs(delta)) {
+ delta = l - level_current;
+ if (!delta)
+ break;
+ }
+ }
+ /* Ajust level_current to closest available level */
+ level_current += delta;
for (i = 0; i < device->brightness->count; i++) {
l = device->brightness->levels[i];
if (l < min)
If you have an ACPI-compatible ASUS laptop, say Y or M here.
+ config FUJITSU_LAPTOP
+ tristate "Fujitsu Laptop Extras"
+ depends on X86
+ depends on ACPI
+ depends on BACKLIGHT_CLASS_DEVICE
+ ---help---
+ This is a driver for laptops built by Fujitsu:
+
+ * P2xxx/P5xxx/S6xxx/S7xxx series Lifebooks
+ * Possibly other Fujitsu laptop models
+
+ It adds support for LCD brightness control.
+
+ If you have a Fujitsu laptop, say Y or M here.
+
config MSI_LAPTOP
tristate "MSI Laptop Extras"
depends on X86
tristate "Sony Laptop Extras"
depends on X86 && ACPI
select BACKLIGHT_CLASS_DEVICE
+ depends on INPUT
---help---
This mini-driver drives the SNC and SPIC devices present in the ACPI
BIOS of the Sony Vaio laptops.
select BACKLIGHT_CLASS_DEVICE
select HWMON
select NVRAM
+ depends on INPUT
---help---
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
support for Fn-Fx key combinations, Bluetooth control, video
If you are not sure, say Y here.
+config ATMEL_SSC
+ tristate "Device driver for Atmel SSC peripheral"
+ depends on AVR32 || ARCH_AT91
+ ---help---
+ This option enables device driver support for Atmel Syncronized
+ Serial Communication peripheral (SSC).
+
+ The SSC peripheral supports a wide variety of serial frame based
+ communications, i.e. I2S, SPI, etc.
+
+ If unsure, say N.
+
endif # MISC_DEVICES
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
+obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_LKDTM) += lkdtm.o
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
obj-$(CONFIG_SGI_IOC4) += ioc4.o
obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
+ obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
jog_dev->id.bustype = BUS_ISA;
jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
- jog_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- jog_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE);
- jog_dev->relbit[0] = BIT(REL_WHEEL);
+ jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE);
+ jog_dev->relbit[0] = BIT_MASK(REL_WHEEL);
error = input_register_device(jog_dev);
if (error)
/* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence
* for Fn keys
*/
-static int sony_nc_C_enable(struct dmi_system_id *id)
+static int sony_nc_C_enable(const struct dmi_system_id *id)
{
int result = 0;
};
/* SNC-only model map */
-static struct dmi_system_id sony_nc_ids[] = {
+static const struct dmi_system_id sony_nc_ids[] = {
{
.ident = "Sony Vaio FE Series",
.callback = sony_nc_C_enable,
#define SONYPI_TYPE3_OFFSET 0x12
struct sony_pic_ioport {
- struct acpi_resource_io io;
+ struct acpi_resource_io io1;
+ struct acpi_resource_io io2;
struct list_head list;
};
{
u8 v1, v2;
- wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+ wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
ITERATIONS_LONG);
- outb(dev, spic_dev.cur_ioport->io.minimum + 4);
- v1 = inb_p(spic_dev.cur_ioport->io.minimum + 4);
- v2 = inb_p(spic_dev.cur_ioport->io.minimum);
+ outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
+ v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4);
+ v2 = inb_p(spic_dev.cur_ioport->io1.minimum);
dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1);
return v2;
}
{
u8 v1;
- wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+ wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
ITERATIONS_LONG);
- outb(dev, spic_dev.cur_ioport->io.minimum + 4);
- wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+ outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
+ wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
ITERATIONS_LONG);
- outb(fn, spic_dev.cur_ioport->io.minimum);
- v1 = inb_p(spic_dev.cur_ioport->io.minimum);
+ outb(fn, spic_dev.cur_ioport->io1.minimum);
+ v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
dprintk("sony_pic_call2: 0x%.4x\n", v1);
return v1;
}
{
u8 v1;
- wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
- outb(dev, spic_dev.cur_ioport->io.minimum + 4);
- wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
- outb(fn, spic_dev.cur_ioport->io.minimum);
- wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
- outb(v, spic_dev.cur_ioport->io.minimum);
- v1 = inb_p(spic_dev.cur_ioport->io.minimum);
+ wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
+ outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
+ wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
+ outb(fn, spic_dev.cur_ioport->io1.minimum);
+ wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
+ outb(v, spic_dev.cur_ioport->io1.minimum);
+ v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
dprintk("sony_pic_call3: 0x%.4x\n", v1);
return v1;
}
switch (resource->type) {
case ACPI_RESOURCE_TYPE_START_DEPENDENT:
+ {
+ /* start IO enumeration */
+ struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
+ if (!ioport)
+ return AE_ERROR;
+
+ list_add(&ioport->list, &dev->ioports);
+ return AE_OK;
+ }
+
case ACPI_RESOURCE_TYPE_END_DEPENDENT:
+ /* end IO enumeration */
return AE_OK;
case ACPI_RESOURCE_TYPE_IRQ:
if (!interrupt)
return AE_ERROR;
- list_add_tail(&interrupt->list, &dev->interrupts);
+ list_add(&interrupt->list, &dev->interrupts);
interrupt->irq.triggering = p->triggering;
interrupt->irq.polarity = p->polarity;
interrupt->irq.sharable = p->sharable;
case ACPI_RESOURCE_TYPE_IO:
{
struct acpi_resource_io *io = &resource->data.io;
- struct sony_pic_ioport *ioport = NULL;
+ struct sony_pic_ioport *ioport =
+ list_first_entry(&dev->ioports, struct sony_pic_ioport, list);
if (!io) {
dprintk("Blank IO resource\n");
return AE_OK;
}
- ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
- if (!ioport)
+ if (!ioport->io1.minimum) {
+ memcpy(&ioport->io1, io, sizeof(*io));
+ dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum,
+ ioport->io1.address_length);
+ }
+ else if (!ioport->io2.minimum) {
+ memcpy(&ioport->io2, io, sizeof(*io));
+ dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum,
+ ioport->io2.address_length);
+ }
+ else {
+ printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n");
return AE_ERROR;
-
- list_add_tail(&ioport->list, &dev->ioports);
- memcpy(&ioport->io, io, sizeof(*io));
+ }
return AE_OK;
}
default:
{
acpi_status status;
int result = 0;
+ /* Type 1 resource layout is:
+ * IO
+ * IO
+ * IRQNoFlags
+ * End
+ *
+ * Type 2 and 3 resource layout is:
+ * IO
+ * IRQNoFlags
+ * End
+ */
struct {
- struct acpi_resource io_res;
- struct acpi_resource irq_res;
- struct acpi_resource end;
+ struct acpi_resource res1;
+ struct acpi_resource res2;
+ struct acpi_resource res3;
+ struct acpi_resource res4;
} *resource;
struct acpi_buffer buffer = { 0, NULL };
buffer.length = sizeof(*resource) + 1;
buffer.pointer = resource;
- /* setup io resource */
- resource->io_res.type = ACPI_RESOURCE_TYPE_IO;
- resource->io_res.length = sizeof(struct acpi_resource);
- memcpy(&resource->io_res.data.io, &ioport->io,
- sizeof(struct acpi_resource_io));
+ /* setup Type 1 resources */
+ if (spic_dev.model == SONYPI_DEVICE_TYPE1) {
- /* setup irq resource */
- resource->irq_res.type = ACPI_RESOURCE_TYPE_IRQ;
- resource->irq_res.length = sizeof(struct acpi_resource);
- memcpy(&resource->irq_res.data.irq, &irq->irq,
- sizeof(struct acpi_resource_irq));
- /* we requested a shared irq */
- resource->irq_res.data.irq.sharable = ACPI_SHARED;
+ /* setup io resources */
+ resource->res1.type = ACPI_RESOURCE_TYPE_IO;
+ resource->res1.length = sizeof(struct acpi_resource);
+ memcpy(&resource->res1.data.io, &ioport->io1,
+ sizeof(struct acpi_resource_io));
- resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
+ resource->res2.type = ACPI_RESOURCE_TYPE_IO;
+ resource->res2.length = sizeof(struct acpi_resource);
+ memcpy(&resource->res2.data.io, &ioport->io2,
+ sizeof(struct acpi_resource_io));
+
+ /* setup irq resource */
+ resource->res3.type = ACPI_RESOURCE_TYPE_IRQ;
+ resource->res3.length = sizeof(struct acpi_resource);
+ memcpy(&resource->res3.data.irq, &irq->irq,
+ sizeof(struct acpi_resource_irq));
+ /* we requested a shared irq */
+ resource->res3.data.irq.sharable = ACPI_SHARED;
+
+ resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG;
+
+ }
+ /* setup Type 2/3 resources */
+ else {
+ /* setup io resource */
+ resource->res1.type = ACPI_RESOURCE_TYPE_IO;
+ resource->res1.length = sizeof(struct acpi_resource);
+ memcpy(&resource->res1.data.io, &ioport->io1,
+ sizeof(struct acpi_resource_io));
+
+ /* setup irq resource */
+ resource->res2.type = ACPI_RESOURCE_TYPE_IRQ;
+ resource->res2.length = sizeof(struct acpi_resource);
+ memcpy(&resource->res2.data.irq, &irq->irq,
+ sizeof(struct acpi_resource_irq));
+ /* we requested a shared irq */
+ resource->res2.data.irq.sharable = ACPI_SHARED;
+
+ resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG;
+ }
/* Attempt to set the resource */
dprintk("Evaluating _SRS\n");
/* check for total failure */
if (ACPI_FAILURE(status)) {
- printk(KERN_ERR DRV_PFX "Error evaluating _SRS");
+ printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n");
result = -ENODEV;
goto end;
}
struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
- ev = inb_p(dev->cur_ioport->io.minimum);
- data_mask = inb_p(dev->cur_ioport->io.minimum + dev->evport_offset);
+ ev = inb_p(dev->cur_ioport->io1.minimum);
+ if (dev->cur_ioport->io2.minimum)
+ data_mask = inb_p(dev->cur_ioport->io2.minimum);
+ else
+ data_mask = inb_p(dev->cur_ioport->io1.minimum + dev->evport_offset);
dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
- ev, data_mask, dev->cur_ioport->io.minimum, dev->evport_offset);
+ ev, data_mask, dev->cur_ioport->io1.minimum, dev->evport_offset);
if (ev == 0x00 || ev == 0xff)
return IRQ_HANDLED;
}
free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
- release_region(spic_dev.cur_ioport->io.minimum,
- spic_dev.cur_ioport->io.address_length);
+ release_region(spic_dev.cur_ioport->io1.minimum,
+ spic_dev.cur_ioport->io1.address_length);
+ if (spic_dev.cur_ioport->io2.minimum)
+ release_region(spic_dev.cur_ioport->io2.minimum,
+ spic_dev.cur_ioport->io2.address_length);
sonypi_compat_exit();
goto err_remove_input;
/* request io port */
- list_for_each_entry(io, &spic_dev.ioports, list) {
- if (request_region(io->io.minimum, io->io.address_length,
+ list_for_each_entry_reverse(io, &spic_dev.ioports, list) {
+ if (request_region(io->io1.minimum, io->io1.address_length,
"Sony Programable I/O Device")) {
- dprintk("I/O port: 0x%.4x (0x%.4x) + 0x%.2x\n",
- io->io.minimum, io->io.maximum,
- io->io.address_length);
- spic_dev.cur_ioport = io;
- break;
+ dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n",
+ io->io1.minimum, io->io1.maximum,
+ io->io1.address_length);
+ /* Type 1 have 2 ioports */
+ if (io->io2.minimum) {
+ if (request_region(io->io2.minimum,
+ io->io2.address_length,
+ "Sony Programable I/O Device")) {
+ dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n",
+ io->io2.minimum, io->io2.maximum,
+ io->io2.address_length);
+ spic_dev.cur_ioport = io;
+ break;
+ }
+ else {
+ dprintk("Unable to get I/O port2: "
+ "0x%.4x (0x%.4x) + 0x%.2x\n",
+ io->io2.minimum, io->io2.maximum,
+ io->io2.address_length);
+ release_region(io->io1.minimum,
+ io->io1.address_length);
+ }
+ }
+ else {
+ spic_dev.cur_ioport = io;
+ break;
+ }
}
}
if (!spic_dev.cur_ioport) {
}
/* request IRQ */
- list_for_each_entry(irq, &spic_dev.interrupts, list) {
+ list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) {
if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
IRQF_SHARED, "sony-laptop", &spic_dev)) {
dprintk("IRQ: %d - triggering: %d - "
free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
err_release_region:
- release_region(spic_dev.cur_ioport->io.minimum,
- spic_dev.cur_ioport->io.address_length);
+ release_region(spic_dev.cur_ioport->io1.minimum,
+ spic_dev.cur_ioport->io1.address_length);
+ if (spic_dev.cur_ioport->io2.minimum)
+ release_region(spic_dev.cur_ioport->io2.minimum,
+ spic_dev.cur_ioport->io2.address_length);
err_remove_compat:
sonypi_compat_exit();
*/
#define IBM_VERSION "0.16"
- #define TPACPI_SYSFS_VERSION 0x010000
+ #define TPACPI_SYSFS_VERSION 0x020000
/*
* Changelog:
#define __unused __attribute__ ((unused))
+ static enum {
+ TPACPI_LIFE_INIT = 0,
+ TPACPI_LIFE_RUNNING,
+ TPACPI_LIFE_EXITING,
+ } tpacpi_lifecycle;
+
/****************************************************************************
****************************************************************************
*
{
struct ibm_struct *ibm = data;
+ if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
+ return;
+
if (!ibm || !ibm->acpi || !ibm->acpi->notify)
return;
****************************************************************************/
static struct platform_device *tpacpi_pdev;
-static struct class_device *tpacpi_hwmon;
+ static struct platform_device *tpacpi_sensors_pdev;
+static struct device *tpacpi_hwmon;
static struct input_dev *tpacpi_inputdev;
+ static struct mutex tpacpi_inputdev_send_mutex;
static int tpacpi_resume_handler(struct platform_device *pdev)
.resume = tpacpi_resume_handler,
};
+ static struct platform_driver tpacpi_hwmon_pdriver = {
+ .driver = {
+ .name = IBM_HWMON_DRVR_NAME,
+ .owner = THIS_MODULE,
+ },
+ };
/*************************************************************************
* thinkpad-acpi driver attributes
{
char *endp;
+ while (*buf && isspace(*buf))
+ buf++;
*value = simple_strtoul(buf, &endp, 0);
while (*endp && isspace(*endp))
endp++;
KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
KEY_UNKNOWN, /* 0x0D: FN+INSERT */
KEY_UNKNOWN, /* 0x0E: FN+DELETE */
- KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
+ KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */
/* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
- KEY_RESERVED, /* 0x10: FN+END (brightness down) */
+ KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */
KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
- KEY_RESERVED, /* 0x14: VOLUME UP */
- KEY_RESERVED, /* 0x15: VOLUME DOWN */
- KEY_RESERVED, /* 0x16: MUTE */
+ KEY_VOLUMEUP, /* 0x14: VOLUME UP */
+ KEY_VOLUMEDOWN, /* 0x15: VOLUME DOWN */
+ KEY_MUTE, /* 0x16: MUTE */
KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
/* (assignments unknown, please report if found) */
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
- KEY_RESERVED, /* 0x14: VOLUME UP */
- KEY_RESERVED, /* 0x15: VOLUME DOWN */
- KEY_RESERVED, /* 0x16: MUTE */
+ KEY_VOLUMEUP, /* 0x14: VOLUME UP */
+ KEY_VOLUMEDOWN, /* 0x15: VOLUME DOWN */
+ KEY_MUTE, /* 0x16: MUTE */
KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
/* (assignments unknown, please report if found) */
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
int res, i;
int status;
+ int hkeyv;
vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
return res;
/* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
- A30, R30, R31, T20-22, X20-21, X22-24 */
- tp_features.hotkey_mask =
- acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
+ A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking
+ for HKEY interface version 0x100 */
+ if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
+ if ((hkeyv >> 8) != 1) {
+ printk(IBM_ERR "unknown version of the "
+ "HKEY interface: 0x%x\n", hkeyv);
+ printk(IBM_ERR "please report this to %s\n",
+ IBM_MAIL);
+ } else {
+ /*
+ * MHKV 0x100 in A31, R40, R40e,
+ * T4x, X31, and later
+ * */
+ tp_features.hotkey_mask = 1;
+ }
+ }
vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
str_supported(tp_features.hotkey_mask));
if (tp_features.hotkey_mask) {
- /* MHKA available in A31, R40, R40e, T4x, X31, and later */
if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
- "MHKA", "qd"))
+ "MHKA", "qd")) {
+ printk(IBM_ERR
+ "missing MHKA handler, "
+ "please report this to %s\n",
+ IBM_MAIL);
hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */
+ }
}
res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
unsigned int keycode)
{
if (keycode != KEY_RESERVED) {
+ mutex_lock(&tpacpi_inputdev_send_mutex);
+
input_report_key(tpacpi_inputdev, keycode, 1);
if (keycode == KEY_UNKNOWN)
input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
scancode);
input_sync(tpacpi_inputdev);
+
+ mutex_unlock(&tpacpi_inputdev_send_mutex);
}
}
{
int wlsw;
- if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw))
+ mutex_lock(&tpacpi_inputdev_send_mutex);
+
+ if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
input_report_switch(tpacpi_inputdev,
SW_RADIO, !!wlsw);
+ input_sync(tpacpi_inputdev);
+ }
+
+ mutex_unlock(&tpacpi_inputdev_send_mutex);
}
static void hotkey_notify(struct ibm_struct *ibm, u32 event)
{
u32 hkey;
unsigned int keycode, scancode;
- int send_acpi_ev = 0;
+ int send_acpi_ev;
+ int ignore_acpi_ev;
+
+ if (event != 0x80) {
+ printk(IBM_ERR "unknown HKEY notification event %d\n", event);
+ /* forward it to userspace, maybe it knows how to handle it */
+ acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
+ ibm->acpi->device->dev.bus_id,
+ event, 0);
+ return;
+ }
+
+ while (1) {
+ if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
+ printk(IBM_ERR "failed to retrieve HKEY event\n");
+ return;
+ }
+
+ if (hkey == 0) {
+ /* queue empty */
+ return;
+ }
+
+ send_acpi_ev = 0;
+ ignore_acpi_ev = 0;
- if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
switch (hkey >> 12) {
case 1:
/* 0x1000-0x1FFF: key presses */
* eat up known LID events */
if (hkey != 0x5001 && hkey != 0x5002) {
printk(IBM_ERR
- "unknown LID-related hotkey event: 0x%04x\n",
- hkey);
+ "unknown LID-related HKEY event: 0x%04x\n",
+ hkey);
send_acpi_ev = 1;
+ } else {
+ ignore_acpi_ev = 1;
}
break;
case 7:
printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey);
send_acpi_ev = 1;
}
- } else {
- printk(IBM_ERR "unknown hotkey notification event %d\n", event);
- hkey = 0;
- send_acpi_ev = 1;
- }
- /* Legacy events */
- if (send_acpi_ev || hotkey_report_mode < 2)
- acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey);
+ /* Legacy events */
+ if (!ignore_acpi_ev && (send_acpi_ev || hotkey_report_mode < 2)) {
+ acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey);
+ }
- /* netlink events */
- if (send_acpi_ev) {
- acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
- ibm->acpi->device->dev.bus_id,
- event, hkey);
+ /* netlink events */
+ if (!ignore_acpi_ev && send_acpi_ev) {
+ acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
+ ibm->acpi->device->dev.bus_id,
+ event, hkey);
+ }
}
}
switch(thermal_read_mode) {
case TPACPI_THERMAL_TPEC_16:
- res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+ res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
&thermal_temp_input16_group);
if (res)
return res;
case TPACPI_THERMAL_TPEC_8:
case TPACPI_THERMAL_ACPI_TMP07:
case TPACPI_THERMAL_ACPI_UPDT:
- res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+ res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
&thermal_temp_input8_group);
if (res)
return res;
{
switch(thermal_read_mode) {
case TPACPI_THERMAL_TPEC_16:
- sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+ sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
&thermal_temp_input16_group);
break;
case TPACPI_THERMAL_TPEC_8:
case TPACPI_THERMAL_ACPI_TMP07:
case TPACPI_THERMAL_ACPI_UPDT:
- sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+ sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
&thermal_temp_input16_group);
break;
case TPACPI_THERMAL_NONE:
__ATTR(fan1_input, S_IRUGO,
fan_fan1_input_show, NULL);
- /* sysfs fan fan_watchdog (driver) ------------------------------------- */
+ /* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */
static ssize_t fan_fan_watchdog_show(struct device_driver *drv,
char *buf)
{
if (fan_status_access_mode != TPACPI_FAN_NONE ||
fan_control_access_mode != TPACPI_FAN_WR_NONE) {
- rc = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+ rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
&fan_attr_group);
if (!(rc < 0))
- rc = driver_create_file(&tpacpi_pdriver.driver,
+ rc = driver_create_file(&tpacpi_hwmon_pdriver.driver,
&driver_attr_fan_watchdog);
if (rc < 0)
return rc;
vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n");
/* FIXME: can we really do this unconditionally? */
- sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group);
- driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog);
+ sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group);
+ driver_remove_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog);
cancel_delayed_work(&fan_watchdog_task);
flush_scheduled_work();
{
int rc;
+ if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
+ return;
+
printk(IBM_NOTICE "fan watchdog: enabling fan\n");
rc = fan_set_enable();
if (rc < 0) {
if (fan_watchdog_active)
cancel_delayed_work(&fan_watchdog_task);
- if (fan_watchdog_maxinterval > 0) {
+ if (fan_watchdog_maxinterval > 0 &&
+ tpacpi_lifecycle != TPACPI_LIFE_EXITING) {
fan_watchdog_active = 1;
if (!schedule_delayed_work(&fan_watchdog_task,
msecs_to_jiffies(fan_watchdog_maxinterval
****************************************************************************
****************************************************************************/
+ /* sysfs name ---------------------------------------------------------- */
+ static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+ {
+ return snprintf(buf, PAGE_SIZE, "%s\n", IBM_NAME);
+ }
+
+ static struct device_attribute dev_attr_thinkpad_acpi_pdev_name =
+ __ATTR(name, S_IRUGO, thinkpad_acpi_pdev_name_show, NULL);
+
+ /* --------------------------------------------------------------------- */
+
/* /proc support */
static struct proc_dir_entry *proc_dir;
static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
{
- struct dmi_device *dev = NULL;
+ const struct dmi_device *dev = NULL;
char ec_fw_string[18];
if (!tp)
{
int ret, i;
+ tpacpi_lifecycle = TPACPI_LIFE_INIT;
+
/* Parameter checking */
if (hotkey_report_mode > 2)
return -EINVAL;
ret = platform_driver_register(&tpacpi_pdriver);
if (ret) {
- printk(IBM_ERR "unable to register platform driver\n");
+ printk(IBM_ERR "unable to register main platform driver\n");
thinkpad_acpi_module_exit();
return ret;
}
tp_features.platform_drv_registered = 1;
+ ret = platform_driver_register(&tpacpi_hwmon_pdriver);
+ if (ret) {
+ printk(IBM_ERR "unable to register hwmon platform driver\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ tp_features.sensors_pdrv_registered = 1;
+
ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver);
+ if (!ret) {
+ tp_features.platform_drv_attrs_registered = 1;
+ ret = tpacpi_create_driver_attributes(&tpacpi_hwmon_pdriver.driver);
+ }
if (ret) {
printk(IBM_ERR "unable to create sysfs driver attributes\n");
thinkpad_acpi_module_exit();
return ret;
}
- tp_features.platform_drv_attrs_registered = 1;
+ tp_features.sensors_pdrv_attrs_registered = 1;
/* Device initialization */
thinkpad_acpi_module_exit();
return ret;
}
- tpacpi_hwmon = hwmon_device_register(&tpacpi_pdev->dev);
+ tpacpi_sensors_pdev = platform_device_register_simple(
+ IBM_HWMON_DRVR_NAME,
+ -1, NULL, 0);
+ if (IS_ERR(tpacpi_sensors_pdev)) {
+ ret = PTR_ERR(tpacpi_sensors_pdev);
+ tpacpi_sensors_pdev = NULL;
+ printk(IBM_ERR "unable to register hwmon platform device\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ ret = device_create_file(&tpacpi_sensors_pdev->dev,
+ &dev_attr_thinkpad_acpi_pdev_name);
+ if (ret) {
+ printk(IBM_ERR
+ "unable to create sysfs hwmon device attributes\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ tp_features.sensors_pdev_attrs_registered = 1;
+ tpacpi_hwmon = hwmon_device_register(&tpacpi_sensors_pdev->dev);
if (IS_ERR(tpacpi_hwmon)) {
ret = PTR_ERR(tpacpi_hwmon);
tpacpi_hwmon = NULL;
thinkpad_acpi_module_exit();
return ret;
}
+ mutex_init(&tpacpi_inputdev_send_mutex);
tpacpi_inputdev = input_allocate_device();
if (!tpacpi_inputdev) {
printk(IBM_ERR "unable to allocate input device\n");
tp_features.input_device_registered = 1;
}
+ tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
return 0;
}
{
struct ibm_struct *ibm, *itmp;
+ tpacpi_lifecycle = TPACPI_LIFE_EXITING;
+
list_for_each_entry_safe_reverse(ibm, itmp,
&tpacpi_all_drivers,
all_drivers) {
if (tpacpi_hwmon)
hwmon_device_unregister(tpacpi_hwmon);
+ if (tp_features.sensors_pdev_attrs_registered)
+ device_remove_file(&tpacpi_sensors_pdev->dev,
+ &dev_attr_thinkpad_acpi_pdev_name);
+ if (tpacpi_sensors_pdev)
+ platform_device_unregister(tpacpi_sensors_pdev);
if (tpacpi_pdev)
platform_device_unregister(tpacpi_pdev);
+ if (tp_features.sensors_pdrv_attrs_registered)
+ tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver);
if (tp_features.platform_drv_attrs_registered)
tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
+ if (tp_features.sensors_pdrv_registered)
+ platform_driver_unregister(&tpacpi_hwmon_pdriver);
+
if (tp_features.platform_drv_registered)
platform_driver_unregister(&tpacpi_pdriver);
#define IBM_NAME "thinkpad"
#define IBM_DESC "ThinkPad ACPI Extras"
- #define IBM_FILE "thinkpad_acpi"
+ #define IBM_FILE IBM_NAME "_acpi"
#define IBM_URL "http://ibm-acpi.sf.net/"
#define IBM_PROC_DIR "ibm"
#define IBM_ACPI_EVENT_PREFIX "ibm"
#define IBM_DRVR_NAME IBM_FILE
+ #define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon"
#define IBM_LOG IBM_FILE ": "
#define IBM_ERR KERN_ERR IBM_LOG
/* Device model */
static struct platform_device *tpacpi_pdev;
-static struct class_device *tpacpi_hwmon;
+ static struct platform_device *tpacpi_sensors_pdev;
+static struct device *tpacpi_hwmon;
static struct platform_driver tpacpi_pdriver;
static struct input_dev *tpacpi_inputdev;
static int tpacpi_create_driver_attributes(struct device_driver *drv);
static struct {
#ifdef CONFIG_THINKPAD_ACPI_BAY
- u16 bay_status:1;
- u16 bay_eject:1;
- u16 bay_status2:1;
- u16 bay_eject2:1;
+ u32 bay_status:1;
+ u32 bay_eject:1;
+ u32 bay_status2:1;
+ u32 bay_eject2:1;
#endif
- u16 bluetooth:1;
- u16 hotkey:1;
- u16 hotkey_mask:1;
- u16 hotkey_wlsw:1;
- u16 light:1;
- u16 light_status:1;
- u16 wan:1;
- u16 fan_ctrl_status_undef:1;
- u16 input_device_registered:1;
- u16 platform_drv_registered:1;
- u16 platform_drv_attrs_registered:1;
+ u32 bluetooth:1;
+ u32 hotkey:1;
+ u32 hotkey_mask:1;
+ u32 hotkey_wlsw:1;
+ u32 light:1;
+ u32 light_status:1;
+ u32 wan:1;
+ u32 fan_ctrl_status_undef:1;
+ u32 input_device_registered:1;
+ u32 platform_drv_registered:1;
+ u32 platform_drv_attrs_registered:1;
+ u32 sensors_pdrv_registered:1;
+ u32 sensors_pdrv_attrs_registered:1;
+ u32 sensors_pdev_attrs_registered:1;
} tp_features;
struct thinkpad_id_data {
modify_acceptable_latency("ipw2100", INFINITE_LATENCY);
- #ifdef ACPI_CSTATE_LIMIT_DEFINED
- if (priv->config & CFG_C3_DISABLED) {
- IPW_DEBUG_INFO(": Resetting C3 transitions.\n");
- acpi_set_cstate_limit(priv->cstate_limit);
- priv->config &= ~CFG_C3_DISABLED;
- }
- #endif
-
/* We have to signal any supplicant if we are disassociating */
if (associated)
wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
u32 chan;
char *txratename;
u8 bssid[ETH_ALEN];
+ DECLARE_MAC_BUF(mac);
/*
* TBD: BSSID is usually 00:00:00:00:00:00 here and not
}
IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID="
- MAC_FMT ")\n",
+ "%s)\n",
priv->net_dev->name, escape_essid(essid, essid_len),
- txratename, chan, MAC_ARG(bssid));
+ txratename, chan, print_mac(mac, bssid));
/* now we copy read ssid into dev */
if (!(priv->config & CFG_STATIC_ESSID)) {
static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
{
+ DECLARE_MAC_BUF(mac);
+
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
- "disassociated: '%s' " MAC_FMT " \n",
+ "disassociated: '%s' %s \n",
escape_essid(priv->essid, priv->essid_len),
- MAC_ARG(priv->bssid));
+ print_mac(mac, priv->bssid));
priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
/* RF_KILL is now enabled (else we wouldn't be here) */
priv->status |= STATUS_RF_KILL_HW;
- #ifdef ACPI_CSTATE_LIMIT_DEFINED
- if (priv->config & CFG_C3_DISABLED) {
- IPW_DEBUG_INFO(": Resetting C3 transitions.\n");
- acpi_set_cstate_limit(priv->cstate_limit);
- priv->config &= ~CFG_C3_DISABLED;
- }
- #endif
-
/* Make sure the RF Kill check timer is running */
priv->stop_rf_kill = 0;
cancel_delayed_work(&priv->rf_kill);
u32 match, reg;
int j;
#endif
- #ifdef ACPI_CSTATE_LIMIT_DEFINED
- int limit;
- #endif
IPW_DEBUG_INFO(": PCI latency error detected at 0x%04zX.\n",
i * sizeof(struct ipw2100_status));
- #ifdef ACPI_CSTATE_LIMIT_DEFINED
- IPW_DEBUG_INFO(": Disabling C3 transitions.\n");
- limit = acpi_get_cstate_limit();
- if (limit > 2) {
- priv->cstate_limit = limit;
- acpi_set_cstate_limit(2);
- priv->config |= CFG_C3_DISABLED;
- }
- #endif
-
#ifdef IPW2100_DEBUG_C3
/* Halt the fimrware so we can get a good image */
write_register(priv->net_dev, IPW_REG_RESET_REG,
char *out = buf;
int length;
int ret;
+ DECLARE_MAC_BUF(mac);
if (priv->status & STATUS_RF_KILL_MASK)
return 0;
__LINE__);
out += sprintf(out, "ESSID: %s\n", essid);
- out += sprintf(out, "BSSID: %02x:%02x:%02x:%02x:%02x:%02x\n",
- bssid[0], bssid[1], bssid[2],
- bssid[3], bssid[4], bssid[5]);
+ out += sprintf(out, "BSSID: %s\n", print_mac(mac, bssid));
out += sprintf(out, "Channel: %d\n", chan);
return out - buf;
static int ipw2100_read_mac_address(struct ipw2100_priv *priv)
{
u32 length = ETH_ALEN;
- u8 mac[ETH_ALEN];
+ u8 addr[ETH_ALEN];
+ DECLARE_MAC_BUF(mac);
int err;
- err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, mac, &length);
+ err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, addr, &length);
if (err) {
IPW_DEBUG_INFO("MAC address read failed\n");
return -EIO;
}
- IPW_DEBUG_INFO("card MAC is %02X:%02X:%02X:%02X:%02X:%02X\n",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
- memcpy(priv->net_dev->dev_addr, mac, ETH_ALEN);
+ memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN);
+ IPW_DEBUG_INFO("card MAC is %s\n",
+ print_mac(mac, priv->net_dev->dev_addr));
return 0;
}
int err;
#ifdef CONFIG_IPW2100_DEBUG
+ DECLARE_MAC_BUF(mac);
if (bssid != NULL)
- IPW_DEBUG_HC("MANDATORY_BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n",
- bssid[0], bssid[1], bssid[2], bssid[3], bssid[4],
- bssid[5]);
+ IPW_DEBUG_HC("MANDATORY_BSSID: %s\n",
+ print_mac(mac, bssid));
else
IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
#endif
IPW_DEBUG_INFO("Attempting to register device...\n");
- SET_MODULE_OWNER(dev);
-
printk(KERN_INFO DRV_NAME
": Detected Intel PRO/Wireless 2100 Network Connection\n");
static const unsigned char off[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
+ DECLARE_MAC_BUF(mac);
// sanity checks
if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0);
- IPW_DEBUG_WX("SET BSSID -> %02X:%02X:%02X:%02X:%02X:%02X\n",
- wrqu->ap_addr.sa_data[0] & 0xff,
- wrqu->ap_addr.sa_data[1] & 0xff,
- wrqu->ap_addr.sa_data[2] & 0xff,
- wrqu->ap_addr.sa_data[3] & 0xff,
- wrqu->ap_addr.sa_data[4] & 0xff,
- wrqu->ap_addr.sa_data[5] & 0xff);
+ IPW_DEBUG_WX("SET BSSID -> %s\n",
+ print_mac(mac, wrqu->ap_addr.sa_data));
done:
mutex_unlock(&priv->action_mutex);
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
+ DECLARE_MAC_BUF(mac);
/* If we are associated, trying to associate, or have a statically
* configured BSSID then return that; otherwise return ANY */
} else
memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
- IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n",
- MAC_ARG(wrqu->ap_addr.sa_data));
+ IPW_DEBUG_WX("Getting WAP BSSID: %s\n",
+ print_mac(mac, wrqu->ap_addr.sa_data));
return 0;
}
static struct iw_handler_def ipw2100_wx_handler_def = {
.standard = ipw2100_wx_handlers,
- .num_standard = sizeof(ipw2100_wx_handlers) / sizeof(iw_handler),
- .num_private = sizeof(ipw2100_private_handler) / sizeof(iw_handler),
- .num_private_args = sizeof(ipw2100_private_args) /
- sizeof(struct iw_priv_args),
+ .num_standard = ARRAY_SIZE(ipw2100_wx_handlers),
+ .num_private = ARRAY_SIZE(ipw2100_private_handler),
+ .num_private_args = ARRAY_SIZE(ipw2100_private_args),
.private = (iw_handler *) ipw2100_private_handler,
.private_args = (struct iw_priv_args *)ipw2100_private_args,
.get_wireless_stats = ipw2100_wx_wireless_stats,
unsigned long seq, last_jiffies, next_jiffies, delta_jiffies, flags;
struct tick_sched *ts;
ktime_t last_update, expires, now, delta;
+ struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
int cpu;
local_irq_save(flags);
out:
ts->next_jiffies = next_jiffies;
ts->last_jiffies = last_jiffies;
+ ts->sleep_length = ktime_sub(dev->next_event, now);
end:
local_irq_restore(flags);
}
+ /**
+ * tick_nohz_get_sleep_length - return the length of the current sleep
+ *
+ * Called from power state control code with interrupts disabled
+ */
+ ktime_t tick_nohz_get_sleep_length(void)
+ {
+ struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
+
+ return ts->sleep_length;
+ }
+
+ EXPORT_SYMBOL_GPL(tick_nohz_get_sleep_length);
+
/**
* nohz_restart_sched_tick - restart the idle tick from the idle task
*
/* Get the next period (per cpu) */
ts->sched_timer.expires = tick_init_jiffy_update();
offset = ktime_to_ns(tick_period) >> 1;
- do_div(offset, NR_CPUS);
+ do_div(offset, num_possible_cpus());
offset *= smp_processor_id();
ts->sched_timer.expires = ktime_add_ns(ts->sched_timer.expires, offset);