From 6d2781310036a8d3fa2b590a6f83a298010fd64a Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 30 Apr 2009 09:35:37 -0600 Subject: ACPI: allow drivers to request both device and system notify events System notify events (0x00-0x7f) are common across all device types and should be handled in Linux/ACPI, not in drivers. However, some BIOSes use system notify events in device-specific ways that require the driver to be involved. This patch adds a ACPI_DRIVER_ALL_NOTIFY_EVENTS driver flag. When a driver sets this flag and supplies a .notify method, Linux/ACPI calls the .notify method for ALL notify events on the device, not just the device-specific (0x80-0xff) events. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/bus.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index ae862f1798d..cdfecc0a2ac 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -549,6 +549,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) { int result = 0; struct acpi_device *device = NULL; + struct acpi_driver *driver; blocking_notifier_call_chain(&acpi_bus_notify_list, type, (void *)handle); @@ -629,7 +630,10 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) break; } - return; + driver = device->driver; + if (driver && driver->ops.notify && + (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) + driver->ops.notify(device, type); } /* -------------------------------------------------------------------------- -- cgit v1.2.3 From 48fe112744d1ff2e899a6491633ac58a3229aabf Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 30 Apr 2009 09:35:42 -0600 Subject: ACPI: ac: use .notify method instead of installing handler directly This patch adds a .notify() method. The presence of .notify() causes Linux/ACPI to manage event handlers and notify handlers on our behalf, so we don't have to install and remove them ourselves. This driver apparently relies on seeing ALL notify events, not just device-specific ones (because it used ACPI_ALL_NOTIFY). We use the ACPI_DRIVER_ALL_NOTIFY_EVENTS driver flag to request all events. Signed-off-by: Bjorn Helgaas CC: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/ac.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 88e42abf5d8..0df8fcb687d 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -61,6 +61,7 @@ static int acpi_ac_open_fs(struct inode *inode, struct file *file); static int acpi_ac_add(struct acpi_device *device); static int acpi_ac_remove(struct acpi_device *device, int type); static int acpi_ac_resume(struct acpi_device *device); +static void acpi_ac_notify(struct acpi_device *device, u32 event); static const struct acpi_device_id ac_device_ids[] = { {"ACPI0003", 0}, @@ -72,10 +73,12 @@ static struct acpi_driver acpi_ac_driver = { .name = "ac", .class = ACPI_AC_CLASS, .ids = ac_device_ids, + .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, .ops = { .add = acpi_ac_add, .remove = acpi_ac_remove, .resume = acpi_ac_resume, + .notify = acpi_ac_notify, }, }; @@ -220,16 +223,14 @@ static int acpi_ac_remove_fs(struct acpi_device *device) Driver Model -------------------------------------------------------------------------- */ -static void acpi_ac_notify(acpi_handle handle, u32 event, void *data) +static void acpi_ac_notify(struct acpi_device *device, u32 event) { - struct acpi_ac *ac = data; - struct acpi_device *device = NULL; + struct acpi_ac *ac = acpi_driver_data(device); if (!ac) return; - device = ac->device; switch (event) { default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -253,7 +254,6 @@ static void acpi_ac_notify(acpi_handle handle, u32 event, void *data) static int acpi_ac_add(struct acpi_device *device) { int result = 0; - acpi_status status = AE_OK; struct acpi_ac *ac = NULL; @@ -286,13 +286,6 @@ static int acpi_ac_add(struct acpi_device *device) ac->charger.get_property = get_ac_property; power_supply_register(&ac->device->dev, &ac->charger); #endif - status = acpi_install_notify_handler(device->handle, - ACPI_ALL_NOTIFY, acpi_ac_notify, - ac); - if (ACPI_FAILURE(status)) { - result = -ENODEV; - goto end; - } printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device), acpi_device_bid(device), @@ -328,7 +321,6 @@ static int acpi_ac_resume(struct acpi_device *device) static int acpi_ac_remove(struct acpi_device *device, int type) { - acpi_status status = AE_OK; struct acpi_ac *ac = NULL; @@ -337,8 +329,6 @@ static int acpi_ac_remove(struct acpi_device *device, int type) ac = acpi_driver_data(device); - status = acpi_remove_notify_handler(device->handle, - ACPI_ALL_NOTIFY, acpi_ac_notify); #ifdef CONFIG_ACPI_SYSFS_POWER if (ac->charger.dev) power_supply_unregister(&ac->charger); -- cgit v1.2.3 From d94066910943837558d2a461c6766da981260bf0 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 30 Apr 2009 09:35:47 -0600 Subject: ACPI: battery: use .notify method instead of installing handler directly This patch adds a .notify() method. The presence of .notify() causes Linux/ACPI to manage event handlers and notify handlers on our behalf, so we don't have to install and remove them ourselves. This driver apparently relies on seeing ALL notify events, not just device-specific ones (because it used ACPI_ALL_NOTIFY). We use the ACPI_DRIVER_ALL_NOTIFY_EVENTS driver flag to request all events. Signed-off-by: Bjorn Helgaas CC: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/battery.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index b0de6312919..eb00c4e3747 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -796,13 +796,12 @@ static void acpi_battery_remove_fs(struct acpi_device *device) Driver Interface -------------------------------------------------------------------------- */ -static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) +static void acpi_battery_notify(struct acpi_device *device, u32 event) { - struct acpi_battery *battery = data; - struct acpi_device *device; + struct acpi_battery *battery = acpi_driver_data(device); + if (!battery) return; - device = battery->device; acpi_battery_update(battery); acpi_bus_generate_proc_event(device, event, acpi_battery_present(battery)); @@ -819,7 +818,6 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) static int acpi_battery_add(struct acpi_device *device) { int result = 0; - acpi_status status = 0; struct acpi_battery *battery = NULL; if (!device) return -EINVAL; @@ -837,14 +835,6 @@ static int acpi_battery_add(struct acpi_device *device) if (result) goto end; #endif - status = acpi_install_notify_handler(device->handle, - ACPI_ALL_NOTIFY, - acpi_battery_notify, battery); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler")); - result = -ENODEV; - goto end; - } printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), device->status.battery_present ? "present" : "absent"); @@ -860,15 +850,11 @@ static int acpi_battery_add(struct acpi_device *device) static int acpi_battery_remove(struct acpi_device *device, int type) { - acpi_status status = 0; struct acpi_battery *battery = NULL; if (!device || !acpi_driver_data(device)) return -EINVAL; battery = acpi_driver_data(device); - status = acpi_remove_notify_handler(device->handle, - ACPI_ALL_NOTIFY, - acpi_battery_notify); #ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_remove_fs(device); #endif @@ -896,10 +882,12 @@ static struct acpi_driver acpi_battery_driver = { .name = "battery", .class = ACPI_BATTERY_CLASS, .ids = battery_device_ids, + .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, .ops = { .add = acpi_battery_add, .resume = acpi_battery_resume, .remove = acpi_battery_remove, + .notify = acpi_battery_notify, }, }; -- cgit v1.2.3 From 02c37bd8d0737c31caaed9a65bd7cb80aefb4c9a Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 22 May 2009 11:43:41 -0600 Subject: ACPI: simplify notification debug messages This replaces several messages that depend on the acpi_device struct with a single message that uses just the acpi_handle. We should be able to deal with notifications to objects that do not yet have an acpi_device struct. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/bus.c | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index cdfecc0a2ac..eb986385c57 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -551,6 +551,9 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) struct acpi_device *device = NULL; struct acpi_driver *driver; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n", + type, handle)); + blocking_notifier_call_chain(&acpi_bus_notify_list, type, (void *)handle); @@ -560,9 +563,6 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) switch (type) { case ACPI_NOTIFY_BUS_CHECK: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received BUS CHECK notification for device [%s]\n", - device->pnp.bus_id)); result = acpi_bus_check_scope(device); /* * TBD: We'll need to outsource certain events to non-ACPI @@ -571,9 +571,6 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) break; case ACPI_NOTIFY_DEVICE_CHECK: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received DEVICE CHECK notification for device [%s]\n", - device->pnp.bus_id)); result = acpi_bus_check_device(device, NULL); /* * TBD: We'll need to outsource certain events to non-ACPI @@ -582,44 +579,26 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) break; case ACPI_NOTIFY_DEVICE_WAKE: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received DEVICE WAKE notification for device [%s]\n", - device->pnp.bus_id)); /* TBD */ break; case ACPI_NOTIFY_EJECT_REQUEST: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received EJECT REQUEST notification for device [%s]\n", - device->pnp.bus_id)); /* TBD */ break; case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received DEVICE CHECK LIGHT notification for device [%s]\n", - device->pnp.bus_id)); /* TBD: Exactly what does 'light' mean? */ break; case ACPI_NOTIFY_FREQUENCY_MISMATCH: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received FREQUENCY MISMATCH notification for device [%s]\n", - device->pnp.bus_id)); /* TBD */ break; case ACPI_NOTIFY_BUS_MODE_MISMATCH: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received BUS MODE MISMATCH notification for device [%s]\n", - device->pnp.bus_id)); /* TBD */ break; case ACPI_NOTIFY_POWER_FAULT: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received POWER FAULT notification for device [%s]\n", - device->pnp.bus_id)); /* TBD */ break; -- cgit v1.2.3 From aa8a149c0cc822e3886eb85b95cb2f7d67e5b7e6 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 22 May 2009 11:43:46 -0600 Subject: ACPI: remove unused "status_changed" return value from Check Device handling Remove "status_changed" return from acpi_bus_check_device(). Nobody does anything useful based on its value. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/bus.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index eb986385c57..19e78fb0a8d 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -450,8 +450,7 @@ int acpi_bus_receive_event(struct acpi_bus_event *event) Notification Handling -------------------------------------------------------------------------- */ -static int -acpi_bus_check_device(struct acpi_device *device, int *status_changed) +static int acpi_bus_check_device(struct acpi_device *device) { acpi_status status = 0; struct acpi_device_status old_status; @@ -460,9 +459,6 @@ acpi_bus_check_device(struct acpi_device *device, int *status_changed) if (!device) return -EINVAL; - if (status_changed) - *status_changed = 0; - old_status = device->status; /* @@ -471,10 +467,6 @@ acpi_bus_check_device(struct acpi_device *device, int *status_changed) */ if (device->parent && !device->parent->status.present) { device->status = device->parent->status; - if (STRUCT_TO_INT(old_status) != STRUCT_TO_INT(device->status)) { - if (status_changed) - *status_changed = 1; - } return 0; } @@ -485,9 +477,6 @@ acpi_bus_check_device(struct acpi_device *device, int *status_changed) if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status)) return 0; - if (status_changed) - *status_changed = 1; - /* * Device Insertion/Removal */ @@ -505,20 +494,15 @@ acpi_bus_check_device(struct acpi_device *device, int *status_changed) static int acpi_bus_check_scope(struct acpi_device *device) { int result = 0; - int status_changed = 0; - if (!device) return -EINVAL; /* Status Change? */ - result = acpi_bus_check_device(device, &status_changed); + result = acpi_bus_check_device(device); if (result) return result; - if (!status_changed) - return 0; - /* * TBD: Enumerate child devices within this device's scope and * run acpi_bus_check_device()'s on them. @@ -571,7 +555,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) break; case ACPI_NOTIFY_DEVICE_CHECK: - result = acpi_bus_check_device(device, NULL); + result = acpi_bus_check_device(device); /* * TBD: We'll need to outsource certain events to non-ACPI * drivers via the device manager (device.c). -- cgit v1.2.3 From cdd5b8ca122cc4239375dee7fcdc658315c119e4 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 22 May 2009 11:43:51 -0600 Subject: ACPI: remove unused return values from Bus Check & Device Check handling Remove return values from acpi_bus_check_device() and acpi_bus_check_scope() since nobody looks at them. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/bus.c | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 19e78fb0a8d..2b08c3dc79d 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -450,14 +450,13 @@ int acpi_bus_receive_event(struct acpi_bus_event *event) Notification Handling -------------------------------------------------------------------------- */ -static int acpi_bus_check_device(struct acpi_device *device) +static void acpi_bus_check_device(struct acpi_device *device) { - acpi_status status = 0; + acpi_status status; struct acpi_device_status old_status; - if (!device) - return -EINVAL; + return; old_status = device->status; @@ -467,15 +466,15 @@ static int acpi_bus_check_device(struct acpi_device *device) */ if (device->parent && !device->parent->status.present) { device->status = device->parent->status; - return 0; + return; } status = acpi_bus_get_status(device); if (ACPI_FAILURE(status)) - return -ENODEV; + return; if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status)) - return 0; + return; /* * Device Insertion/Removal @@ -487,28 +486,20 @@ static int acpi_bus_check_device(struct acpi_device *device) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device removal detected\n")); /* TBD: Handle device removal */ } - - return 0; } -static int acpi_bus_check_scope(struct acpi_device *device) +static void acpi_bus_check_scope(struct acpi_device *device) { - int result = 0; - if (!device) - return -EINVAL; + return; /* Status Change? */ - result = acpi_bus_check_device(device); - if (result) - return result; + acpi_bus_check_device(device); /* * TBD: Enumerate child devices within this device's scope and * run acpi_bus_check_device()'s on them. */ - - return 0; } static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list); @@ -531,7 +522,6 @@ EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier); */ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) { - int result = 0; struct acpi_device *device = NULL; struct acpi_driver *driver; @@ -547,7 +537,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) switch (type) { case ACPI_NOTIFY_BUS_CHECK: - result = acpi_bus_check_scope(device); + acpi_bus_check_scope(device); /* * TBD: We'll need to outsource certain events to non-ACPI * drivers via the device manager (device.c). @@ -555,7 +545,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) break; case ACPI_NOTIFY_DEVICE_CHECK: - result = acpi_bus_check_device(device); + acpi_bus_check_device(device); /* * TBD: We'll need to outsource certain events to non-ACPI * drivers via the device manager (device.c). -- cgit v1.2.3 From ff754e2e85557ed7244385f0f2053c80e8ac9948 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 22 May 2009 11:43:56 -0600 Subject: ACPI: use handle, not device, in system notification path This patch changes the global system notification path so it uses the acpi_handle, not the acpi_device. System notifications often deal with device presence and status change. In these cases, we may not have an acpi_device. For example, we may get a Device Check notification on an object that previously was not present. Since the object was not present, we would not have had an acpi_device for it. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/bus.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 2b08c3dc79d..2876fc70c3a 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -450,11 +450,14 @@ int acpi_bus_receive_event(struct acpi_bus_event *event) Notification Handling -------------------------------------------------------------------------- */ -static void acpi_bus_check_device(struct acpi_device *device) +static void acpi_bus_check_device(acpi_handle handle) { + struct acpi_device *device; acpi_status status; struct acpi_device_status old_status; + if (acpi_bus_get_device(handle, &device)) + return; if (!device) return; @@ -488,13 +491,10 @@ static void acpi_bus_check_device(struct acpi_device *device) } } -static void acpi_bus_check_scope(struct acpi_device *device) +static void acpi_bus_check_scope(acpi_handle handle) { - if (!device) - return; - /* Status Change? */ - acpi_bus_check_device(device); + acpi_bus_check_device(handle); /* * TBD: Enumerate child devices within this device's scope and @@ -531,13 +531,10 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) blocking_notifier_call_chain(&acpi_bus_notify_list, type, (void *)handle); - if (acpi_bus_get_device(handle, &device)) - return; - switch (type) { case ACPI_NOTIFY_BUS_CHECK: - acpi_bus_check_scope(device); + acpi_bus_check_scope(handle); /* * TBD: We'll need to outsource certain events to non-ACPI * drivers via the device manager (device.c). @@ -545,7 +542,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) break; case ACPI_NOTIFY_DEVICE_CHECK: - acpi_bus_check_device(device); + acpi_bus_check_device(handle); /* * TBD: We'll need to outsource certain events to non-ACPI * drivers via the device manager (device.c). @@ -583,10 +580,13 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) break; } - driver = device->driver; - if (driver && driver->ops.notify && - (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) - driver->ops.notify(device, type); + acpi_bus_get_device(handle, &device); + if (device) { + driver = device->driver; + if (driver && driver->ops.notify && + (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) + driver->ops.notify(device, type); + } } /* -------------------------------------------------------------------------- -- cgit v1.2.3 From 586caae36cece718ff46b3a59b88af79e9f7a2e0 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Thu, 18 Jun 2009 00:38:27 -0400 Subject: ACPI: battery: fix CONFIG_ACPI_PROCFS_POWER=n build warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/acpi/battery.c:841: warning: label ‘end’ defined but not used Signed-off-by: Len Brown --- drivers/acpi/battery.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index eb00c4e3747..58b4517ce71 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -832,14 +832,12 @@ static int acpi_battery_add(struct acpi_device *device) acpi_battery_update(battery); #ifdef CONFIG_ACPI_PROCFS_POWER result = acpi_battery_add_fs(device); - if (result) - goto end; #endif - printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", - ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), - device->status.battery_present ? "present" : "absent"); - end: - if (result) { + if (!result) { + printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", + ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), + device->status.battery_present ? "present" : "absent"); + } else { #ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_remove_fs(device); #endif -- cgit v1.2.3