Commit 96e31022 authored by Linus Torvalds's avatar Linus Torvalds

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: (32 commits)
  ACPI: thermal: show temperature in millidegree Celsius
  thermal: fix generic thermal I/F for hwmon
  acer-wmi: build depends on i8042
  documentation:  Move power-related files to Documentation/power/
  ACPI: buffer array too short in drivers/acpi/system.c
  acer-wmi: Add DMI quirk for mail LED support on Acer Aspire 3610/ 5610
  acer-wmi: Fix DSDT path in documentation
  acer-wmi: Make device detection error messages more descriptive
  laptops: move laptop-mode.txt to Documentation/laptops/
  ACPICA: Warn if packages with invalid references are evaluated
  ACPI: add _PRT quirks to work around broken firmware
  Hibernation: Fix mark_nosave_pages()
  ACPI: Ignore _BQC object when registering backlight device
  ACPI: WMI: Clean up handling of spec violating data blocks
  acer-wmi: Don't warn if mail LED cannot be detected
  acer-wmi: Rename mail LED correctly & remove hardcoded colour
  ACPI: use ACPI_DEBUG_PRINT instead of printk in acpi_processor_hotplug_notify()
  ACPI: button: make real parent for input devices in device tree
  toshiba_acpi: Enable autoloading
  ACPI: EC: Handle IRQ storm on Acer laptops
  ...
