Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (28 commits) ACPI: check battery status on resume for un/plug events during sleep ACPICA: Fix incorrect handling of PCI Express Root Bridge _HID ACPI: asus_acpi: don't printk on writing garbage to proc files ACPI: asus_acpi: fix proc files parsing ACPI: SCI interrupt source override ACPI: fix printk format warnings ACPI: fix section for CPU init functions ACPI: update comments in motherboard.c ACPI: acpi_pci_link_set() can allocate with either GFP_ATOMIC or GFP_KERNEL ACPI: fix potential OOPS in power driver with CONFIG_ACPI_DEBUG ACPI: ibm_acpi: delete obsolete documentation ACPI: created a dedicated workqueue for notify() execution ACPI: Remove deferred execution from global lock acquire wakeup path MSI S270 Laptop support: backlight, wlan, bluetooth states ACPI: EC: export ec_transaction() for msi-laptop driver ACPI: EC: Simplify acpi_hw_low_level*() with inb()/outb(). ACPI: EC: Unify poll and interrupt gpe handlers ACPI: EC: Unify poll and interrupt mode transaction functions ACPI: EC: Remove unused variables and duplicated code ACPI: EC: Remove unnecessary delay added by previous transation patch. ...
This commit is contained in:
commit
0b269d8462
@ -30,9 +30,10 @@ detailed description):
|
||||
- ACPI sounds
|
||||
- temperature sensors
|
||||
- Experimental: embedded controller register dump
|
||||
- Experimental: LCD brightness control
|
||||
- Experimental: volume control
|
||||
- LCD brightness control
|
||||
- Volume control
|
||||
- Experimental: fan speed, fan enable/disable
|
||||
- Experimental: WAN enable and disable
|
||||
|
||||
A compatibility table by model and feature is maintained on the web
|
||||
site, http://ibm-acpi.sf.net/. I appreciate any success or failure
|
||||
@ -52,40 +53,7 @@ Installation
|
||||
|
||||
If you are compiling this driver as included in the Linux kernel
|
||||
sources, simply enable the CONFIG_ACPI_IBM option (Power Management /
|
||||
ACPI / IBM ThinkPad Laptop Extras). The rest of this section describes
|
||||
how to install this driver when downloaded from the web site.
|
||||
|
||||
First, you need to get a kernel with ACPI support up and running.
|
||||
Please refer to http://acpi.sourceforge.net/ for help with this
|
||||
step. How successful you will be depends a lot on you ThinkPad model,
|
||||
the kernel you are using and any additional patches applied. The
|
||||
kernel provided with your distribution may not be good enough. I
|
||||
needed to compile a 2.6.7 kernel with the 20040715 ACPI patch to get
|
||||
ACPI working reliably on my ThinkPad X40. Old ThinkPad models may not
|
||||
be supported at all.
|
||||
|
||||
Assuming you have the basic ACPI support working (e.g. you can see the
|
||||
/proc/acpi directory), follow the following steps to install this
|
||||
driver:
|
||||
|
||||
- unpack the archive:
|
||||
|
||||
tar xzvf ibm-acpi-x.y.tar.gz; cd ibm-acpi-x.y
|
||||
|
||||
- compile the driver:
|
||||
|
||||
make
|
||||
|
||||
- install the module in your kernel modules directory:
|
||||
|
||||
make install
|
||||
|
||||
- load the module:
|
||||
|
||||
modprobe ibm_acpi
|
||||
|
||||
After loading the module, check the "dmesg" output for any error messages.
|
||||
|
||||
ACPI / IBM ThinkPad Laptop Extras).
|
||||
|
||||
Features
|
||||
--------
|
||||
@ -523,13 +491,8 @@ registers contain the current battery capacity, etc. If you experiment
|
||||
with this, do send me your results (including some complete dumps with
|
||||
a description of the conditions when they were taken.)
|
||||
|
||||
EXPERIMENTAL: LCD brightness control -- /proc/acpi/ibm/brightness
|
||||
-----------------------------------------------------------------
|
||||
|
||||
This feature is marked EXPERIMENTAL because the implementation
|
||||
directly accesses hardware registers and may not work as expected. USE
|
||||
WITH CAUTION! To use this feature, you need to supply the
|
||||
experimental=1 parameter when loading the module.
|
||||
LCD brightness control -- /proc/acpi/ibm/brightness
|
||||
---------------------------------------------------
|
||||
|
||||
This feature allows software control of the LCD brightness on ThinkPad
|
||||
models which don't have a hardware brightness slider. The available
|
||||
@ -542,13 +505,8 @@ commands are:
|
||||
The <level> number range is 0 to 7, although not all of them may be
|
||||
distinct. The current brightness level is shown in the file.
|
||||
|
||||
EXPERIMENTAL: Volume control -- /proc/acpi/ibm/volume
|
||||
-----------------------------------------------------
|
||||
|
||||
This feature is marked EXPERIMENTAL because the implementation
|
||||
directly accesses hardware registers and may not work as expected. USE
|
||||
WITH CAUTION! To use this feature, you need to supply the
|
||||
experimental=1 parameter when loading the module.
|
||||
Volume control -- /proc/acpi/ibm/volume
|
||||
---------------------------------------
|
||||
|
||||
This feature allows volume control on ThinkPad models which don't have
|
||||
a hardware volume knob. The available commands are:
|
||||
@ -611,6 +569,23 @@ with the following command:
|
||||
|
||||
echo 'level <level>' > /proc/acpi/ibm/thermal
|
||||
|
||||
EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan
|
||||
---------------------------------------
|
||||
|
||||
This feature is marked EXPERIMENTAL because the implementation
|
||||
directly accesses hardware registers and may not work as expected. USE
|
||||
WITH CAUTION! To use this feature, you need to supply the
|
||||
experimental=1 parameter when loading the module.
|
||||
|
||||
This feature shows the presence and current state of a WAN (Sierra
|
||||
Wireless EV-DO) device. If WAN is installed, the following commands can
|
||||
be used:
|
||||
|
||||
echo enable > /proc/acpi/ibm/wan
|
||||
echo disable > /proc/acpi/ibm/wan
|
||||
|
||||
It was tested on a Lenovo Thinkpad X60. It should probably work on other
|
||||
Thinkpad models which come with this module installed.
|
||||
|
||||
Multiple Commands, Module Parameters
|
||||
------------------------------------
|
||||
|
@ -1998,6 +1998,13 @@ M: rubini@ipvvis.unipv.it
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
MSI LAPTOP SUPPORT
|
||||
P: Lennart Poettering
|
||||
M: mzxreary@0pointer.de
|
||||
L: https://tango.0pointer.de/mailman/listinfo/s270-linux
|
||||
W: http://0pointer.de/lennart/tchibo.html
|
||||
S: Maintained
|
||||
|
||||
MTRR AND SIMILAR SUPPORT [i386]
|
||||
P: Richard Gooch
|
||||
M: rgooch@atnf.csiro.au
|
||||
|
@ -332,7 +332,7 @@ acpi_parse_ioapic(acpi_table_entry_header * header, const unsigned long end)
|
||||
/*
|
||||
* Parse Interrupt Source Override for the ACPI SCI
|
||||
*/
|
||||
static void acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
|
||||
static void acpi_sci_ioapic_setup(u32 bus_irq, u32 gsi, u16 polarity, u16 trigger)
|
||||
{
|
||||
if (trigger == 0) /* compatible SCI trigger is level */
|
||||
trigger = 3;
|
||||
@ -352,13 +352,13 @@ static void acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
|
||||
* If GSI is < 16, this will update its flags,
|
||||
* else it will create a new mp_irqs[] entry.
|
||||
*/
|
||||
mp_override_legacy_irq(gsi, polarity, trigger, gsi);
|
||||
mp_override_legacy_irq(bus_irq, polarity, trigger, gsi);
|
||||
|
||||
/*
|
||||
* stash over-ride to indicate we've been here
|
||||
* and for later update of acpi_fadt
|
||||
*/
|
||||
acpi_sci_override_gsi = gsi;
|
||||
acpi_sci_override_gsi = bus_irq;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -376,7 +376,7 @@ acpi_parse_int_src_ovr(acpi_table_entry_header * header,
|
||||
acpi_table_print_madt_entry(header);
|
||||
|
||||
if (intsrc->bus_irq == acpi_fadt.sci_int) {
|
||||
acpi_sci_ioapic_setup(intsrc->global_irq,
|
||||
acpi_sci_ioapic_setup(intsrc->bus_irq, intsrc->global_irq,
|
||||
intsrc->flags.polarity,
|
||||
intsrc->flags.trigger);
|
||||
return 0;
|
||||
@ -879,7 +879,7 @@ static int __init acpi_parse_madt_ioapic_entries(void)
|
||||
* pretend we got one so we can set the SCI flags.
|
||||
*/
|
||||
if (!acpi_sci_override_gsi)
|
||||
acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0);
|
||||
acpi_sci_ioapic_setup(acpi_fadt.sci_int, acpi_fadt.sci_int, 0, 0);
|
||||
|
||||
/* Fill in identity legacy mapings where no override */
|
||||
mp_config_acpi_legacy_irqs();
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/cpu.h>
|
||||
|
||||
#include <acpi/processor.h>
|
||||
#include <asm/acpi.h>
|
||||
@ -41,5 +42,124 @@ void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
|
||||
flags->bm_check = 1;
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_processor_power_init_bm_check);
|
||||
|
||||
/* The code below handles cstate entry with monitor-mwait pair on Intel*/
|
||||
|
||||
struct cstate_entry_s {
|
||||
struct {
|
||||
unsigned int eax;
|
||||
unsigned int ecx;
|
||||
} states[ACPI_PROCESSOR_MAX_POWER];
|
||||
};
|
||||
static struct cstate_entry_s *cpu_cstate_entry; /* per CPU ptr */
|
||||
|
||||
static short mwait_supported[ACPI_PROCESSOR_MAX_POWER];
|
||||
|
||||
#define MWAIT_SUBSTATE_MASK (0xf)
|
||||
#define MWAIT_SUBSTATE_SIZE (4)
|
||||
|
||||
#define CPUID_MWAIT_LEAF (5)
|
||||
#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
|
||||
#define CPUID5_ECX_INTERRUPT_BREAK (0x2)
|
||||
|
||||
#define MWAIT_ECX_INTERRUPT_BREAK (0x1)
|
||||
|
||||
#define NATIVE_CSTATE_BEYOND_HALT (2)
|
||||
|
||||
int acpi_processor_ffh_cstate_probe(unsigned int cpu,
|
||||
struct acpi_processor_cx *cx, struct acpi_power_register *reg)
|
||||
{
|
||||
struct cstate_entry_s *percpu_entry;
|
||||
struct cpuinfo_x86 *c = cpu_data + cpu;
|
||||
|
||||
cpumask_t saved_mask;
|
||||
int retval;
|
||||
unsigned int eax, ebx, ecx, edx;
|
||||
unsigned int edx_part;
|
||||
unsigned int cstate_type; /* C-state type and not ACPI C-state type */
|
||||
unsigned int num_cstate_subtype;
|
||||
|
||||
if (!cpu_cstate_entry || c->cpuid_level < CPUID_MWAIT_LEAF )
|
||||
return -1;
|
||||
|
||||
if (reg->bit_offset != NATIVE_CSTATE_BEYOND_HALT)
|
||||
return -1;
|
||||
|
||||
percpu_entry = per_cpu_ptr(cpu_cstate_entry, cpu);
|
||||
percpu_entry->states[cx->index].eax = 0;
|
||||
percpu_entry->states[cx->index].ecx = 0;
|
||||
|
||||
/* Make sure we are running on right CPU */
|
||||
saved_mask = current->cpus_allowed;
|
||||
retval = set_cpus_allowed(current, cpumask_of_cpu(cpu));
|
||||
if (retval)
|
||||
return -1;
|
||||
|
||||
cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
/* Check whether this particular cx_type (in CST) is supported or not */
|
||||
cstate_type = (cx->address >> MWAIT_SUBSTATE_SIZE) + 1;
|
||||
edx_part = edx >> (cstate_type * MWAIT_SUBSTATE_SIZE);
|
||||
num_cstate_subtype = edx_part & MWAIT_SUBSTATE_MASK;
|
||||
|
||||
retval = 0;
|
||||
if (num_cstate_subtype < (cx->address & MWAIT_SUBSTATE_MASK)) {
|
||||
retval = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* mwait ecx extensions INTERRUPT_BREAK should be supported for C2/C3 */
|
||||
if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) ||
|
||||
!(ecx & CPUID5_ECX_INTERRUPT_BREAK)) {
|
||||
retval = -1;
|
||||
goto out;
|
||||
}
|
||||
percpu_entry->states[cx->index].ecx = MWAIT_ECX_INTERRUPT_BREAK;
|
||||
|
||||
/* Use the hint in CST */
|
||||
percpu_entry->states[cx->index].eax = cx->address;
|
||||
|
||||
if (!mwait_supported[cstate_type]) {
|
||||
mwait_supported[cstate_type] = 1;
|
||||
printk(KERN_DEBUG "Monitor-Mwait will be used to enter C-%d "
|
||||
"state\n", cx->type);
|
||||
}
|
||||
|
||||
out:
|
||||
set_cpus_allowed(current, saved_mask);
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_probe);
|
||||
|
||||
void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx)
|
||||
{
|
||||
unsigned int cpu = smp_processor_id();
|
||||
struct cstate_entry_s *percpu_entry;
|
||||
|
||||
percpu_entry = per_cpu_ptr(cpu_cstate_entry, cpu);
|
||||
mwait_idle_with_hints(percpu_entry->states[cx->index].eax,
|
||||
percpu_entry->states[cx->index].ecx);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_enter);
|
||||
|
||||
static int __init ffh_cstate_init(void)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &boot_cpu_data;
|
||||
if (c->x86_vendor != X86_VENDOR_INTEL)
|
||||
return -1;
|
||||
|
||||
cpu_cstate_entry = alloc_percpu(struct cstate_entry_s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit ffh_cstate_exit(void)
|
||||
{
|
||||
if (cpu_cstate_entry) {
|
||||
free_percpu(cpu_cstate_entry);
|
||||
cpu_cstate_entry = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
arch_initcall(ffh_cstate_init);
|
||||
__exitcall(ffh_cstate_exit);
|
||||
|
@ -236,18 +236,26 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait);
|
||||
* We execute MONITOR against need_resched and enter optimized wait state
|
||||
* through MWAIT. Whenever someone changes need_resched, we would be woken
|
||||
* up from MWAIT (without an IPI).
|
||||
*
|
||||
* New with Core Duo processors, MWAIT can take some hints based on CPU
|
||||
* capability.
|
||||
*/
|
||||
void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
|
||||
{
|
||||
if (!need_resched()) {
|
||||
__monitor((void *)¤t_thread_info()->flags, 0, 0);
|
||||
smp_mb();
|
||||
if (!need_resched())
|
||||
__mwait(eax, ecx);
|
||||
}
|
||||
}
|
||||
|
||||
/* Default MONITOR/MWAIT with no hints, used for default C1 state */
|
||||
static void mwait_idle(void)
|
||||
{
|
||||
local_irq_enable();
|
||||
|
||||
while (!need_resched()) {
|
||||
__monitor((void *)¤t_thread_info()->flags, 0, 0);
|
||||
smp_mb();
|
||||
if (need_resched())
|
||||
break;
|
||||
__mwait(0, 0);
|
||||
}
|
||||
while (!need_resched())
|
||||
mwait_idle_with_hints(0, 0);
|
||||
}
|
||||
|
||||
void __devinit select_idle_routine(const struct cpuinfo_x86 *c)
|
||||
|
@ -238,18 +238,26 @@ void cpu_idle (void)
|
||||
* We execute MONITOR against need_resched and enter optimized wait state
|
||||
* through MWAIT. Whenever someone changes need_resched, we would be woken
|
||||
* up from MWAIT (without an IPI).
|
||||
*
|
||||
* New with Core Duo processors, MWAIT can take some hints based on CPU
|
||||
* capability.
|
||||
*/
|
||||
void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
|
||||
{
|
||||
if (!need_resched()) {
|
||||
__monitor((void *)¤t_thread_info()->flags, 0, 0);
|
||||
smp_mb();
|
||||
if (!need_resched())
|
||||
__mwait(eax, ecx);
|
||||
}
|
||||
}
|
||||
|
||||
/* Default MONITOR/MWAIT with no hints, used for default C1 state */
|
||||
static void mwait_idle(void)
|
||||
{
|
||||
local_irq_enable();
|
||||
|
||||
while (!need_resched()) {
|
||||
__monitor((void *)¤t_thread_info()->flags, 0, 0);
|
||||
smp_mb();
|
||||
if (need_resched())
|
||||
break;
|
||||
__mwait(0, 0);
|
||||
}
|
||||
while (!need_resched())
|
||||
mwait_idle_with_hints(0,0);
|
||||
}
|
||||
|
||||
void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
|
||||
|
@ -138,6 +138,7 @@ struct asus_hotk {
|
||||
S2x, //S200 (J1 reported), Victor MP-XP7210
|
||||
W1N, //W1000N
|
||||
W5A, //W5A
|
||||
W3V, //W3030V
|
||||
xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N
|
||||
//(Centrino)
|
||||
END_MODEL
|
||||
@ -376,6 +377,17 @@ static struct model_data model_conf[END_MODEL] = {
|
||||
.display_get = "\\ADVG"},
|
||||
|
||||
{
|
||||
.name = "W3V",
|
||||
.mt_mled = "MLED",
|
||||
.mt_wled = "WLED",
|
||||
.mt_lcd_switch = xxN_PREFIX "_Q10",
|
||||
.lcd_status = "\\BKLT",
|
||||
.brightness_set = "SPLV",
|
||||
.brightness_get = "GPLV",
|
||||
.display_set = "SDSP",
|
||||
.display_get = "\\INFB"},
|
||||
|
||||
{
|
||||
.name = "xxN",
|
||||
.mt_mled = "MLED",
|
||||
/* WLED present, but not controlled by ACPI */
|
||||
@ -555,11 +567,11 @@ static int
|
||||
write_led(const char __user * buffer, unsigned long count,
|
||||
char *ledname, int ledmask, int invert)
|
||||
{
|
||||
int value;
|
||||
int rv, value;
|
||||
int led_out = 0;
|
||||
|
||||
count = parse_arg(buffer, count, &value);
|
||||
if (count > 0)
|
||||
rv = parse_arg(buffer, count, &value);
|
||||
if (rv > 0)
|
||||
led_out = value ? 1 : 0;
|
||||
|
||||
hotk->status =
|
||||
@ -572,7 +584,7 @@ write_led(const char __user * buffer, unsigned long count,
|
||||
printk(KERN_WARNING "Asus ACPI: LED (%s) write failed\n",
|
||||
ledname);
|
||||
|
||||
return count;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -607,20 +619,18 @@ static int
|
||||
proc_write_ledd(struct file *file, const char __user * buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
int value;
|
||||
int rv, value;
|
||||
|
||||
count = parse_arg(buffer, count, &value);
|
||||
if (count > 0) {
|
||||
rv = parse_arg(buffer, count, &value);
|
||||
if (rv > 0) {
|
||||
if (!write_acpi_int
|
||||
(hotk->handle, hotk->methods->mt_ledd, value, NULL))
|
||||
printk(KERN_WARNING
|
||||
"Asus ACPI: LED display write failed\n");
|
||||
else
|
||||
hotk->ledd_status = (u32) value;
|
||||
} else if (count < 0)
|
||||
printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
|
||||
|
||||
return count;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -761,12 +771,12 @@ static int
|
||||
proc_write_lcd(struct file *file, const char __user * buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
int value;
|
||||
int rv, value;
|
||||
|
||||
count = parse_arg(buffer, count, &value);
|
||||
if (count > 0)
|
||||
rv = parse_arg(buffer, count, &value);
|
||||
if (rv > 0)
|
||||
set_lcd_state(value);
|
||||
return count;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int read_brightness(void)
|
||||
@ -830,18 +840,15 @@ static int
|
||||
proc_write_brn(struct file *file, const char __user * buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
int value;
|
||||
int rv, value;
|
||||
|
||||
count = parse_arg(buffer, count, &value);
|
||||
if (count > 0) {
|
||||
rv = parse_arg(buffer, count, &value);
|
||||
if (rv > 0) {
|
||||
value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
|
||||
/* 0 <= value <= 15 */
|
||||
set_brightness(value);
|
||||
} else if (count < 0) {
|
||||
printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
|
||||
}
|
||||
|
||||
return count;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void set_display(int value)
|
||||
@ -880,15 +887,12 @@ static int
|
||||
proc_write_disp(struct file *file, const char __user * buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
int value;
|
||||
int rv, value;
|
||||
|
||||
count = parse_arg(buffer, count, &value);
|
||||
if (count > 0)
|
||||
rv = parse_arg(buffer, count, &value);
|
||||
if (rv > 0)
|
||||
set_display(value);
|
||||
else if (count < 0)
|
||||
printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
|
||||
|
||||
return count;
|
||||
return rv;
|
||||
}
|
||||
|
||||
typedef int (proc_readfunc) (char *page, char **start, off_t off, int count,
|
||||
@ -1097,6 +1101,8 @@ static int asus_model_match(char *model)
|
||||
return A4G;
|
||||
else if (strncmp(model, "W1N", 3) == 0)
|
||||
return W1N;
|
||||
else if (strncmp(model, "W3V", 3) == 0)
|
||||
return W3V;
|
||||
else if (strncmp(model, "W5A", 3) == 0)
|
||||
return W5A;
|
||||
else
|
||||
@ -1200,9 +1206,10 @@ static int asus_hotk_get_info(void)
|
||||
hotk->methods->mt_wled = NULL;
|
||||
/* L5D's WLED is not controlled by ACPI */
|
||||
else if (strncmp(string, "M2N", 3) == 0 ||
|
||||
strncmp(string, "W3V", 3) == 0 ||
|
||||
strncmp(string, "S1N", 3) == 0)
|
||||
hotk->methods->mt_wled = "WLED";
|
||||
/* M2N and S1N have a usable WLED */
|
||||
/* M2N, S1N and W3V have a usable WLED */
|
||||
else if (asus_info) {
|
||||
if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
|
||||
hotk->methods->mled_status = NULL;
|
||||
|
@ -64,6 +64,7 @@ extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
|
||||
|
||||
static int acpi_battery_add(struct acpi_device *device);
|
||||
static int acpi_battery_remove(struct acpi_device *device, int type);
|
||||
static int acpi_battery_resume(struct acpi_device *device, int status);
|
||||
|
||||
static struct acpi_driver acpi_battery_driver = {
|
||||
.name = ACPI_BATTERY_DRIVER_NAME,
|
||||
@ -71,6 +72,7 @@ static struct acpi_driver acpi_battery_driver = {
|
||||
.ids = ACPI_BATTERY_HID,
|
||||
.ops = {
|
||||
.add = acpi_battery_add,
|
||||
.resume = acpi_battery_resume,
|
||||
.remove = acpi_battery_remove,
|
||||
},
|
||||
};
|
||||
@ -753,6 +755,18 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* this is needed to learn about changes made in suspended state */
|
||||
static int acpi_battery_resume(struct acpi_device *device, int state)
|
||||
{
|
||||
struct acpi_battery *battery;
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
battery = device->driver_data;
|
||||
return acpi_battery_check(battery);
|
||||
}
|
||||
|
||||
static int __init acpi_battery_init(void)
|
||||
{
|
||||
int result;
|
||||
|
1108
drivers/acpi/ec.c
1108
drivers/acpi/ec.c
File diff suppressed because it is too large
Load Diff
@ -342,20 +342,8 @@ static u32 acpi_ev_global_lock_handler(void *context)
|
||||
if (acquired) {
|
||||
|
||||
/* Got the lock, now wake all threads waiting for it */
|
||||
|
||||
acpi_gbl_global_lock_acquired = TRUE;
|
||||
|
||||
/* Run the Global Lock thread which will signal all waiting threads */
|
||||
|
||||
status =
|
||||
acpi_os_execute(OSL_GLOBAL_LOCK_HANDLER,
|
||||
acpi_ev_global_lock_thread, context);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"Could not queue Global Lock thread"));
|
||||
|
||||
return (ACPI_INTERRUPT_NOT_HANDLED);
|
||||
}
|
||||
acpi_ev_global_lock_thread(context);
|
||||
}
|
||||
|
||||
return (ACPI_INTERRUPT_HANDLED);
|
||||
|
@ -225,13 +225,12 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
|
||||
if (!
|
||||
(ACPI_STRNCMP
|
||||
(object_hID.value, PCI_ROOT_HID_STRING,
|
||||
sizeof(PCI_ROOT_HID_STRING))
|
||||
||
|
||||
!(ACPI_STRNCMP
|
||||
(object_hID.value,
|
||||
PCI_EXPRESS_ROOT_HID_STRING,
|
||||
sizeof(PCI_EXPRESS_ROOT_HID_STRING)))))
|
||||
{
|
||||
sizeof(PCI_ROOT_HID_STRING)))
|
||||
||
|
||||
!(ACPI_STRNCMP
|
||||
(object_hID.value,
|
||||
PCI_EXPRESS_ROOT_HID_STRING,
|
||||
sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) {
|
||||
|
||||
/* Install a handler for this PCI root bridge */
|
||||
|
||||
|
@ -1702,13 +1702,11 @@ static struct ibm_struct ibms[] = {
|
||||
.name = "brightness",
|
||||
.read = brightness_read,
|
||||
.write = brightness_write,
|
||||
.experimental = 1,
|
||||
},
|
||||
{
|
||||
.name = "volume",
|
||||
.read = volume_read,
|
||||
.write = volume_write,
|
||||
.experimental = 1,
|
||||
},
|
||||
{
|
||||
.name = "fan",
|
||||
|
@ -48,6 +48,12 @@ ACPI_MODULE_NAME("acpi_motherboard")
|
||||
* the io ports if they really know they can use it, while
|
||||
* still preventing hotplug PCI devices from using it.
|
||||
*/
|
||||
|
||||
/*
|
||||
* When CONFIG_PNP is enabled, pnp/system.c binds to PNP0C01
|
||||
* and PNP0C02, redundant with acpi_reserve_io_ranges().
|
||||
* But acpi_reserve_io_ranges() is necessary for !CONFIG_PNP.
|
||||
*/
|
||||
static acpi_status acpi_reserve_io_ranges(struct acpi_resource *res, void *data)
|
||||
{
|
||||
struct resource *requested_res = NULL;
|
||||
|
@ -73,6 +73,7 @@ static unsigned int acpi_irq_irq;
|
||||
static acpi_osd_handler acpi_irq_handler;
|
||||
static void *acpi_irq_context;
|
||||
static struct workqueue_struct *kacpid_wq;
|
||||
static struct workqueue_struct *kacpi_notify_wq;
|
||||
|
||||
acpi_status acpi_os_initialize(void)
|
||||
{
|
||||
@ -91,8 +92,9 @@ acpi_status acpi_os_initialize1(void)
|
||||
return AE_NULL_ENTRY;
|
||||
}
|
||||
kacpid_wq = create_singlethread_workqueue("kacpid");
|
||||
kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify");
|
||||
BUG_ON(!kacpid_wq);
|
||||
|
||||
BUG_ON(!kacpi_notify_wq);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
@ -104,6 +106,7 @@ acpi_status acpi_os_terminate(void)
|
||||
}
|
||||
|
||||
destroy_workqueue(kacpid_wq);
|
||||
destroy_workqueue(kacpi_notify_wq);
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
@ -566,10 +569,7 @@ void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */
|
||||
|
||||
static void acpi_os_execute_deferred(void *context)
|
||||
{
|
||||
struct acpi_os_dpc *dpc = NULL;
|
||||
|
||||
|
||||
dpc = (struct acpi_os_dpc *)context;
|
||||
struct acpi_os_dpc *dpc = (struct acpi_os_dpc *)context;
|
||||
if (!dpc) {
|
||||
printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
|
||||
return;
|
||||
@ -604,14 +604,12 @@ acpi_status acpi_os_execute(acpi_execute_type type,
|
||||
struct acpi_os_dpc *dpc;
|
||||
struct work_struct *task;
|
||||
|
||||
ACPI_FUNCTION_TRACE("os_queue_for_execution");
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Scheduling function [%p(%p)] for deferred execution.\n",
|
||||
function, context));
|
||||
|
||||
if (!function)
|
||||
return_ACPI_STATUS(AE_BAD_PARAMETER);
|
||||
return AE_BAD_PARAMETER;
|
||||
|
||||
/*
|
||||
* Allocate/initialize DPC structure. Note that this memory will be
|
||||
@ -624,26 +622,20 @@ acpi_status acpi_os_execute(acpi_execute_type type,
|
||||
* from the same memory.
|
||||
*/
|
||||
|
||||
dpc =
|
||||
kmalloc(sizeof(struct acpi_os_dpc) + sizeof(struct work_struct),
|
||||
GFP_ATOMIC);
|
||||
dpc = kmalloc(sizeof(struct acpi_os_dpc) +
|
||||
sizeof(struct work_struct), GFP_ATOMIC);
|
||||
if (!dpc)
|
||||
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||
|
||||
return AE_NO_MEMORY;
|
||||
dpc->function = function;
|
||||
dpc->context = context;
|
||||
|
||||
task = (void *)(dpc + 1);
|
||||
INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc);
|
||||
|
||||
if (!queue_work(kacpid_wq, task)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Call to queue_work() failed.\n"));
|
||||
kfree(dpc);
|
||||
if (!queue_work((type == OSL_NOTIFY_HANDLER)?
|
||||
kacpi_notify_wq : kacpid_wq, task)) {
|
||||
status = AE_ERROR;
|
||||
kfree(dpc);
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
return status;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_os_execute);
|
||||
|
@ -307,7 +307,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
|
||||
if (!link || !irq)
|
||||
return -EINVAL;
|
||||
|
||||
resource = kmalloc(sizeof(*resource) + 1, GFP_ATOMIC);
|
||||
resource = kmalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL);
|
||||
if (!resource)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -216,10 +216,8 @@ static int acpi_power_off_device(acpi_handle handle)
|
||||
{
|
||||
int result = 0;
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_device *device = NULL;
|
||||
struct acpi_power_resource *resource = NULL;
|
||||
|
||||
|
||||
result = acpi_power_get_context(handle, &resource);
|
||||
if (result)
|
||||
return result;
|
||||
@ -230,13 +228,13 @@ static int acpi_power_off_device(acpi_handle handle)
|
||||
if (resource->references) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Resource [%s] is still in use, dereferencing\n",
|
||||
device->pnp.bus_id));
|
||||
resource->device->pnp.bus_id));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (resource->state == ACPI_POWER_RESOURCE_STATE_OFF) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already off\n",
|
||||
device->pnp.bus_id));
|
||||
resource->device->pnp.bus_id));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -251,8 +249,7 @@ static int acpi_power_off_device(acpi_handle handle)
|
||||
return -ENOEXEC;
|
||||
|
||||
/* Update the power resource's _device_ power state */
|
||||
device = resource->device;
|
||||
device->power.state = ACPI_STATE_D3;
|
||||
resource->device->power.state = ACPI_STATE_D3;
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned off\n",
|
||||
resource->name));
|
||||
|
@ -519,7 +519,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
|
||||
|
||||
static void *processor_device_array[NR_CPUS];
|
||||
|
||||
static int acpi_processor_start(struct acpi_device *device)
|
||||
static int __cpuinit acpi_processor_start(struct acpi_device *device)
|
||||
{
|
||||
int result = 0;
|
||||
acpi_status status = AE_OK;
|
||||
|
@ -219,6 +219,23 @@ static void acpi_safe_halt(void)
|
||||
|
||||
static atomic_t c3_cpu_count;
|
||||
|
||||
/* Common C-state entry for C2, C3, .. */
|
||||
static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
|
||||
{
|
||||
if (cstate->space_id == ACPI_CSTATE_FFH) {
|
||||
/* Call into architectural FFH based C-state */
|
||||
acpi_processor_ffh_cstate_enter(cstate);
|
||||
} else {
|
||||
int unused;
|
||||
/* IO port based C-state */
|
||||
inb(cstate->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_fadt.xpm_tmr_blk.address);
|
||||
}
|
||||
}
|
||||
|
||||
static void acpi_processor_idle(void)
|
||||
{
|
||||
struct acpi_processor *pr = NULL;
|
||||
@ -361,11 +378,7 @@ static void acpi_processor_idle(void)
|
||||
/* Get start time (ticks) */
|
||||
t1 = inl(acpi_fadt.xpm_tmr_blk.address);
|
||||
/* Invoke C2 */
|
||||
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. */
|
||||
t2 = inl(acpi_fadt.xpm_tmr_blk.address);
|
||||
acpi_cstate_enter(cx);
|
||||
/* Get end time (ticks) */
|
||||
t2 = inl(acpi_fadt.xpm_tmr_blk.address);
|
||||
|
||||
@ -401,9 +414,7 @@ static void acpi_processor_idle(void)
|
||||
/* Get start time (ticks) */
|
||||
t1 = inl(acpi_fadt.xpm_tmr_blk.address);
|
||||
/* Invoke C3 */
|
||||
inb(cx->address);
|
||||
/* Dummy wait op (see above) */
|
||||
t2 = inl(acpi_fadt.xpm_tmr_blk.address);
|
||||
acpi_cstate_enter(cx);
|
||||
/* Get end time (ticks) */
|
||||
t2 = inl(acpi_fadt.xpm_tmr_blk.address);
|
||||
if (pr->flags.bm_check) {
|
||||
@ -628,20 +639,16 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_processor_get_power_info_default_c1(struct acpi_processor *pr)
|
||||
static int acpi_processor_get_power_info_default(struct acpi_processor *pr)
|
||||
{
|
||||
|
||||
/* Zero initialize all the C-states info. */
|
||||
memset(pr->power.states, 0, sizeof(pr->power.states));
|
||||
|
||||
/* set the first C-State to C1 */
|
||||
pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
|
||||
|
||||
/* the C0 state only exists as a filler in our array,
|
||||
* and all processors need to support C1 */
|
||||
if (!pr->power.states[ACPI_STATE_C1].valid) {
|
||||
/* set the first C-State to C1 */
|
||||
/* all processors need to support C1 */
|
||||
pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
|
||||
pr->power.states[ACPI_STATE_C1].valid = 1;
|
||||
}
|
||||
/* the C0 state only exists as a filler in our array */
|
||||
pr->power.states[ACPI_STATE_C0].valid = 1;
|
||||
pr->power.states[ACPI_STATE_C1].valid = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -658,12 +665,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
|
||||
if (nocst)
|
||||
return -ENODEV;
|
||||
|
||||
current_count = 1;
|
||||
|
||||
/* Zero initialize C2 onwards and prepare for fresh CST lookup */
|
||||
for (i = 2; i < ACPI_PROCESSOR_MAX_POWER; i++)
|
||||
memset(&(pr->power.states[i]), 0,
|
||||
sizeof(struct acpi_processor_cx));
|
||||
current_count = 0;
|
||||
|
||||
status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
@ -718,22 +720,39 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
|
||||
(reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE))
|
||||
continue;
|
||||
|
||||
cx.address = (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) ?
|
||||
0 : reg->address;
|
||||
|
||||
/* There should be an easy way to extract an integer... */
|
||||
obj = (union acpi_object *)&(element->package.elements[1]);
|
||||
if (obj->type != ACPI_TYPE_INTEGER)
|
||||
continue;
|
||||
|
||||
cx.type = obj->integer.value;
|
||||
/*
|
||||
* Some buggy BIOSes won't list C1 in _CST -
|
||||
* Let acpi_processor_get_power_info_default() handle them later
|
||||
*/
|
||||
if (i == 1 && cx.type != ACPI_STATE_C1)
|
||||
current_count++;
|
||||
|
||||
if ((cx.type != ACPI_STATE_C1) &&
|
||||
(reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO))
|
||||
continue;
|
||||
cx.address = reg->address;
|
||||
cx.index = current_count + 1;
|
||||
|
||||
if ((cx.type < ACPI_STATE_C2) || (cx.type > ACPI_STATE_C3))
|
||||
continue;
|
||||
cx.space_id = ACPI_CSTATE_SYSTEMIO;
|
||||
if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
|
||||
if (acpi_processor_ffh_cstate_probe
|
||||
(pr->id, &cx, reg) == 0) {
|
||||
cx.space_id = ACPI_CSTATE_FFH;
|
||||
} else if (cx.type != ACPI_STATE_C1) {
|
||||
/*
|
||||
* C1 is a special case where FIXED_HARDWARE
|
||||
* can be handled in non-MWAIT way as well.
|
||||
* In that case, save this _CST entry info.
|
||||
* That is, we retain space_id of SYSTEM_IO for
|
||||
* halt based C1.
|
||||
* Otherwise, ignore this info and continue.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
obj = (union acpi_object *)&(element->package.elements[2]);
|
||||
if (obj->type != ACPI_TYPE_INTEGER)
|
||||
@ -938,12 +957,18 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr)
|
||||
/* NOTE: the idle thread may not be running while calling
|
||||
* this function */
|
||||
|
||||
/* Adding C1 state */
|
||||
acpi_processor_get_power_info_default_c1(pr);
|
||||
/* Zero initialize all the C-states info. */
|
||||
memset(pr->power.states, 0, sizeof(pr->power.states));
|
||||
|
||||
result = acpi_processor_get_power_info_cst(pr);
|
||||
if (result == -ENODEV)
|
||||
acpi_processor_get_power_info_fadt(pr);
|
||||
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
acpi_processor_get_power_info_default(pr);
|
||||
|
||||
pr->power.count = acpi_processor_power_verify(pr);
|
||||
|
||||
/*
|
||||
@ -1105,7 +1130,7 @@ static struct notifier_block acpi_processor_latency_notifier = {
|
||||
.notifier_call = acpi_processor_latency_notify,
|
||||
};
|
||||
|
||||
int acpi_processor_power_init(struct acpi_processor *pr,
|
||||
int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
|
||||
struct acpi_device *device)
|
||||
{
|
||||
acpi_status status = 0;
|
||||
|
@ -98,11 +98,11 @@ static int update_info_mode = UPDATE_INFO_MODE;
|
||||
static int update_time = UPDATE_TIME;
|
||||
static int update_time2 = UPDATE_TIME2;
|
||||
|
||||
module_param(capacity_mode, int, CAPACITY_UNIT);
|
||||
module_param(update_mode, int, UPDATE_MODE);
|
||||
module_param(update_info_mode, int, UPDATE_INFO_MODE);
|
||||
module_param(update_time, int, UPDATE_TIME);
|
||||
module_param(update_time2, int, UPDATE_TIME2);
|
||||
module_param(capacity_mode, int, 0);
|
||||
module_param(update_mode, int, 0);
|
||||
module_param(update_info_mode, int, 0);
|
||||
module_param(update_time, int, 0);
|
||||
module_param(update_time2, int, 0);
|
||||
|
||||
static int acpi_sbs_add(struct acpi_device *device);
|
||||
static int acpi_sbs_remove(struct acpi_device *device, int type);
|
||||
@ -1685,10 +1685,16 @@ static int acpi_sbs_add(struct acpi_device *device)
|
||||
|
||||
int acpi_sbs_remove(struct acpi_device *device, int type)
|
||||
{
|
||||
struct acpi_sbs *sbs = (struct acpi_sbs *)acpi_driver_data(device);
|
||||
struct acpi_sbs *sbs = NULL;
|
||||
int id;
|
||||
|
||||
if (!device || !sbs) {
|
||||
if (!device) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sbs = (struct acpi_sbs *)acpi_driver_data(device);
|
||||
|
||||
if (!sbs) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -324,7 +324,7 @@ acpi_tb_get_this_table(struct acpi_pointer *address,
|
||||
|
||||
if (header->length < sizeof(struct acpi_table_header)) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Table length (%X) is smaller than minimum (%X)",
|
||||
"Table length (%X) is smaller than minimum (%zX)",
|
||||
header->length, sizeof(struct acpi_table_header)));
|
||||
|
||||
return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
|
||||
|
@ -187,7 +187,7 @@ acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr)
|
||||
|
||||
if (table_ptr->length < sizeof(struct acpi_table_header)) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"RSDT/XSDT length (%X) is smaller than minimum (%X)",
|
||||
"RSDT/XSDT length (%X) is smaller than minimum (%zX)",
|
||||
table_ptr->length,
|
||||
sizeof(struct acpi_table_header)));
|
||||
|
||||
|
@ -57,4 +57,23 @@ config TIFM_7XX1
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called tifm_7xx1.
|
||||
|
||||
config MSI_LAPTOP
|
||||
tristate "MSI Laptop Extras"
|
||||
depends on X86
|
||||
depends on ACPI_EC
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
---help---
|
||||
This is a driver for laptops built by MSI (MICRO-STAR
|
||||
INTERNATIONAL):
|
||||
|
||||
MSI MegaBook S270 (MS-1013)
|
||||
Cytron/TCM/Medion/Tchibo MD96100/SAM2000
|
||||
|
||||
It adds support for Bluetooth, WLAN and LCD brightness control.
|
||||
|
||||
More information about this driver is available at
|
||||
<http://0pointer.de/lennart/tchibo.html>.
|
||||
|
||||
If you have an MSI S270 laptop, say Y or M here.
|
||||
|
||||
endmenu
|
||||
|
@ -5,6 +5,7 @@ obj- := misc.o # Dummy rule to force built-in.o to be made
|
||||
|
||||
obj-$(CONFIG_IBM_ASM) += ibmasm/
|
||||
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
|
||||
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
|
||||
obj-$(CONFIG_LKDTM) += lkdtm.o
|
||||
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
|
||||
obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
|
||||
|
395
drivers/misc/msi-laptop.c
Normal file
395
drivers/misc/msi-laptop.c
Normal file
@ -0,0 +1,395 @@
|
||||
/*-*-linux-c-*-*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) de>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* msi-laptop.c - MSI S270 laptop support. This laptop is sold under
|
||||
* various brands, including "Cytron/TCM/Medion/Tchibo MD96100".
|
||||
*
|
||||
* This driver exports a few files in /sys/devices/platform/msi-laptop-pf/:
|
||||
*
|
||||
* lcd_level - Screen brightness: contains a single integer in the
|
||||
* range 0..8. (rw)
|
||||
*
|
||||
* auto_brightness - Enable automatic brightness control: contains
|
||||
* either 0 or 1. If set to 1 the hardware adjusts the screen
|
||||
* brightness automatically when the power cord is
|
||||
* plugged/unplugged. (rw)
|
||||
*
|
||||
* wlan - WLAN subsystem enabled: contains either 0 or 1. (ro)
|
||||
*
|
||||
* bluetooth - Bluetooth subsystem enabled: contains either 0 or 1
|
||||
* Please note that this file is constantly 0 if no Bluetooth
|
||||
* hardware is available. (ro)
|
||||
*
|
||||
* In addition to these platform device attributes the driver
|
||||
* registers itself in the Linux backlight control subsystem and is
|
||||
* available to userspace under /sys/class/backlight/msi-laptop-bl/.
|
||||
*
|
||||
* This driver might work on other laptops produced by MSI. If you
|
||||
* want to try it you can pass force=1 as argument to the module which
|
||||
* will force it to load even when the DMI data doesn't identify the
|
||||
* laptop as MSI S270. YMMV.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/autoconf.h>
|
||||
|
||||
#define MSI_DRIVER_VERSION "0.5"
|
||||
|
||||
#define MSI_LCD_LEVEL_MAX 9
|
||||
|
||||
#define MSI_EC_COMMAND_WIRELESS 0x10
|
||||
#define MSI_EC_COMMAND_LCD_LEVEL 0x11
|
||||
|
||||
static int force;
|
||||
module_param(force, bool, 0);
|
||||
MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
|
||||
|
||||
static int auto_brightness;
|
||||
module_param(auto_brightness, int, 0);
|
||||
MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)");
|
||||
|
||||
/* Hardware access */
|
||||
|
||||
static int set_lcd_level(int level)
|
||||
{
|
||||
u8 buf[2];
|
||||
|
||||
if (level < 0 || level >= MSI_LCD_LEVEL_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
buf[0] = 0x80;
|
||||
buf[1] = (u8) (level*31);
|
||||
|
||||
return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0);
|
||||
}
|
||||
|
||||
static int get_lcd_level(void)
|
||||
{
|
||||
u8 wdata = 0, rdata;
|
||||
int result;
|
||||
|
||||
result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
return (int) rdata / 31;
|
||||
}
|
||||
|
||||
static int get_auto_brightness(void)
|
||||
{
|
||||
u8 wdata = 4, rdata;
|
||||
int result;
|
||||
|
||||
result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
return !!(rdata & 8);
|
||||
}
|
||||
|
||||
static int set_auto_brightness(int enable)
|
||||
{
|
||||
u8 wdata[2], rdata;
|
||||
int result;
|
||||
|
||||
wdata[0] = 4;
|
||||
|
||||
result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 1);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
wdata[0] = 0x84;
|
||||
wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0);
|
||||
|
||||
return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0);
|
||||
}
|
||||
|
||||
static int get_wireless_state(int *wlan, int *bluetooth)
|
||||
{
|
||||
u8 wdata = 0, rdata;
|
||||
int result;
|
||||
|
||||
result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1);
|
||||
if (result < 0)
|
||||
return -1;
|
||||
|
||||
if (wlan)
|
||||
*wlan = !!(rdata & 8);
|
||||
|
||||
if (bluetooth)
|
||||
*bluetooth = !!(rdata & 128);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Backlight device stuff */
|
||||
|
||||
static int bl_get_brightness(struct backlight_device *b)
|
||||
{
|
||||
return get_lcd_level();
|
||||
}
|
||||
|
||||
|
||||
static int bl_update_status(struct backlight_device *b)
|
||||
{
|
||||
return set_lcd_level(b->props->brightness);
|
||||
}
|
||||
|
||||
static struct backlight_properties msibl_props = {
|
||||
.owner = THIS_MODULE,
|
||||
.get_brightness = bl_get_brightness,
|
||||
.update_status = bl_update_status,
|
||||
.max_brightness = MSI_LCD_LEVEL_MAX-1,
|
||||
};
|
||||
|
||||
static struct backlight_device *msibl_device;
|
||||
|
||||
/* Platform device */
|
||||
|
||||
static ssize_t show_wlan(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
||||
int ret, enabled;
|
||||
|
||||
ret = get_wireless_state(&enabled, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%i\n", enabled);
|
||||
}
|
||||
|
||||
static ssize_t show_bluetooth(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
||||
int ret, enabled;
|
||||
|
||||
ret = get_wireless_state(NULL, &enabled);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%i\n", enabled);
|
||||
}
|
||||
|
||||
static ssize_t show_lcd_level(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
||||
int ret;
|
||||
|
||||
ret = get_lcd_level();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%i\n", ret);
|
||||
}
|
||||
|
||||
static ssize_t store_lcd_level(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
|
||||
int level, ret;
|
||||
|
||||
if (sscanf(buf, "%i", &level) != 1 || (level < 0 || level >= MSI_LCD_LEVEL_MAX))
|
||||
return -EINVAL;
|
||||
|
||||
ret = set_lcd_level(level);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_auto_brightness(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
||||
int ret;
|
||||
|
||||
ret = get_auto_brightness();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%i\n", ret);
|
||||
}
|
||||
|
||||
static ssize_t store_auto_brightness(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
|
||||
int enable, ret;
|
||||
|
||||
if (sscanf(buf, "%i", &enable) != 1 || (enable != (enable & 1)))
|
||||
return -EINVAL;
|
||||
|
||||
ret = set_auto_brightness(enable);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
|
||||
static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness, store_auto_brightness);
|
||||
static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL);
|
||||
static DEVICE_ATTR(wlan, 0444, show_wlan, NULL);
|
||||
|
||||
static struct attribute *msipf_attributes[] = {
|
||||
&dev_attr_lcd_level.attr,
|
||||
&dev_attr_auto_brightness.attr,
|
||||
&dev_attr_bluetooth.attr,
|
||||
&dev_attr_wlan.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group msipf_attribute_group = {
|
||||
.attrs = msipf_attributes
|
||||
};
|
||||
|
||||
static struct platform_driver msipf_driver = {
|
||||
.driver = {
|
||||
.name = "msi-laptop-pf",
|
||||
.owner = THIS_MODULE,
|
||||
}
|
||||
};
|
||||
|
||||
static struct platform_device *msipf_device;
|
||||
|
||||
/* Initialization */
|
||||
|
||||
static struct dmi_system_id __initdata msi_dmi_table[] = {
|
||||
{
|
||||
.ident = "MSI S270",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MS-1013"),
|
||||
}
|
||||
},
|
||||
{
|
||||
.ident = "Medion MD96100",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "NOTEBOOK"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "SAM2000"),
|
||||
}
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
static int __init msi_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (acpi_disabled)
|
||||
return -ENODEV;
|
||||
|
||||
if (!force && !dmi_check_system(msi_dmi_table))
|
||||
return -ENODEV;
|
||||
|
||||
if (auto_brightness < 0 || auto_brightness > 2)
|
||||
return -EINVAL;
|
||||
|
||||
/* Register backlight stuff */
|
||||
|
||||
msibl_device = backlight_device_register("msi-laptop-bl", NULL, &msibl_props);
|
||||
if (IS_ERR(msibl_device))
|
||||
return PTR_ERR(msibl_device);
|
||||
|
||||
ret = platform_driver_register(&msipf_driver);
|
||||
if (ret)
|
||||
goto fail_backlight;
|
||||
|
||||
/* Register platform stuff */
|
||||
|
||||
msipf_device = platform_device_alloc("msi-laptop-pf", -1);
|
||||
if (!msipf_device) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_platform_driver;
|
||||
}
|
||||
|
||||
ret = platform_device_add(msipf_device);
|
||||
if (ret)
|
||||
goto fail_platform_device1;
|
||||
|
||||
ret = sysfs_create_group(&msipf_device->dev.kobj, &msipf_attribute_group);
|
||||
if (ret)
|
||||
goto fail_platform_device2;
|
||||
|
||||
/* Disable automatic brightness control by default because
|
||||
* this module was probably loaded to do brightness control in
|
||||
* software. */
|
||||
|
||||
if (auto_brightness != 2)
|
||||
set_auto_brightness(auto_brightness);
|
||||
|
||||
printk(KERN_INFO "msi-laptop: driver "MSI_DRIVER_VERSION" successfully loaded.\n");
|
||||
|
||||
return 0;
|
||||
|
||||
fail_platform_device2:
|
||||
|
||||
platform_device_del(msipf_device);
|
||||
|
||||
fail_platform_device1:
|
||||
|
||||
platform_device_put(msipf_device);
|
||||
|
||||
fail_platform_driver:
|
||||
|
||||
platform_driver_unregister(&msipf_driver);
|
||||
|
||||
fail_backlight:
|
||||
|
||||
backlight_device_unregister(msibl_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit msi_cleanup(void)
|
||||
{
|
||||
|
||||
sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
|
||||
platform_device_unregister(msipf_device);
|
||||
platform_driver_unregister(&msipf_driver);
|
||||
backlight_device_unregister(msibl_device);
|
||||
|
||||
/* Enable automatic brightness control again */
|
||||
if (auto_brightness != 2)
|
||||
set_auto_brightness(1);
|
||||
|
||||
printk(KERN_INFO "msi-laptop: driver unloaded.\n");
|
||||
}
|
||||
|
||||
module_init(msi_init);
|
||||
module_exit(msi_cleanup);
|
||||
|
||||
MODULE_AUTHOR("Lennart Poettering");
|
||||
MODULE_DESCRIPTION("MSI Laptop Support");
|
||||
MODULE_VERSION(MSI_DRIVER_VERSION);
|
||||
MODULE_LICENSE("GPL");
|
@ -13,6 +13,7 @@
|
||||
#define ACPI_PDC_SMP_C_SWCOORD (0x0040)
|
||||
#define ACPI_PDC_SMP_T_SWCOORD (0x0080)
|
||||
#define ACPI_PDC_C_C1_FFH (0x0100)
|
||||
#define ACPI_PDC_C_C2C3_FFH (0x0200)
|
||||
|
||||
#define ACPI_PDC_EST_CAPABILITY_SMP (ACPI_PDC_SMP_C1PT | \
|
||||
ACPI_PDC_C_C1_HALT | \
|
||||
@ -23,8 +24,10 @@
|
||||
ACPI_PDC_SMP_P_SWCOORD | \
|
||||
ACPI_PDC_P_FFH)
|
||||
|
||||
#define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \
|
||||
ACPI_PDC_SMP_C1PT | \
|
||||
ACPI_PDC_C_C1_HALT)
|
||||
#define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \
|
||||
ACPI_PDC_SMP_C1PT | \
|
||||
ACPI_PDC_C_C1_HALT | \
|
||||
ACPI_PDC_C_C1_FFH | \
|
||||
ACPI_PDC_C_C2C3_FFH)
|
||||
|
||||
#endif /* __PDC_INTEL_H__ */
|
||||
|
@ -29,6 +29,9 @@
|
||||
#define DOMAIN_COORD_TYPE_SW_ANY 0xfd
|
||||
#define DOMAIN_COORD_TYPE_HW_ALL 0xfe
|
||||
|
||||
#define ACPI_CSTATE_SYSTEMIO (0)
|
||||
#define ACPI_CSTATE_FFH (1)
|
||||
|
||||
/* Power Management */
|
||||
|
||||
struct acpi_processor_cx;
|
||||
@ -58,6 +61,8 @@ struct acpi_processor_cx {
|
||||
u8 valid;
|
||||
u8 type;
|
||||
u32 address;
|
||||
u8 space_id;
|
||||
u8 index;
|
||||
u32 latency;
|
||||
u32 latency_ticks;
|
||||
u32 power;
|
||||
@ -206,6 +211,9 @@ void arch_acpi_processor_init_pdc(struct acpi_processor *pr);
|
||||
#ifdef ARCH_HAS_POWER_INIT
|
||||
void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
|
||||
unsigned int cpu);
|
||||
int acpi_processor_ffh_cstate_probe(unsigned int cpu,
|
||||
struct acpi_processor_cx *cx, struct acpi_power_register *reg);
|
||||
void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cstate);
|
||||
#else
|
||||
static inline void acpi_processor_power_init_bm_check(struct
|
||||
acpi_processor_flags
|
||||
@ -214,6 +222,16 @@ static inline void acpi_processor_power_init_bm_check(struct
|
||||
flags->bm_check = 1;
|
||||
return;
|
||||
}
|
||||
static inline int acpi_processor_ffh_cstate_probe(unsigned int cpu,
|
||||
struct acpi_processor_cx *cx, struct acpi_power_register *reg)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
static inline void acpi_processor_ffh_cstate_enter(
|
||||
struct acpi_processor_cx *cstate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* in processor_perflib.c */
|
||||
|
@ -306,6 +306,8 @@ static inline void __mwait(unsigned long eax, unsigned long ecx)
|
||||
: :"a" (eax), "c" (ecx));
|
||||
}
|
||||
|
||||
extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx);
|
||||
|
||||
/* from system description table in BIOS. Mostly for MCA use, but
|
||||
others may find it useful. */
|
||||
extern unsigned int machine_id;
|
||||
|
@ -475,6 +475,8 @@ static inline void __mwait(unsigned long eax, unsigned long ecx)
|
||||
: :"a" (eax), "c" (ecx));
|
||||
}
|
||||
|
||||
extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx);
|
||||
|
||||
#define stack_current() \
|
||||
({ \
|
||||
struct thread_info *ti; \
|
||||
|
@ -494,6 +494,9 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver);
|
||||
|
||||
extern int ec_read(u8 addr, u8 *val);
|
||||
extern int ec_write(u8 addr, u8 val);
|
||||
extern int ec_transaction(u8 command,
|
||||
const u8 *wdata, unsigned wdata_len,
|
||||
u8 *rdata, unsigned rdata_len);
|
||||
|
||||
#endif /*CONFIG_ACPI_EC*/
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user