summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/bus.c53
-rw-r--r--drivers/acpi/pci_link.c4
-rw-r--r--drivers/acpi/power.c68
-rw-r--r--drivers/acpi/processor_perflib.c18
-rw-r--r--drivers/acpi/scan.c62
-rw-r--r--drivers/acpi/wmi.c49
-rw-r--r--drivers/misc/Kconfig1
-rw-r--r--drivers/misc/acer-wmi.c225
-rw-r--r--drivers/pnp/pnpacpi/core.c6
9 files changed, 329 insertions, 157 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index ccae305ee55..e9b116d2b56 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -48,6 +48,23 @@ EXPORT_SYMBOL(acpi_root_dir);
#define STRUCT_TO_INT(s) (*((int*)&s))
+static int set_power_nocheck(const struct dmi_system_id *id)
+{
+ printk(KERN_NOTICE PREFIX "%s detected - "
+ "disable power check in power transistion\n", id->ident);
+ acpi_power_nocheck = 1;
+ return 0;
+}
+static struct dmi_system_id __cpuinitdata power_nocheck_dmi_table[] = {
+ {
+ set_power_nocheck, "HP Pavilion 05", {
+ DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+ DMI_MATCH(DMI_SYS_VENDOR, "HP Pavilion 05"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "2001211RE101GLEND") }, NULL},
+ {},
+};
+
+
/* --------------------------------------------------------------------------
Device Management
-------------------------------------------------------------------------- */
@@ -95,21 +112,21 @@ int acpi_bus_get_status(struct acpi_device *device)
}
/*
- * Otherwise we assume the status of our parent (unless we don't
- * have one, in which case status is implied).
+ * According to ACPI spec some device can be present and functional
+ * even if the parent is not present but functional.
+ * In such conditions the child device should not inherit the status
+ * from the parent.
*/
- else if (device->parent)
- device->status = device->parent->status;
else
STRUCT_TO_INT(device->status) =
ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING;
if (device->status.functional && !device->status.present) {
- printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: "
- "functional but not present; setting present\n",
- device->pnp.bus_id, (u32) STRUCT_TO_INT(device->status));
- device->status.present = 1;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: "
+ "functional but not present;\n",
+ device->pnp.bus_id,
+ (u32) STRUCT_TO_INT(device->status)));
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n",
@@ -223,7 +240,19 @@ int acpi_bus_set_power(acpi_handle handle, int state)
/*
* Get device's current power state
*/
- acpi_bus_get_power(device->handle, &device->power.state);
+ if (!acpi_power_nocheck) {
+ /*
+ * Maybe the incorrect power state is returned on the bogus
+ * bios, which is different with the real power state.
+ * For example: the bios returns D0 state and the real power
+ * state is D3. OS expects to set the device to D0 state. In
+ * such case if OS uses the power state returned by the BIOS,
+ * the device can't be transisted to the correct power state.
+ * So if the acpi_power_nocheck is set, it is unnecessary to
+ * get the power state by calling acpi_bus_get_power.
+ */
+ acpi_bus_get_power(device->handle, &device->power.state);
+ }
if ((state == device->power.state) && !device->flags.force_power_state) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
state));
@@ -818,7 +847,11 @@ static int __init acpi_init(void)
}
} else
disable_acpi();
-
+ /*
+ * If the laptop falls into the DMI check table, the power state check
+ * will be disabled in the course of device power transistion.
+ */
+ dmi_check_system(power_nocheck_dmi_table);
return result;
}
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index cf47805a744..65bf4fa5963 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -709,7 +709,7 @@ int acpi_pci_link_free_irq(acpi_handle handle)
acpi_device_bid(link->device)));
if (link->refcnt == 0) {
- acpi_ut_evaluate_object(link->device->handle, "_DIS", 0, NULL);
+ acpi_evaluate_object(link->device->handle, "_DIS", NULL, NULL);
}
mutex_unlock(&acpi_link_lock);
return (link->irq.active);
@@ -773,7 +773,7 @@ static int acpi_pci_link_add(struct acpi_device *device)
end:
/* disable all links -- to be activated on use */
- acpi_ut_evaluate_object(device->handle, "_DIS", 0, NULL);
+ acpi_evaluate_object(device->handle, "_DIS", NULL, NULL);
mutex_unlock(&acpi_link_lock);
if (result)
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 4ab21cb1c8c..7ff7349c0c5 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -54,6 +54,14 @@ ACPI_MODULE_NAME("power");
#define ACPI_POWER_RESOURCE_STATE_OFF 0x00
#define ACPI_POWER_RESOURCE_STATE_ON 0x01
#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
+
+#ifdef MODULE_PARAM_PREFIX
+#undef MODULE_PARAM_PREFIX
+#endif
+#define MODULE_PARAM_PREFIX "acpi."
+int acpi_power_nocheck;
+module_param_named(power_nocheck, acpi_power_nocheck, bool, 000);
+
static int acpi_power_add(struct acpi_device *device);
static int acpi_power_remove(struct acpi_device *device, int type);
static int acpi_power_resume(struct acpi_device *device);
@@ -128,16 +136,16 @@ acpi_power_get_context(acpi_handle handle,
return 0;
}
-static int acpi_power_get_state(struct acpi_power_resource *resource, int *state)
+static int acpi_power_get_state(acpi_handle handle, int *state)
{
acpi_status status = AE_OK;
unsigned long sta = 0;
- if (!resource || !state)
+ if (!handle || !state)
return -EINVAL;
- status = acpi_evaluate_integer(resource->device->handle, "_STA", NULL, &sta);
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status))
return -ENODEV;
@@ -145,7 +153,7 @@ static int acpi_power_get_state(struct acpi_power_resource *resource, int *state
ACPI_POWER_RESOURCE_STATE_OFF;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n",
- resource->name, state ? "on" : "off"));
+ acpi_ut_get_node_name(handle), state ? "on" : "off"));
return 0;
}
@@ -153,7 +161,6 @@ static int acpi_power_get_state(struct acpi_power_resource *resource, int *state
static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
{
int result = 0, state1;
- struct acpi_power_resource *resource = NULL;
u32 i = 0;
@@ -161,12 +168,15 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
return -EINVAL;
/* The state of the list is 'on' IFF all resources are 'on'. */
+ /* */
for (i = 0; i < list->count; i++) {
- result = acpi_power_get_context(list->handles[i], &resource);
- if (result)
- return result;
- result = acpi_power_get_state(resource, &state1);
+ /*
+ * The state of the power resource can be obtained by
+ * using the ACPI handle. In such case it is unnecessary to
+ * get the Power resource first and then get its state again.
+ */
+ result = acpi_power_get_state(list->handles[i], &state1);
if (result)
return result;
@@ -226,12 +236,18 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
if (ACPI_FAILURE(status))
return -ENODEV;
- result = acpi_power_get_state(resource, &state);
- if (result)
- return result;
- if (state != ACPI_POWER_RESOURCE_STATE_ON)
- return -ENOEXEC;
-
+ if (!acpi_power_nocheck) {
+ /*
+ * If acpi_power_nocheck is set, it is unnecessary to check
+ * the power state after power transition.
+ */
+ result = acpi_power_get_state(resource->device->handle,
+ &state);
+ if (result)
+ return result;
+ if (state != ACPI_POWER_RESOURCE_STATE_ON)
+ return -ENOEXEC;
+ }
/* Update the power resource's _device_ power state */
resource->device->power.state = ACPI_STATE_D0;
@@ -277,11 +293,17 @@ static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev)
if (ACPI_FAILURE(status))
return -ENODEV;
- result = acpi_power_get_state(resource, &state);
- if (result)
- return result;
- if (state != ACPI_POWER_RESOURCE_STATE_OFF)
- return -ENOEXEC;
+ if (!acpi_power_nocheck) {
+ /*
+ * If acpi_power_nocheck is set, it is unnecessary to check
+ * the power state after power transition.
+ */
+ result = acpi_power_get_state(handle, &state);
+ if (result)
+ return result;
+ if (state != ACPI_POWER_RESOURCE_STATE_OFF)
+ return -ENOEXEC;
+ }
/* Update the power resource's _device_ power state */
resource->device->power.state = ACPI_STATE_D3;
@@ -555,7 +577,7 @@ static int acpi_power_seq_show(struct seq_file *seq, void *offset)
if (!resource)
goto end;
- result = acpi_power_get_state(resource, &state);
+ result = acpi_power_get_state(resource->device->handle, &state);
if (result)
goto end;
@@ -668,7 +690,7 @@ static int acpi_power_add(struct acpi_device *device)
resource->system_level = acpi_object.power_resource.system_level;
resource->order = acpi_object.power_resource.resource_order;
- result = acpi_power_get_state(resource, &state);
+ result = acpi_power_get_state(device->handle, &state);
if (result)
goto end;
@@ -735,7 +757,7 @@ static int acpi_power_resume(struct acpi_device *device)
resource = (struct acpi_power_resource *)acpi_driver_data(device);
- result = acpi_power_get_state(resource, &state);
+ result = acpi_power_get_state(device->handle, &state);
if (result)
return result;
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index e5c457b45f2..b0614f37947 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -38,6 +38,7 @@
#include <asm/uaccess.h>
#endif
+#include <asm/cpufeature.h>
#include <acpi/acpi_bus.h>
#include <acpi/processor.h>
@@ -334,7 +335,6 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr)
acpi_status status = AE_OK;
acpi_handle handle = NULL;
-
if (!pr || !pr->performance || !pr->handle)
return -EINVAL;
@@ -347,13 +347,25 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr)
result = acpi_processor_get_performance_control(pr);
if (result)
- return result;
+ goto update_bios;
result = acpi_processor_get_performance_states(pr);
if (result)
- return result;
+ goto update_bios;
return 0;
+
+ /*
+ * Having _PPC but missing frequencies (_PSS, _PCT) is a very good hint that
+ * the BIOS is older than the CPU and does not know its frequencies
+ */
+ update_bios:
+ if (ACPI_SUCCESS(acpi_get_handle(pr->handle, "_PPC", &handle))){
+ if(boot_cpu_has(X86_FEATURE_EST))
+ printk(KERN_WARNING FW_BUG "BIOS needs update for CPU "
+ "frequency support\n");
+ }
+ return result;
}
int acpi_processor_notify_smm(struct module *calling_module)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 81d6095468f..1f98103b53c 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -276,6 +276,13 @@ int acpi_match_device_ids(struct acpi_device *device,
{
const struct acpi_device_id *id;
+ /*
+ * If the device is not present, it is unnecessary to load device
+ * driver for it.
+ */
+ if (!device->status.present)
+ return -ENODEV;
+
if (device->flags.hardware_id) {
for (id = ids; id->id[0]; id++) {
if (!strcmp((char*)id->id, device->pnp.hardware_id))
@@ -807,6 +814,7 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
/* TBD: System wake support and resource requirements. */
device->power.state = ACPI_STATE_UNKNOWN;
+ acpi_bus_get_power(device->handle, &(device->power.state));
return 0;
}
@@ -1153,20 +1161,6 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
}
static int
-acpi_is_child_device(struct acpi_device *device,
- int (*matcher)(struct acpi_device *))
-{
- int result = -ENODEV;
-
- do {
- if (ACPI_SUCCESS(matcher(device)))
- return AE_OK;
- } while ((device = device->parent));
-
- return result;
-}
-
-static int
acpi_add_single_object(struct acpi_device **child,
struct acpi_device *parent, acpi_handle handle, int type,
struct acpi_bus_ops *ops)
@@ -1221,15 +1215,18 @@ acpi_add_single_object(struct acpi_device **child,
result = -ENODEV;
goto end;
}
- if (!device->status.present) {
- /* Bay and dock should be handled even if absent */
- if (!ACPI_SUCCESS(
- acpi_is_child_device(device, acpi_bay_match)) &&
- !ACPI_SUCCESS(
- acpi_is_child_device(device, acpi_dock_match))) {
- result = -ENODEV;
- goto end;
- }
+ /*
+ * When the device is neither present nor functional, the
+ * device should not be added to Linux ACPI device tree.
+ * When the status of the device is not present but functinal,
+ * it should be added to Linux ACPI tree. For example : bay
+ * device , dock device.
+ * In such conditions it is unncessary to check whether it is
+ * bay device or dock device.
+ */
+ if (!device->status.present && !device->status.functional) {
+ result = -ENODEV;
+ goto end;
}
break;
default:
@@ -1252,6 +1249,16 @@ acpi_add_single_object(struct acpi_device **child,
acpi_device_set_id(device, parent, handle, type);
/*
+ * The ACPI device is attached to acpi handle before getting
+ * the power/wakeup/peformance flags. Otherwise OS can't get
+ * the corresponding ACPI device by the acpi handle in the course
+ * of getting the power/wakeup/performance flags.
+ */
+ result = acpi_device_set_context(device, type);
+ if (result)
+ goto end;
+
+ /*
* Power Management
* ----------------
*/
@@ -1281,8 +1288,6 @@ acpi_add_single_object(struct acpi_device **child,
goto end;
}
- if ((result = acpi_device_set_context(device, type)))
- goto end;
result = acpi_device_register(device, parent);
@@ -1402,7 +1407,12 @@ static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops)
* TBD: Need notifications and other detection mechanisms
* in place before we can fully implement this.
*/
- if (child->status.present) {
+ /*
+ * When the device is not present but functional, it is also
+ * necessary to scan the children of this device.
+ */
+ if (child->status.present || (!child->status.present &&
+ child->status.functional)) {
status = acpi_get_next_object(ACPI_TYPE_ANY, chandle,
NULL, NULL);
if (ACPI_SUCCESS(status)) {
diff --git a/drivers/acpi/wmi.c b/drivers/acpi/wmi.c
index cfe2c833474..47cd7baf9b1 100644
--- a/drivers/acpi/wmi.c
+++ b/drivers/acpi/wmi.c
@@ -217,6 +217,35 @@ static bool find_guid(const char *guid_string, struct wmi_block **out)
return 0;
}
+static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
+{
+ struct guid_block *block = NULL;
+ char method[5];
+ struct acpi_object_list input;
+ union acpi_object params[1];
+ acpi_status status;
+ acpi_handle handle;
+
+ block = &wblock->gblock;
+ handle = wblock->handle;
+
+ if (!block)
+ return AE_NOT_EXIST;
+
+ input.count = 1;
+ input.pointer = params;
+ params[0].type = ACPI_TYPE_INTEGER;
+ params[0].integer.value = enable;
+
+ snprintf(method, 5, "WE%02X", block->notify_id);
+ status = acpi_evaluate_object(handle, method, &input, NULL);
+
+ if (status != AE_OK && status != AE_NOT_FOUND)
+ return status;
+ else
+ return AE_OK;
+}
+
/*
* Exported WMI functions
*/
@@ -242,7 +271,7 @@ u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
char method[4] = "WM";
if (!find_guid(guid_string, &wblock))
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
block = &wblock->gblock;
handle = wblock->handle;
@@ -304,7 +333,7 @@ struct acpi_buffer *out)
return AE_BAD_PARAMETER;
if (!find_guid(guid_string, &wblock))
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
block = &wblock->gblock;
handle = wblock->handle;
@@ -314,7 +343,7 @@ struct acpi_buffer *out)
/* Check GUID is a data block */
if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
input.count = 1;
input.pointer = wq_params;
@@ -385,7 +414,7 @@ const struct acpi_buffer *in)
return AE_BAD_DATA;
if (!find_guid(guid_string, &wblock))
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
block = &wblock->gblock;
handle = wblock->handle;
@@ -395,7 +424,7 @@ const struct acpi_buffer *in)
/* Check GUID is a data block */
if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
input.count = 2;
input.pointer = params;
@@ -427,6 +456,7 @@ acpi_status wmi_install_notify_handler(const char *guid,
wmi_notify_handler handler, void *data)
{
struct wmi_block *block;
+ acpi_status status;
if (!guid || !handler)
return AE_BAD_PARAMETER;
@@ -441,7 +471,9 @@ wmi_notify_handler handler, void *data)
block->handler = handler;
block->handler_data = data;
- return AE_OK;
+ status = wmi_method_enable(block, 1);
+
+ return status;
}
EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
@@ -453,6 +485,7 @@ EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
acpi_status wmi_remove_notify_handler(const char *guid)
{
struct wmi_block *block;
+ acpi_status status;
if (!guid)
return AE_BAD_PARAMETER;
@@ -464,10 +497,12 @@ acpi_status wmi_remove_notify_handler(const char *guid)
if (!block->handler)
return AE_NULL_ENTRY;
+ status = wmi_method_enable(block, 0);
+
block->handler = NULL;
block->handler_data = NULL;
- return AE_OK;
+ return status;
}
EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index a726f3b01a6..6abb95919c3 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -145,6 +145,7 @@ config ACER_WMI
depends on NEW_LEDS
depends on BACKLIGHT_CLASS_DEVICE
depends on SERIO_I8042
+ depends on RFKILL
select ACPI_WMI
---help---
This is a driver for newer Acer (and Wistron) laptops. It adds
diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c
index d8b0d326e45..0532a2de2ce 100644
--- a/drivers/misc/acer-wmi.c
+++ b/drivers/misc/acer-wmi.c
@@ -33,6 +33,8 @@
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/i8042.h>
+#include <linux/rfkill.h>
+#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <acpi/acpi_drivers.h>
@@ -123,21 +125,15 @@ enum interface_flags {
static int max_brightness = 0xF;
-static int wireless = -1;
-static int bluetooth = -1;
static int mailled = -1;
static int brightness = -1;
static int threeg = -1;
static int force_series;
module_param(mailled, int, 0444);
-module_param(wireless, int, 0444);
-module_param(bluetooth, int, 0444);
module_param(brightness, int, 0444);
module_param(threeg, int, 0444);
module_param(force_series, int, 0444);
-MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware");
-MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware");
MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
@@ -145,8 +141,6 @@ MODULE_PARM_DESC(force_series, "Force a different laptop series");
struct acer_data {
int mailled;
- int wireless;
- int bluetooth;
int threeg;
int brightness;
};
@@ -157,6 +151,9 @@ struct acer_debug {
u32 wmid_devices;
};
+static struct rfkill *wireless_rfkill;
+static struct rfkill *bluetooth_rfkill;
+
/* Each low-level interface must define at least some of the following */
struct wmi_interface {
/* The WMI device type */
@@ -476,7 +473,7 @@ struct wmi_interface *iface)
}
break;
default:
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
}
return AE_OK;
}
@@ -514,7 +511,7 @@ static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
break;
}
default:
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
}
/* Actually do the set */
@@ -689,7 +686,7 @@ struct wmi_interface *iface)
return 0;
}
default:
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
}
status = WMI_execute_u32(method_id, 0, &result);
@@ -735,7 +732,7 @@ static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
}
break;
default:
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
}
return WMI_execute_u32(method_id, (u32)value, NULL);
}
@@ -785,7 +782,7 @@ static struct wmi_interface wmid_interface = {
static acpi_status get_u32(u32 *value, u32 cap)
{
- acpi_status status = AE_BAD_ADDRESS;
+ acpi_status status = AE_ERROR;
switch (interface->type) {
case ACER_AMW0:
@@ -846,8 +843,6 @@ static void __init acer_commandline_init(void)
* capability isn't available on the given interface
*/
set_u32(mailled, ACER_CAP_MAILLED);
- set_u32(wireless, ACER_CAP_WIRELESS);
- set_u32(bluetooth, ACER_CAP_BLUETOOTH);
set_u32(threeg, ACER_CAP_THREEG);
set_u32(brightness, ACER_CAP_BRIGHTNESS);
}
@@ -933,40 +928,135 @@ static void acer_backlight_exit(void)
}
/*
- * Read/ write bool sysfs macro
+ * Rfkill devices
*/
-#define show_set_bool(value, cap) \
-static ssize_t \
-show_bool_##value(struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- u32 result; \
- acpi_status status = get_u32(&result, cap); \
- if (ACPI_SUCCESS(status)) \
- return sprintf(buf, "%u\n", result); \
- return sprintf(buf, "Read error\n"); \
-} \
-\
-static ssize_t \
-set_bool_##value(struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- u32 tmp = simple_strtoul(buf, NULL, 10); \
- acpi_status status = set_u32(tmp, cap); \
- if (ACPI_FAILURE(status)) \
- return -EINVAL; \
- return count; \
-} \
-static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
- show_bool_##value, set_bool_##value);
-
-show_set_bool(wireless, ACER_CAP_WIRELESS);
-show_set_bool(bluetooth, ACER_CAP_BLUETOOTH);
-show_set_bool(threeg, ACER_CAP_THREEG);
+static void acer_rfkill_update(struct work_struct *ignored);
+static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update);
+static void acer_rfkill_update(struct work_struct *ignored)
+{
+ u32 state;
+ acpi_status status;
+
+ status = get_u32(&state, ACER_CAP_WIRELESS);
+ if (ACPI_SUCCESS(status))
+ rfkill_force_state(wireless_rfkill, state ?
+ RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED);
+
+ if (has_cap(ACER_CAP_BLUETOOTH)) {
+ status = get_u32(&state, ACER_CAP_BLUETOOTH);
+ if (ACPI_SUCCESS(status))
+ rfkill_force_state(bluetooth_rfkill, state ?
+ RFKILL_STATE_UNBLOCKED :
+ RFKILL_STATE_SOFT_BLOCKED);
+ }
+
+ schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
+}
+
+static int acer_rfkill_set(void *data, enum rfkill_state state)
+{
+ acpi_status status;
+ u32 *cap = data;
+ status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+ return 0;
+}
+
+static struct rfkill * acer_rfkill_register(struct device *dev,
+enum rfkill_type type, char *name, u32 cap)
+{
+ int err;
+ u32 state;
+ u32 *data;
+ struct rfkill *rfkill_dev;
+
+ rfkill_dev = rfkill_allocate(dev, type);
+ if (!rfkill_dev)
+ return ERR_PTR(-ENOMEM);
+ rfkill_dev->name = name;
+ get_u32(&state, cap);
+ rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED :
+ RFKILL_STATE_SOFT_BLOCKED;
+ data = kzalloc(sizeof(u32), GFP_KERNEL);
+ if (!data) {
+ rfkill_free(rfkill_dev);
+ return ERR_PTR(-ENOMEM);
+ }
+ *data = cap;
+ rfkill_dev->data = data;
+ rfkill_dev->toggle_radio = acer_rfkill_set;
+ rfkill_dev->user_claim_unsupported = 1;
+
+ err = rfkill_register(rfkill_dev);
+ if (err) {
+ kfree(rfkill_dev->data);
+ rfkill_free(rfkill_dev);
+ return ERR_PTR(err);
+ }
+ return rfkill_dev;
+}
+
+static int acer_rfkill_init(struct device *dev)
+{
+ wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
+ "acer-wireless", ACER_CAP_WIRELESS);
+ if (IS_ERR(wireless_rfkill))
+ return PTR_ERR(wireless_rfkill);
+
+ if (has_cap(ACER_CAP_BLUETOOTH)) {
+ bluetooth_rfkill = acer_rfkill_register(dev,
+ RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
+ ACER_CAP_BLUETOOTH);
+ if (IS_ERR(bluetooth_rfkill)) {
+ kfree(wireless_rfkill->data);
+ rfkill_unregister(wireless_rfkill);
+ return PTR_ERR(bluetooth_rfkill);
+ }
+ }
+
+ schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
+
+ return 0;
+}
+
+static void acer_rfkill_exit(void)
+{
+ cancel_delayed_work_sync(&acer_rfkill_work);
+ kfree(wireless_rfkill->data);
+ rfkill_unregister(wireless_rfkill);
+ if (has_cap(ACER_CAP_BLUETOOTH)) {
+ kfree(wireless_rfkill->data);
+ rfkill_unregister(bluetooth_rfkill);
+ }
+ return;
+}
/*
- * Read interface sysfs macro
+ * sysfs interface
*/
+static ssize_t show_bool_threeg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 result; \
+ acpi_status status = get_u32(&result, ACER_CAP_THREEG);
+ if (ACPI_SUCCESS(status))
+ return sprintf(buf, "%u\n", result);
+ return sprintf(buf, "Read error\n");
+}
+
+static ssize_t set_bool_threeg(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ u32 tmp = simple_strtoul(buf, NULL, 10);
+ acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
+ if (ACPI_FAILURE(status))
+ return -EINVAL;
+ return count;
+}
+static DEVICE_ATTR(threeg, S_IWUGO | S_IRUGO | S_IWUSR, show_bool_threeg,
+ set_bool_threeg);
+
static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -1026,7 +1116,9 @@ static int __devinit acer_platform_probe(struct platform_device *device)
goto error_brightness;
}
- return 0;
+ err = acer_rfkill_init(&device->dev);
+
+ return err;
error_brightness:
acer_led_exit();
@@ -1040,6 +1132,8 @@ static int acer_platform_remove(struct platform_device *device)
acer_led_exit();
if (has_cap(ACER_CAP_BRIGHTNESS))
acer_backlight_exit();
+
+ acer_rfkill_exit();
return 0;
}
@@ -1052,16 +1146,6 @@ pm_message_t state)
if (!data)
return -ENOMEM;
- if (has_cap(ACER_CAP_WIRELESS)) {
- get_u32(&value, ACER_CAP_WIRELESS);
- data->wireless = value;
- }
-
- if (has_cap(ACER_CAP_BLUETOOTH)) {
- get_u32(&value, ACER_CAP_BLUETOOTH);
- data->bluetooth = value;
- }
-
if (has_cap(ACER_CAP_MAILLED)) {
get_u32(&value, ACER_CAP_MAILLED);
data->mailled = value;
@@ -1082,15 +1166,6 @@ static int acer_platform_resume(struct platform_device *device)
if (!data)
return -ENOMEM;
- if (has_cap(ACER_CAP_WIRELESS))
- set_u32(data->wireless, ACER_CAP_WIRELESS);
-
- if (has_cap(ACER_CAP_BLUETOOTH))
- set_u32(data->bluetooth, ACER_CAP_BLUETOOTH);
-
- if (has_cap(ACER_CAP_THREEG))
- set_u32(data->threeg, ACER_CAP_THREEG);
-
if (has_cap(ACER_CAP_MAILLED))
set_u32(data->mailled, ACER_CAP_MAILLED);
@@ -1115,12 +1190,6 @@ static struct platform_device *acer_platform_device;
static int remove_sysfs(struct platform_device *device)
{
- if (has_cap(ACER_CAP_WIRELESS))
- device_remove_file(&device->dev, &dev_attr_wireless);
-
- if (has_cap(ACER_CAP_BLUETOOTH))
- device_remove_file(&device->dev, &dev_attr_bluetooth);
-
if (has_cap(ACER_CAP_THREEG))
device_remove_file(&device->dev, &dev_attr_threeg);
@@ -1133,20 +1202,6 @@ static int create_sysfs(void)
{
int retval = -ENOMEM;
- if (has_cap(ACER_CAP_WIRELESS)) {
- retval = device_create_file(&acer_platform_device->dev,
- &dev_attr_wireless);
- if (retval)
- goto error_sysfs;
- }
-
- if (has_cap(ACER_CAP_BLUETOOTH)) {
- retval = device_create_file(&acer_platform_device->dev,
- &dev_attr_bluetooth);
- if (retval)
- goto error_sysfs;
- }
-
if (has_cap(ACER_CAP_THREEG)) {
retval = device_create_file(&acer_platform_device->dev,
&dev_attr_threeg);
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index c1b9ea34977..98b9df7776e 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -148,9 +148,13 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
acpi_status status;
struct pnp_dev *dev;
+ /*
+ * If a PnPacpi device is not present , the device
+ * driver should not be loaded.
+ */
status = acpi_get_handle(device->handle, "_CRS", &temp);
if (ACPI_FAILURE(status) || !ispnpidacpi(acpi_device_hid(device)) ||
- is_exclusive_device(device))
+ is_exclusive_device(device) || (!device->status.present))
return 0;
dev = pnp_alloc_dev(&pnpacpi_protocol, num, acpi_device_hid(device));