parents f2005e17 29ea5171
...@@ -225,8 +225,6 @@ kprobes.txt ...@@ -225,8 +225,6 @@ kprobes.txt
- documents the kernel probes debugging feature. - documents the kernel probes debugging feature.
kref.txt kref.txt
- docs on adding reference counters (krefs) to kernel objects. - docs on adding reference counters (krefs) to kernel objects.
laptop-mode.txt
- how to conserve battery power using laptop-mode.
laptops/ laptops/
- directory with laptop related info and laptop driver documentation. - directory with laptop related info and laptop driver documentation.
ldm.txt ldm.txt
...@@ -301,12 +299,8 @@ pcmcia/ ...@@ -301,12 +299,8 @@ pcmcia/
- info on the Linux PCMCIA driver. - info on the Linux PCMCIA driver.
pi-futex.txt pi-futex.txt
- documentation on lightweight PI-futexes. - documentation on lightweight PI-futexes.
pm.txt
- info on Linux power management support.
pnp.txt pnp.txt
- Linux Plug and Play documentation. - Linux Plug and Play documentation.
power_supply_class.txt
- Tells userspace about battery, UPS, AC or DC power supply properties
power/ power/
- directory with info on Linux PCI power management. - directory with info on Linux PCI power management.
powerpc/ powerpc/
......
...@@ -1506,13 +1506,13 @@ laptop_mode ...@@ -1506,13 +1506,13 @@ laptop_mode
----------- -----------
laptop_mode is a knob that controls "laptop mode". All the things that are laptop_mode is a knob that controls "laptop mode". All the things that are
controlled by this knob are discussed in Documentation/laptop-mode.txt. controlled by this knob are discussed in Documentation/laptops/laptop-mode.txt.
block_dump block_dump
---------- ----------
block_dump enables block I/O debugging when set to a nonzero value. More block_dump enables block I/O debugging when set to a nonzero value. More
information on block I/O debugging is in Documentation/laptop-mode.txt. information on block I/O debugging is in Documentation/laptops/laptop-mode.txt.
swap_token_timeout swap_token_timeout
------------------ ------------------
......
...@@ -138,7 +138,7 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -138,7 +138,7 @@ and is between 256 and 4096 characters. It is defined in the file
strict -- Be less tolerant of platforms that are not strict -- Be less tolerant of platforms that are not
strictly ACPI specification compliant. strictly ACPI specification compliant.
See also Documentation/pm.txt, pci=noacpi See also Documentation/power/pm.txt, pci=noacpi
acpi_apic_instance= [ACPI, IOAPIC] acpi_apic_instance= [ACPI, IOAPIC]
Format: <int> Format: <int>
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
- This file - This file
acer-wmi.txt acer-wmi.txt
- information on the Acer Laptop WMI Extras driver. - information on the Acer Laptop WMI Extras driver.
laptop-mode.txt
- how to conserve battery power using laptop-mode.
sony-laptop.txt sony-laptop.txt
- Sony Notebook Control Driver (SNC) Readme. - Sony Notebook Control Driver (SNC) Readme.
sonypi.txt sonypi.txt
......
...@@ -48,7 +48,7 @@ DSDT. ...@@ -48,7 +48,7 @@ DSDT.
To send me the DSDT, as root/sudo: To send me the DSDT, as root/sudo:
cat /sys/firmware/acpi/DSDT > dsdt cat /sys/firmware/acpi/tables/DSDT > dsdt
And send me the resulting 'dsdt' file. And send me the resulting 'dsdt' file.
...@@ -169,7 +169,7 @@ can be added to acer-wmi. ...@@ -169,7 +169,7 @@ can be added to acer-wmi.
The LED is exposed through the LED subsystem, and can be found in: The LED is exposed through the LED subsystem, and can be found in:
/sys/devices/platform/acer-wmi/leds/acer-mail:green/ /sys/devices/platform/acer-wmi/leds/acer-wmi::mail/
The mail LED is autodetected, so if you don't have one, the LED device won't The mail LED is autodetected, so if you don't have one, the LED device won't
be registered. be registered.
......
...@@ -14,6 +14,12 @@ notifiers.txt ...@@ -14,6 +14,12 @@ notifiers.txt
- Registering suspend notifiers in device drivers - Registering suspend notifiers in device drivers
pci.txt pci.txt
- How the PCI Subsystem Does Power Management - How the PCI Subsystem Does Power Management
pm.txt
- info on Linux power management support.
pm_qos_interface.txt
- info on Linux PM Quality of Service interface
power_supply_class.txt
- Tells userspace about battery, UPS, AC or DC power supply properties
s2ram.txt s2ram.txt
- How to get suspend to ram working (and debug it when it isn't) - How to get suspend to ram working (and debug it when it isn't)
states.txt states.txt
......
...@@ -143,10 +143,10 @@ type Strings which represent the thermal zone type. ...@@ -143,10 +143,10 @@ type Strings which represent the thermal zone type.
This is given by thermal zone driver as part of registration. This is given by thermal zone driver as part of registration.
Eg: "ACPI thermal zone" indicates it's a ACPI thermal device Eg: "ACPI thermal zone" indicates it's a ACPI thermal device
RO RO
Optional Required
temp Current temperature as reported by thermal zone (sensor) temp Current temperature as reported by thermal zone (sensor)
Unit: degree Celsius Unit: millidegree Celsius
RO RO
Required Required
...@@ -163,7 +163,7 @@ mode One of the predefined values in [kernel, user] ...@@ -163,7 +163,7 @@ mode One of the predefined values in [kernel, user]
charge of the thermal management. charge of the thermal management.
trip_point_[0-*]_temp The temperature above which trip point will be fired trip_point_[0-*]_temp The temperature above which trip point will be fired
Unit: degree Celsius Unit: millidegree Celsius
RO RO
Optional Optional
...@@ -193,7 +193,7 @@ type String which represents the type of device ...@@ -193,7 +193,7 @@ type String which represents the type of device
eg. For memory controller device on intel_menlow platform: eg. For memory controller device on intel_menlow platform:
this should be "Memory controller" this should be "Memory controller"
RO RO
Optional Required
max_state The maximum permissible cooling state of this cooling device. max_state The maximum permissible cooling state of this cooling device.
RO RO
...@@ -219,16 +219,16 @@ the sys I/F structure will be built like this: ...@@ -219,16 +219,16 @@ the sys I/F structure will be built like this:
|thermal_zone1: |thermal_zone1:
|-----type: ACPI thermal zone |-----type: ACPI thermal zone
|-----temp: 37 |-----temp: 37000
|-----mode: kernel |-----mode: kernel
|-----trip_point_0_temp: 100 |-----trip_point_0_temp: 100000
|-----trip_point_0_type: critical |-----trip_point_0_type: critical
|-----trip_point_1_temp: 80 |-----trip_point_1_temp: 80000
|-----trip_point_1_type: passive |-----trip_point_1_type: passive
|-----trip_point_2_temp: 70 |-----trip_point_2_temp: 70000
|-----trip_point_2_type: active[0] |-----trip_point_2_type: active0
|-----trip_point_3_temp: 60 |-----trip_point_3_temp: 60000
|-----trip_point_3_type: active[1] |-----trip_point_3_type: active1
|-----cdev0: --->/sys/class/thermal/cooling_device0 |-----cdev0: --->/sys/class/thermal/cooling_device0
|-----cdev0_trip_point: 1 /* cdev0 can be used for passive */ |-----cdev0_trip_point: 1 /* cdev0 can be used for passive */
|-----cdev1: --->/sys/class/thermal/cooling_device3 |-----cdev1: --->/sys/class/thermal/cooling_device3
......
...@@ -1259,7 +1259,7 @@ menuconfig APM ...@@ -1259,7 +1259,7 @@ menuconfig APM
machines with more than one CPU. machines with more than one CPU.
In order to use APM, you will need supporting software. For location In order to use APM, you will need supporting software. For location
and more information, read <file:Documentation/pm.txt> and the and more information, read <file:Documentation/power/pm.txt> and the
Battery Powered Linux mini-HOWTO, available from Battery Powered Linux mini-HOWTO, available from
<http://www.tldp.org/docs.html#howto>. <http://www.tldp.org/docs.html#howto>.
......
...@@ -283,24 +283,23 @@ config ACPI_TOSHIBA ...@@ -283,24 +283,23 @@ config ACPI_TOSHIBA
If you have a legacy free Toshiba laptop (such as the Libretto L1 If you have a legacy free Toshiba laptop (such as the Libretto L1
series), say Y. series), say Y.
config ACPI_CUSTOM_DSDT config ACPI_CUSTOM_DSDT_FILE
bool "Include Custom DSDT" string "Custom DSDT Table file to include"
default ""
depends on !STANDALONE depends on !STANDALONE
default n
help help
This option supports a custom DSDT by linking it into the kernel. This option supports a custom DSDT by linking it into the kernel.
See Documentation/acpi/dsdt-override.txt See Documentation/acpi/dsdt-override.txt
If unsure, say N.
config ACPI_CUSTOM_DSDT_FILE
string "Custom DSDT Table file to include"
depends on ACPI_CUSTOM_DSDT
default ""
help
Enter the full path name to the file which includes the AmlCode Enter the full path name to the file which includes the AmlCode
declaration. declaration.
If unsure, don't enter a file name.
config ACPI_CUSTOM_DSDT
bool
default ACPI_CUSTOM_DSDT_FILE != ""
config ACPI_CUSTOM_DSDT_INITRD config ACPI_CUSTOM_DSDT_INITRD
bool "Read Custom DSDT from initramfs" bool "Read Custom DSDT from initramfs"
depends on BLK_DEV_INITRD depends on BLK_DEV_INITRD
......
...@@ -776,7 +776,7 @@ static int __init acpi_init(void) ...@@ -776,7 +776,7 @@ static int __init acpi_init(void)
acpi_kobj = kobject_create_and_add("acpi", firmware_kobj); acpi_kobj = kobject_create_and_add("acpi", firmware_kobj);
if (!acpi_kobj) { if (!acpi_kobj) {
printk(KERN_WARNING "%s: kset create error\n", __FUNCTION__); printk(KERN_WARNING "%s: kset create error\n", __func__);
acpi_kobj = NULL; acpi_kobj = NULL;
} }
......
...@@ -449,6 +449,7 @@ static int acpi_button_add(struct acpi_device *device) ...@@ -449,6 +449,7 @@ static int acpi_button_add(struct acpi_device *device)
input->phys = button->phys; input->phys = button->phys;
input->id.bustype = BUS_HOST; input->id.bustype = BUS_HOST;
input->id.product = button->type; input->id.product = button->type;
input->dev.parent = &device->dev;
switch (button->type) { switch (button->type) {
case ACPI_BUTTON_TYPE_POWER: case ACPI_BUTTON_TYPE_POWER:
......
...@@ -129,6 +129,7 @@ static struct acpi_ec { ...@@ -129,6 +129,7 @@ static struct acpi_ec {
struct mutex lock; struct mutex lock;
wait_queue_head_t wait; wait_queue_head_t wait;
struct list_head list; struct list_head list;
atomic_t irq_count;
u8 handlers_installed; u8 handlers_installed;
} *boot_ec, *first_ec; } *boot_ec, *first_ec;
...@@ -181,6 +182,8 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) ...@@ -181,6 +182,8 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
{ {
int ret = 0; int ret = 0;
atomic_set(&ec->irq_count, 0);
if (unlikely(event == ACPI_EC_EVENT_OBF_1 && if (unlikely(event == ACPI_EC_EVENT_OBF_1 &&
test_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags))) test_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags)))
force_poll = 1; force_poll = 1;
...@@ -227,6 +230,7 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) ...@@ -227,6 +230,7 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
while (time_before(jiffies, delay)) { while (time_before(jiffies, delay)) {
if (acpi_ec_check_status(ec, event)) if (acpi_ec_check_status(ec, event))
goto end; goto end;
msleep(5);
} }
} }
pr_err(PREFIX "acpi_ec_wait timeout," pr_err(PREFIX "acpi_ec_wait timeout,"
...@@ -529,6 +533,13 @@ static u32 acpi_ec_gpe_handler(void *data) ...@@ -529,6 +533,13 @@ static u32 acpi_ec_gpe_handler(void *data)
struct acpi_ec *ec = data; struct acpi_ec *ec = data;
pr_debug(PREFIX "~~~> interrupt\n"); pr_debug(PREFIX "~~~> interrupt\n");
atomic_inc(&ec->irq_count);
if (atomic_read(&ec->irq_count) > 5) {
pr_err(PREFIX "GPE storm detected, disabling EC GPE\n");
acpi_disable_gpe(NULL, ec->gpe, ACPI_ISR);
clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
return ACPI_INTERRUPT_HANDLED;
}
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))
wake_up(&ec->wait); wake_up(&ec->wait);
...@@ -943,11 +954,7 @@ int __init acpi_ec_ecdt_probe(void) ...@@ -943,11 +954,7 @@ int __init acpi_ec_ecdt_probe(void)
boot_ec->command_addr = ecdt_ptr->control.address; boot_ec->command_addr = ecdt_ptr->control.address;
boot_ec->data_addr = ecdt_ptr->data.address; boot_ec->data_addr = ecdt_ptr->data.address;
boot_ec->gpe = ecdt_ptr->gpe; boot_ec->gpe = ecdt_ptr->gpe;
if (ACPI_FAILURE(acpi_get_handle(NULL, ecdt_ptr->id,
&boot_ec->handle))) {
pr_info("Failed to locate handle for boot EC\n");
boot_ec->handle = ACPI_ROOT_OBJECT; boot_ec->handle = ACPI_ROOT_OBJECT;
}
} else { } else {
/* This workaround is needed only on some broken machines, /* This workaround is needed only on some broken machines,
* which require early EC, but fail to provide ECDT */ * which require early EC, but fail to provide ECDT */
......
...@@ -1237,7 +1237,7 @@ int acpi_check_resource_conflict(struct resource *res) ...@@ -1237,7 +1237,7 @@ int acpi_check_resource_conflict(struct resource *res)
if (clash) { if (clash) {
if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) { if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) {
printk(KERN_INFO "%sACPI: %s resource %s [0x%llx-0x%llx]" printk("%sACPI: %s resource %s [0x%llx-0x%llx]"
" conflicts with ACPI region %s" " conflicts with ACPI region %s"
" [0x%llx-0x%llx]\n", " [0x%llx-0x%llx]\n",
acpi_enforce_resources == ENFORCE_RESOURCES_LAX acpi_enforce_resources == ENFORCE_RESOURCES_LAX
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
*/ */
#include <linux/dmi.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -76,6 +77,101 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment, ...@@ -76,6 +77,101 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment,
return NULL; return NULL;
} }
/* http://bugzilla.kernel.org/show_bug.cgi?id=4773 */
static struct dmi_system_id medion_md9580[] = {
{
.ident = "Medion MD9580-F laptop",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
DMI_MATCH(DMI_PRODUCT_NAME, "A555"),
},
},
{ }
};
/* http://bugzilla.kernel.org/show_bug.cgi?id=5044 */
static struct dmi_system_id dell_optiplex[] = {
{
.ident = "Dell Optiplex GX1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX1 600S+"),
},
},
{ }
};
/* http://bugzilla.kernel.org/show_bug.cgi?id=10138 */
static struct dmi_system_id hp_t5710[] = {
{
.ident = "HP t5710",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "hp t5000 series"),
DMI_MATCH(DMI_BOARD_NAME, "098Ch"),
},
},
{ }
};
struct prt_quirk {
struct dmi_system_id *system;
unsigned int segment;
unsigned int bus;
unsigned int device;
unsigned char pin;
char *source; /* according to BIOS */
char *actual_source;
};
/*
* These systems have incorrect _PRT entries. The BIOS claims the PCI
* interrupt at the listed segment/bus/device/pin is connected to the first
* link device, but it is actually connected to the second.
*/
static struct prt_quirk prt_quirks[] = {
{ medion_md9580, 0, 0, 9, 'A',
"\\_SB_.PCI0.ISA.LNKA",
"\\_SB_.PCI0.ISA.LNKB"},
{ dell_optiplex, 0, 0, 0xd, 'A',
"\\_SB_.LNKB",
"\\_SB_.LNKA"},
{ hp_t5710, 0, 0, 1, 'A',
"\\_SB_.PCI0.LNK1",
"\\_SB_.PCI0.LNK3"},
};
static void
do_prt_fixups(struct acpi_prt_entry *entry, struct acpi_pci_routing_table *prt)
{
int i;
struct prt_quirk *quirk;
for (i = 0; i < ARRAY_SIZE(prt_quirks); i++) {
quirk = &prt_quirks[i];
/* All current quirks involve link devices, not GSIs */
if (!prt->source)
continue;
if (dmi_check_system(quirk->system) &&
entry->id.segment == quirk->segment &&
entry->id.bus == quirk->bus &&
entry->id.device == quirk->device &&
entry->pin + 'A' == quirk->pin &&
!strcmp(prt->source, quirk->source) &&
strlen(prt->source) >= strlen(quirk->actual_source)) {
printk(KERN_WARNING PREFIX "firmware reports "
"%04x:%02x:%02x[%c] connected to %s; "
"changing to %s\n",
entry->id.segment, entry->id.bus,
entry->id.device, 'A' + entry->pin,
prt->source, quirk->actual_source);
strcpy(prt->source, quirk->actual_source);
}
}
}
static int static int
acpi_pci_irq_add_entry(acpi_handle handle, acpi_pci_irq_add_entry(acpi_handle handle,
int segment, int bus, struct acpi_pci_routing_table *prt) int segment, int bus, struct acpi_pci_routing_table *prt)
...@@ -96,6 +192,8 @@ acpi_pci_irq_add_entry(acpi_handle handle, ...@@ -96,6 +192,8 @@ acpi_pci_irq_add_entry(acpi_handle handle,
entry->id.function = prt->address & 0xFFFF; entry->id.function = prt->address & 0xFFFF;
entry->pin = prt->pin; entry->pin = prt->pin;
do_prt_fixups(entry, prt);
/* /*
* Type 1: Dynamic * Type 1: Dynamic
* --------------- * ---------------
......
...@@ -184,7 +184,7 @@ static void acpi_pci_bridge_scan(struct acpi_device *device) ...@@ -184,7 +184,7 @@ static void acpi_pci_bridge_scan(struct acpi_device *device)
} }
} }
static int acpi_pci_root_add(struct acpi_device *device) static int __devinit acpi_pci_root_add(struct acpi_device *device)
{ {
int result = 0; int result = 0;
struct acpi_pci_root *root = NULL; struct acpi_pci_root *root = NULL;
......
...@@ -840,17 +840,19 @@ static int is_processor_present(acpi_handle handle) ...@@ -840,17 +840,19 @@ static int is_processor_present(acpi_handle handle)
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
/*
* if a processor object does not have an _STA object,
* OSPM assumes that the processor is present.
*/
if (status == AE_NOT_FOUND)
return 1;
if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT)) if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT))
return 1; return 1;
ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present")); /*
* _STA is mandatory for a processor that supports hot plug
*/
if (status == AE_NOT_FOUND)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Processor does not support hot plug\n"));
else
ACPI_EXCEPTION((AE_INFO, status,
"Processor Device is not present"));
return 0; return 0;
} }
...@@ -886,8 +888,8 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device) ...@@ -886,8 +888,8 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
return 0; return 0;
} }
static void static void __ref acpi_processor_hotplug_notify(acpi_handle handle,
acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data) u32 event, void *data)
{ {
struct acpi_processor *pr; struct acpi_processor *pr;
struct acpi_device *device = NULL; struct acpi_device *device = NULL;
...@@ -897,9 +899,10 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data) ...@@ -897,9 +899,10 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data)
switch (event) { switch (event) {
case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK: case ACPI_NOTIFY_DEVICE_CHECK:
printk("Processor driver received %s event\n", ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Processor driver received %s event\n",
(event == ACPI_NOTIFY_BUS_CHECK) ? (event == ACPI_NOTIFY_BUS_CHECK) ?
"ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK"); "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK"));
if (!is_processor_present(handle)) if (!is_processor_present(handle))
break; break;
......
...@@ -609,7 +609,8 @@ acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) ...@@ -609,7 +609,8 @@ acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer); status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);
if (ACPI_SUCCESS(status)) { if (ACPI_SUCCESS(status)) {
obj = buffer.pointer; obj = buffer.pointer;
status = acpi_get_handle(NULL, obj->string.pointer, ejd); status = acpi_get_handle(ACPI_ROOT_OBJECT, obj->string.pointer,
ejd);
kfree(buffer.pointer); kfree(buffer.pointer);
} }
return status; return status;
...@@ -966,7 +967,7 @@ static void acpi_device_set_id(struct acpi_device *device, ...@@ -966,7 +967,7 @@ static void acpi_device_set_id(struct acpi_device *device,
case ACPI_BUS_TYPE_DEVICE: case ACPI_BUS_TYPE_DEVICE:
status = acpi_get_object_info(handle, &buffer); status = acpi_get_object_info(handle, &buffer);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
printk(KERN_ERR PREFIX "%s: Error reading device info\n", __FUNCTION__); printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__);
return; return;
} }
......
...@@ -504,7 +504,7 @@ static void acpi_power_off_prepare(void) ...@@ -504,7 +504,7 @@ static void acpi_power_off_prepare(void)
static void acpi_power_off(void) static void acpi_power_off(void)
{ {
/* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
printk("%s called\n", __FUNCTION__); printk("%s called\n", __func__);
local_irq_disable(); local_irq_disable();
acpi_enable_wakeup_device(ACPI_STATE_S5); acpi_enable_wakeup_device(ACPI_STATE_S5);
acpi_enter_sleep_state(ACPI_STATE_S5); acpi_enter_sleep_state(ACPI_STATE_S5);
......
...@@ -319,7 +319,7 @@ void acpi_irq_stats_init(void) ...@@ -319,7 +319,7 @@ void acpi_irq_stats_init(void)
goto fail; goto fail;
for (i = 0; i < num_counters; ++i) { for (i = 0; i < num_counters; ++i) {
char buffer[10]; char buffer[12];
char *name; char *name;
if (i < num_gpes) if (i < num_gpes)
......
...@@ -879,6 +879,8 @@ static void acpi_thermal_check(void *data) ...@@ -879,6 +879,8 @@ static void acpi_thermal_check(void *data)
} }
/* sys I/F for generic thermal sysfs support */ /* sys I/F for generic thermal sysfs support */
#define KELVIN_TO_MILLICELSIUS(t) (t * 100 - 273200)
static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf) static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
{ {
struct acpi_thermal *tz = thermal->devdata; struct acpi_thermal *tz = thermal->devdata;
...@@ -886,7 +888,7 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf) ...@@ -886,7 +888,7 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
if (!tz) if (!tz)
return -EINVAL; return -EINVAL;
return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(tz->temperature)); return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(tz->temperature));
} }
static const char enabled[] = "kernel"; static const char enabled[] = "kernel";
...@@ -980,21 +982,21 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal, ...@@ -980,21 +982,21 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
if (tz->trips.critical.flags.valid) { if (tz->trips.critical.flags.valid) {
if (!trip) if (!trip)
return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
tz->trips.critical.temperature)); tz->trips.critical.temperature));
trip--; trip--;
} }
if (tz->trips.hot.flags.valid) { if (tz->trips.hot.flags.valid) {
if (!trip) if (!trip)
return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
tz->trips.hot.temperature)); tz->trips.hot.temperature));
trip--; trip--;
} }
if (tz->trips.passive.flags.valid) { if (tz->trips.passive.flags.valid) {
if (!trip) if (!trip)
return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
tz->trips.passive.temperature)); tz->trips.passive.temperature));
trip--; trip--;
} }
...@@ -1002,7 +1004,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal, ...@@ -1002,7 +1004,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
tz->trips.active[i].flags.valid; i++) { tz->trips.active[i].flags.valid; i++) {
if (!trip) if (!trip)
return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
tz->trips.active[i].temperature)); tz->trips.active[i].temperature));
trip--; trip--;
} }
......
...@@ -99,6 +99,13 @@ MODULE_LICENSE("GPL"); ...@@ -99,6 +99,13 @@ MODULE_LICENSE("GPL");
#define HCI_VIDEO_OUT_CRT 0x2 #define HCI_VIDEO_OUT_CRT 0x2
#define HCI_VIDEO_OUT_TV 0x4 #define HCI_VIDEO_OUT_TV 0x4
static const struct acpi_device_id toshiba_device_ids[] = {
{"TOS6200", 0},
{"TOS1900", 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
/* utility /* utility
*/ */
......
...@@ -109,7 +109,7 @@ void acpi_ut_track_stack_ptr(void) ...@@ -109,7 +109,7 @@ void acpi_ut_track_stack_ptr(void)
* RETURN: Updated pointer to the function name * RETURN: Updated pointer to the function name
* *
* DESCRIPTION: Remove the "Acpi" prefix from the function name, if present. * DESCRIPTION: Remove the "Acpi" prefix from the function name, if present.
* This allows compiler macros such as __FUNCTION__ to be used * This allows compiler macros such as __func__ to be used
* with no change to the debug output. * with no change to the debug output.
* *
******************************************************************************/ ******************************************************************************/
......
...@@ -432,7 +432,7 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object, ...@@ -432,7 +432,7 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object,
* element -- which is legal) * element -- which is legal)
*/ */
if (!internal_object) { if (!internal_object) {
*obj_length = 0; *obj_length = sizeof(union acpi_object);
return_ACPI_STATUS(AE_OK); return_ACPI_STATUS(AE_OK);
} }
......
...@@ -407,6 +407,12 @@ acpi_evaluate_reference(acpi_handle handle, ...@@ -407,6 +407,12 @@ acpi_evaluate_reference(acpi_handle handle,
break; break;
} }
if (!element->reference.handle) {
printk(KERN_WARNING PREFIX "Invalid reference in"
" package %s\n", pathname);
status = AE_NULL_ENTRY;
break;
}
/* Get the acpi_handle. */ /* Get the acpi_handle. */
list->handles[i] = element->reference.handle; list->handles[i] = element->reference.handle;
......
...@@ -713,7 +713,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) ...@@ -713,7 +713,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
kfree(obj); kfree(obj);
if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){ if (device->cap._BCL && device->cap._BCM && max_level > 0) {
int result; int result;
static int count = 0; static int count = 0;
char *name; char *name;
...@@ -1201,7 +1201,7 @@ static int acpi_video_bus_ROM_seq_show(struct seq_file *seq, void *offset) ...@@ -1201,7 +1201,7 @@ static int acpi_video_bus_ROM_seq_show(struct seq_file *seq, void *offset)
if (!video) if (!video)
goto end; goto end;
printk(KERN_INFO PREFIX "Please implement %s\n", __FUNCTION__); printk(KERN_INFO PREFIX "Please implement %s\n", __func__);
seq_printf(seq, "<TODO>\n"); seq_printf(seq, "<TODO>\n");
end: end:
......
...@@ -293,7 +293,7 @@ struct acpi_buffer *out) ...@@ -293,7 +293,7 @@ struct acpi_buffer *out)
{ {
struct guid_block *block = NULL; struct guid_block *block = NULL;
struct wmi_block *wblock = NULL; struct wmi_block *wblock = NULL;
acpi_handle handle; acpi_handle handle, wc_handle;
acpi_status status, wc_status = AE_ERROR; acpi_status status, wc_status = AE_ERROR;
struct acpi_object_list input, wc_input; struct acpi_object_list input, wc_input;
union acpi_object wc_params[1], wq_params[1]; union acpi_object wc_params[1], wq_params[1];
...@@ -338,6 +338,8 @@ struct acpi_buffer *out) ...@@ -338,6 +338,8 @@ struct acpi_buffer *out)
* expensive, but have no corresponding WCxx method. So we * expensive, but have no corresponding WCxx method. So we
* should not fail if this happens. * should not fail if this happens.
*/ */
wc_status = acpi_get_handle(handle, wc_method, &wc_handle);
if (ACPI_SUCCESS(wc_status))
wc_status = acpi_evaluate_object(handle, wc_method, wc_status = acpi_evaluate_object(handle, wc_method,
&wc_input, NULL); &wc_input, NULL);
} }
...@@ -351,7 +353,7 @@ struct acpi_buffer *out) ...@@ -351,7 +353,7 @@ struct acpi_buffer *out)
* If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
* the WQxx method failed - we should disable collection anyway. * the WQxx method failed - we should disable collection anyway.
*/ */
if ((block->flags & ACPI_WMI_EXPENSIVE) && wc_status) { if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {
wc_params[0].integer.value = 0; wc_params[0].integer.value = 0;
status = acpi_evaluate_object(handle, status = acpi_evaluate_object(handle,
wc_method, &wc_input, NULL); wc_method, &wc_input, NULL);
......
...@@ -108,6 +108,7 @@ config ACER_WMI ...@@ -108,6 +108,7 @@ config ACER_WMI
depends on ACPI depends on ACPI
depends on LEDS_CLASS depends on LEDS_CLASS
depends on BACKLIGHT_CLASS_DEVICE depends on BACKLIGHT_CLASS_DEVICE
depends on SERIO_I8042
select ACPI_WMI select ACPI_WMI
---help--- ---help---
This is a driver for newer Acer (and Wistron) laptops. It adds This is a driver for newer Acer (and Wistron) laptops. It adds
......
...@@ -217,6 +217,15 @@ static struct dmi_system_id acer_quirks[] = { ...@@ -217,6 +217,15 @@ static struct dmi_system_id acer_quirks[] = {
}, },
.driver_data = &quirk_acer_travelmate_2490, .driver_data = &quirk_acer_travelmate_2490,
}, },
{
.callback = dmi_matched,
.ident = "Acer Aspire 3610",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3610"),
},
.driver_data = &quirk_acer_travelmate_2490,
},
{ {
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer Aspire 5100", .ident = "Acer Aspire 5100",
...@@ -226,6 +235,15 @@ static struct dmi_system_id acer_quirks[] = { ...@@ -226,6 +235,15 @@ static struct dmi_system_id acer_quirks[] = {
}, },
.driver_data = &quirk_acer_travelmate_2490, .driver_data = &quirk_acer_travelmate_2490,
}, },
{
.callback = dmi_matched,
.ident = "Acer Aspire 5610",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
},
.driver_data = &quirk_acer_travelmate_2490,
},
{ {
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer Aspire 5630", .ident = "Acer Aspire 5630",
...@@ -761,11 +779,11 @@ enum led_brightness value) ...@@ -761,11 +779,11 @@ enum led_brightness value)
} }
static struct led_classdev mail_led = { static struct led_classdev mail_led = {
.name = "acer-mail:green", .name = "acer-wmi::mail",
.brightness_set = mail_led_set, .brightness_set = mail_led_set,
}; };
static int __init acer_led_init(struct device *dev) static int __devinit acer_led_init(struct device *dev)
{ {
return led_classdev_register(dev, &mail_led); return led_classdev_register(dev, &mail_led);
} }
...@@ -798,7 +816,7 @@ static struct backlight_ops acer_bl_ops = { ...@@ -798,7 +816,7 @@ static struct backlight_ops acer_bl_ops = {
.update_status = update_bl_status, .update_status = update_bl_status,
}; };
static int __init acer_backlight_init(struct device *dev) static int __devinit acer_backlight_init(struct device *dev)
{ {
struct backlight_device *bd; struct backlight_device *bd;
...@@ -817,7 +835,7 @@ static int __init acer_backlight_init(struct device *dev) ...@@ -817,7 +835,7 @@ static int __init acer_backlight_init(struct device *dev)
return 0; return 0;
} }
static void __exit acer_backlight_exit(void) static void acer_backlight_exit(void)
{ {
backlight_device_unregister(acer_backlight_device); backlight_device_unregister(acer_backlight_device);
} }
...@@ -1052,11 +1070,12 @@ static int __init acer_wmi_init(void) ...@@ -1052,11 +1070,12 @@ static int __init acer_wmi_init(void)
if (wmi_has_guid(WMID_GUID2) && interface) { if (wmi_has_guid(WMID_GUID2) && interface) {
if (ACPI_FAILURE(WMID_set_capabilities())) { if (ACPI_FAILURE(WMID_set_capabilities())) {
printk(ACER_ERR "Unable to detect available devices\n"); printk(ACER_ERR "Unable to detect available WMID "
"devices\n");
return -ENODEV; return -ENODEV;
} }
} else if (!wmi_has_guid(WMID_GUID2) && interface) { } else if (!wmi_has_guid(WMID_GUID2) && interface) {
printk(ACER_ERR "Unable to detect available devices\n"); printk(ACER_ERR "No WMID device detection method found\n");
return -ENODEV; return -ENODEV;
} }
...@@ -1064,21 +1083,20 @@ static int __init acer_wmi_init(void) ...@@ -1064,21 +1083,20 @@ static int __init acer_wmi_init(void)
interface = &AMW0_interface; interface = &AMW0_interface;
if (ACPI_FAILURE(AMW0_set_capabilities())) { if (ACPI_FAILURE(AMW0_set_capabilities())) {
printk(ACER_ERR "Unable to detect available devices\n"); printk(ACER_ERR "Unable to detect available AMW0 "
"devices\n");
return -ENODEV; return -ENODEV;
} }
} }
if (wmi_has_guid(AMW0_GUID1)) { if (wmi_has_guid(AMW0_GUID1))
if (ACPI_FAILURE(AMW0_find_mailled())) AMW0_find_mailled();
printk(ACER_ERR "Unable to detect mail LED\n");
}
find_quirks(); find_quirks();
if (!interface) { if (!interface) {
printk(ACER_ERR "No or unsupported WMI interface, unable to "); printk(ACER_ERR "No or unsupported WMI interface, unable to "
printk(KERN_CONT "load.\n"); "load\n");
return -ENODEV; return -ENODEV;
} }
......
...@@ -315,7 +315,7 @@ static void sony_laptop_report_input_event(u8 event) ...@@ -315,7 +315,7 @@ static void sony_laptop_report_input_event(u8 event)
break; break;
default: default:
if (event > ARRAY_SIZE(sony_laptop_input_index)) { if (event >= ARRAY_SIZE(sony_laptop_input_index)) {
dprintk("sony_laptop_report_input_event, event not known: %d\n", event); dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
break; break;
} }
......
...@@ -272,21 +272,29 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) ...@@ -272,21 +272,29 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
{ {
acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev); acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
acpi_handle tmp; acpi_handle tmp;
static int state_conv[] = { static const u8 state_conv[] = {
[0] = 0, [PCI_D0] = ACPI_STATE_D0,
[1] = 1, [PCI_D1] = ACPI_STATE_D1,
[2] = 2, [PCI_D2] = ACPI_STATE_D2,
[3] = 3, [PCI_D3hot] = ACPI_STATE_D3,
[4] = 3 [PCI_D3cold] = ACPI_STATE_D3
}; };
int acpi_state = state_conv[(int __force) state];
if (!handle) if (!handle)
return -ENODEV; return -ENODEV;
/* If the ACPI device has _EJ0, ignore the device */ /* If the ACPI device has _EJ0, ignore the device */
if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp))) if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
return 0; return 0;
return acpi_bus_set_power(handle, acpi_state);
switch (state) {
case PCI_D0:
case PCI_D1:
case PCI_D2:
case PCI_D3hot:
case PCI_D3cold:
return acpi_bus_set_power(handle, state_conv[state]);
}
return -EINVAL;
} }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
menuconfig THERMAL menuconfig THERMAL
bool "Generic Thermal sysfs driver" bool "Generic Thermal sysfs driver"
select HWMON
default y default y
help help
Generic Thermal Sysfs driver offers a generic mechanism for Generic Thermal Sysfs driver offers a generic mechanism for
......
...@@ -30,8 +30,10 @@ ...@@ -30,8 +30,10 @@
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/thermal.h> #include <linux/thermal.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
MODULE_AUTHOR("Zhang Rui") MODULE_AUTHOR("Zhang Rui");
MODULE_DESCRIPTION("Generic thermal management sysfs support"); MODULE_DESCRIPTION("Generic thermal management sysfs support");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -56,6 +58,9 @@ static LIST_HEAD(thermal_tz_list); ...@@ -56,6 +58,9 @@ static LIST_HEAD(thermal_tz_list);
static LIST_HEAD(thermal_cdev_list); static LIST_HEAD(thermal_cdev_list);
static DEFINE_MUTEX(thermal_list_lock); static DEFINE_MUTEX(thermal_list_lock);
static struct device *thermal_hwmon;
#define MAX_THERMAL_ZONES 10
static int get_idr(struct idr *idr, struct mutex *lock, int *id) static int get_idr(struct idr *idr, struct mutex *lock, int *id)
{ {
int err; int err;
...@@ -87,7 +92,67 @@ static void release_idr(struct idr *idr, struct mutex *lock, int id) ...@@ -87,7 +92,67 @@ static void release_idr(struct idr *idr, struct mutex *lock, int id)
mutex_unlock(lock); mutex_unlock(lock);
} }
/* sys I/F for thermal zone */ /* hwmon sys I/F*/
static ssize_t
name_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf, "thermal_sys_class\n");
}
static ssize_t
temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct thermal_zone_device *tz;
struct sensor_device_attribute *sensor_attr
= to_sensor_dev_attr(attr);
list_for_each_entry(tz, &thermal_tz_list, node)
if (tz->id == sensor_attr->index)
return tz->ops->get_temp(tz, buf);
return -ENODEV;
}
static ssize_t
temp_crit_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct thermal_zone_device *tz;
struct sensor_device_attribute *sensor_attr
= to_sensor_dev_attr(attr);
list_for_each_entry(tz, &thermal_tz_list, node)
if (tz->id == sensor_attr->index)
return tz->ops->get_trip_temp(tz, 0, buf);
return -ENODEV;
}
static DEVICE_ATTR(name, 0444, name_show, NULL);
static struct sensor_device_attribute sensor_attrs[] = {
SENSOR_ATTR(temp1_input, 0444, temp_input_show, NULL, 0),
SENSOR_ATTR(temp1_crit, 0444, temp_crit_show, NULL, 0),
SENSOR_ATTR(temp2_input, 0444, temp_input_show, NULL, 1),
SENSOR_ATTR(temp2_crit, 0444, temp_crit_show, NULL, 1),
SENSOR_ATTR(temp3_input, 0444, temp_input_show, NULL, 2),
SENSOR_ATTR(temp3_crit, 0444, temp_crit_show, NULL, 2),
SENSOR_ATTR(temp4_input, 0444, temp_input_show, NULL, 3),
SENSOR_ATTR(temp4_crit, 0444, temp_crit_show, NULL, 3),
SENSOR_ATTR(temp5_input, 0444, temp_input_show, NULL, 4),
SENSOR_ATTR(temp5_crit, 0444, temp_crit_show, NULL, 4),
SENSOR_ATTR(temp6_input, 0444, temp_input_show, NULL, 5),
SENSOR_ATTR(temp6_crit, 0444, temp_crit_show, NULL, 5),
SENSOR_ATTR(temp7_input, 0444, temp_input_show, NULL, 6),
SENSOR_ATTR(temp7_crit, 0444, temp_crit_show, NULL, 6),
SENSOR_ATTR(temp8_input, 0444, temp_input_show, NULL, 7),
SENSOR_ATTR(temp8_crit, 0444, temp_crit_show, NULL, 7),
SENSOR_ATTR(temp9_input, 0444, temp_input_show, NULL, 8),
SENSOR_ATTR(temp9_crit, 0444, temp_crit_show, NULL, 8),
SENSOR_ATTR(temp10_input, 0444, temp_input_show, NULL, 9),
SENSOR_ATTR(temp10_crit, 0444, temp_crit_show, NULL, 9),
};
/* thermal zone sys I/F */
#define to_thermal_zone(_dev) \ #define to_thermal_zone(_dev) \
container_of(_dev, struct thermal_zone_device, device) container_of(_dev, struct thermal_zone_device, device)
...@@ -214,7 +279,7 @@ do { \ ...@@ -214,7 +279,7 @@ do { \
device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]); \ device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]); \
} while (0) } while (0)
/* sys I/F for cooling device */ /* cooling device sys I/F */
#define to_cooling_device(_dev) \ #define to_cooling_device(_dev) \
container_of(_dev, struct thermal_cooling_device, device) container_of(_dev, struct thermal_cooling_device, device)
...@@ -447,6 +512,9 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type, ...@@ -447,6 +512,9 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type,
struct thermal_zone_device *pos; struct thermal_zone_device *pos;
int result; int result;
if (!type)
return ERR_PTR(-EINVAL);
if (strlen(type) >= THERMAL_NAME_LENGTH) if (strlen(type) >= THERMAL_NAME_LENGTH)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -477,11 +545,9 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type, ...@@ -477,11 +545,9 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type,
} }
/* sys I/F */ /* sys I/F */
if (type) {
result = device_create_file(&cdev->device, &dev_attr_cdev_type); result = device_create_file(&cdev->device, &dev_attr_cdev_type);
if (result) if (result)
goto unregister; goto unregister;
}
result = device_create_file(&cdev->device, &dev_attr_max_state); result = device_create_file(&cdev->device, &dev_attr_max_state);
if (result) if (result)
...@@ -547,7 +613,7 @@ void thermal_cooling_device_unregister(struct ...@@ -547,7 +613,7 @@ void thermal_cooling_device_unregister(struct
tz->ops->unbind(tz, cdev); tz->ops->unbind(tz, cdev);
} }
mutex_unlock(&thermal_list_lock); mutex_unlock(&thermal_list_lock);
if (cdev->type[0])
device_remove_file(&cdev->device, &dev_attr_cdev_type); device_remove_file(&cdev->device, &dev_attr_cdev_type);
device_remove_file(&cdev->device, &dev_attr_max_state); device_remove_file(&cdev->device, &dev_attr_max_state);
device_remove_file(&cdev->device, &dev_attr_cur_state); device_remove_file(&cdev->device, &dev_attr_cur_state);
...@@ -580,6 +646,9 @@ struct thermal_zone_device *thermal_zone_device_register(char *type, ...@@ -580,6 +646,9 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
int result; int result;
int count; int count;
if (!type)
return ERR_PTR(-EINVAL);
if (strlen(type) >= THERMAL_NAME_LENGTH) if (strlen(type) >= THERMAL_NAME_LENGTH)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -601,6 +670,13 @@ struct thermal_zone_device *thermal_zone_device_register(char *type, ...@@ -601,6 +670,13 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
kfree(tz); kfree(tz);
return ERR_PTR(result); return ERR_PTR(result);
} }
if (tz->id >= MAX_THERMAL_ZONES) {
printk(KERN_ERR PREFIX
"Too many thermal zones\n");
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
kfree(tz);
return ERR_PTR(-EINVAL);
}
strcpy(tz->type, type); strcpy(tz->type, type);
tz->ops = ops; tz->ops = ops;
...@@ -615,12 +691,27 @@ struct thermal_zone_device *thermal_zone_device_register(char *type, ...@@ -615,12 +691,27 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
return ERR_PTR(result); return ERR_PTR(result);
} }
/* hwmon sys I/F */
result = device_create_file(thermal_hwmon,
&sensor_attrs[tz->id * 2].dev_attr);
if (result)
goto unregister;
if (trips > 0) {
char buf[40];
result = tz->ops->get_trip_type(tz, 0, buf);
if (result > 0 && !strcmp(buf, "critical\n")) {
result = device_create_file(thermal_hwmon,
&sensor_attrs[tz->id * 2 + 1].dev_attr);
if (result)
goto unregister;
}
}
/* sys I/F */ /* sys I/F */
if (type) {
result = device_create_file(&tz->device, &dev_attr_type); result = device_create_file(&tz->device, &dev_attr_type);
if (result) if (result)
goto unregister; goto unregister;
}
result = device_create_file(&tz->device, &dev_attr_temp); result = device_create_file(&tz->device, &dev_attr_temp);
if (result) if (result)
...@@ -687,7 +778,16 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) ...@@ -687,7 +778,16 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
tz->ops->unbind(tz, cdev); tz->ops->unbind(tz, cdev);
mutex_unlock(&thermal_list_lock); mutex_unlock(&thermal_list_lock);
if (tz->type[0]) device_remove_file(thermal_hwmon,
&sensor_attrs[tz->id * 2].dev_attr);
if (tz->trips > 0) {
char buf[40];
if (tz->ops->get_trip_type(tz, 0, buf) > 0)
if (!strcmp(buf, "critical\n"))
device_remove_file(thermal_hwmon,
&sensor_attrs[tz->id * 2 + 1].dev_attr);
}
device_remove_file(&tz->device, &dev_attr_type); device_remove_file(&tz->device, &dev_attr_type);
device_remove_file(&tz->device, &dev_attr_temp); device_remove_file(&tz->device, &dev_attr_temp);
if (tz->ops->get_mode) if (tz->ops->get_mode)
...@@ -705,6 +805,19 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) ...@@ -705,6 +805,19 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
EXPORT_SYMBOL(thermal_zone_device_unregister); EXPORT_SYMBOL(thermal_zone_device_unregister);
static void thermal_exit(void)
{
if (thermal_hwmon) {
device_remove_file(thermal_hwmon, &dev_attr_name);
hwmon_device_unregister(thermal_hwmon);
}
class_unregister(&thermal_class);
idr_destroy(&thermal_tz_idr);
idr_destroy(&thermal_cdev_idr);
mutex_destroy(&thermal_idr_lock);
mutex_destroy(&thermal_list_lock);
}
static int __init thermal_init(void) static int __init thermal_init(void)
{ {
int result = 0; int result = 0;
...@@ -716,16 +829,20 @@ static int __init thermal_init(void) ...@@ -716,16 +829,20 @@ static int __init thermal_init(void)
mutex_destroy(&thermal_idr_lock); mutex_destroy(&thermal_idr_lock);
mutex_destroy(&thermal_list_lock); mutex_destroy(&thermal_list_lock);
} }
thermal_hwmon = hwmon_device_register(NULL);
if (IS_ERR(thermal_hwmon)) {
result = PTR_ERR(thermal_hwmon);
thermal_hwmon = NULL;
printk(KERN_ERR PREFIX
"unable to register hwmon device\n");
thermal_exit();
return result; return result;
} }
static void __exit thermal_exit(void) result = device_create_file(thermal_hwmon, &dev_attr_name);
{
class_unregister(&thermal_class); return result;
idr_destroy(&thermal_tz_idr);
idr_destroy(&thermal_cdev_idr);
mutex_destroy(&thermal_idr_lock);
mutex_destroy(&thermal_list_lock);
} }
subsys_initcall(thermal_init); subsys_initcall(thermal_init);
......
...@@ -190,7 +190,7 @@ config APM_EMULATION ...@@ -190,7 +190,7 @@ config APM_EMULATION
notification of APM "events" (e.g. battery status change). notification of APM "events" (e.g. battery status change).
In order to use APM, you will need supporting software. For location In order to use APM, you will need supporting software. For location
and more information, read <file:Documentation/pm.txt> and the and more information, read <file:Documentation/power/pm.txt> and the
Battery Powered Linux mini-HOWTO, available from Battery Powered Linux mini-HOWTO, available from
<http://www.tldp.org/docs.html#howto>. <http://www.tldp.org/docs.html#howto>.
......
...@@ -447,7 +447,7 @@ static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free) ...@@ -447,7 +447,7 @@ static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free)
* of @bm->cur_zone_bm are updated. * of @bm->cur_zone_bm are updated.
*/ */
static void memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn, static int memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn,
void **addr, unsigned int *bit_nr) void **addr, unsigned int *bit_nr)
{ {
struct zone_bitmap *zone_bm; struct zone_bitmap *zone_bm;
...@@ -461,7 +461,8 @@ static void memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn, ...@@ -461,7 +461,8 @@ static void memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn,
while (pfn < zone_bm->start_pfn || pfn >= zone_bm->end_pfn) { while (pfn < zone_bm->start_pfn || pfn >= zone_bm->end_pfn) {
zone_bm = zone_bm->next; zone_bm = zone_bm->next;
BUG_ON(!zone_bm); if (!zone_bm)
return -EFAULT;
} }
bm->cur.zone_bm = zone_bm; bm->cur.zone_bm = zone_bm;
} }
...@@ -479,23 +480,40 @@ static void memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn, ...@@ -479,23 +480,40 @@ static void memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn,
pfn -= bb->start_pfn; pfn -= bb->start_pfn;
*bit_nr = pfn % BM_BITS_PER_CHUNK; *bit_nr = pfn % BM_BITS_PER_CHUNK;
*addr = bb->data + pfn / BM_BITS_PER_CHUNK; *addr = bb->data + pfn / BM_BITS_PER_CHUNK;
return 0;
} }
static void memory_bm_set_bit(struct memory_bitmap *bm, unsigned long pfn) static void memory_bm_set_bit(struct memory_bitmap *bm, unsigned long pfn)
{ {
void *addr; void *addr;
unsigned int bit; unsigned int bit;
int error;
memory_bm_find_bit(bm, pfn, &addr, &bit); error = memory_bm_find_bit(bm, pfn, &addr, &bit);
BUG_ON(error);
set_bit(bit, addr); set_bit(bit, addr);
} }
static int mem_bm_set_bit_check(struct memory_bitmap *bm, unsigned long pfn)
{
void *addr;
unsigned int bit;
int error;
error = memory_bm_find_bit(bm, pfn, &addr, &bit);
if (!error)
set_bit(bit, addr);
return error;
}
static void memory_bm_clear_bit(struct memory_bitmap *bm, unsigned long pfn) static void memory_bm_clear_bit(struct memory_bitmap *bm, unsigned long pfn)
{ {
void *addr; void *addr;
unsigned int bit; unsigned int bit;
int error;
memory_bm_find_bit(bm, pfn, &addr, &bit); error = memory_bm_find_bit(bm, pfn, &addr, &bit);
BUG_ON(error);
clear_bit(bit, addr); clear_bit(bit, addr);
} }
...@@ -503,8 +521,10 @@ static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn) ...@@ -503,8 +521,10 @@ static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn)
{ {
void *addr; void *addr;
unsigned int bit; unsigned int bit;
int error;
memory_bm_find_bit(bm, pfn, &addr, &bit); error = memory_bm_find_bit(bm, pfn, &addr, &bit);
BUG_ON(error);
return test_bit(bit, addr); return test_bit(bit, addr);
} }
...@@ -709,8 +729,15 @@ static void mark_nosave_pages(struct memory_bitmap *bm) ...@@ -709,8 +729,15 @@ static void mark_nosave_pages(struct memory_bitmap *bm)
region->end_pfn << PAGE_SHIFT); region->end_pfn << PAGE_SHIFT);
for (pfn = region->start_pfn; pfn < region->end_pfn; pfn++) for (pfn = region->start_pfn; pfn < region->end_pfn; pfn++)
if (pfn_valid(pfn)) if (pfn_valid(pfn)) {
memory_bm_set_bit(bm, pfn); /*
* It is safe to ignore the result of
* mem_bm_set_bit_check() here, since we won't
* touch the PFNs for which the error is
* returned anyway.
*/
mem_bm_set_bit_check(bm, pfn);
}
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment