From 21bc42ab852549f4a547d18d77e0e4d1b24ffd96 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Tue, 4 Sep 2007 12:49:22 -0400 Subject: ACPI: thermal: use round_jiffies when thermal zone polling is enabled Properly functioning systems do not use thermal zone polling, they use event-based notification. However, some users enable periodic thermal zone polling to work around bugs on their platforms, and at least one platform exists with a real _TZP that requests polling. While thermal zone polling (_TZP) is specified in units to 0.1 seconds, it actually has a maximum granularity of 1 second. Thus, we can safely round up the _TZP timeout to occur on the next 1-second boundary. This will batch it with other 1-second-granularity timers in the system and thus potentially extend processor idle duration. Note that the same timer is used both for _TZP and for passive processor thermal throttling. We can not round up the timeout when it is used for passive thermal throttling. Also, we can not make this a deferrable timer, as temperature is just as relevant during idle as it is during non-idle. Signed-off-by: Len Brown --- drivers/acpi/thermal.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index bc6d586..15d5fdc 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -711,6 +711,7 @@ static void acpi_thermal_check(void *data) int result = 0; struct acpi_thermal *tz = data; unsigned long sleep_time = 0; + unsigned long timeout_jiffies = 0; int i = 0; struct acpi_thermal_state state; @@ -787,10 +788,13 @@ static void acpi_thermal_check(void *data) * a thermal event occurs). Note that _TSP and _TZD values are * given in 1/10th seconds (we must covert to milliseconds). */ - if (tz->state.passive) + if (tz->state.passive) { sleep_time = tz->trips.passive.tsp * 100; - else if (tz->polling_frequency > 0) + timeout_jiffies = jiffies + (HZ * sleep_time) / 1000; + } else if (tz->polling_frequency > 0) { sleep_time = tz->polling_frequency * 100; + timeout_jiffies = round_jiffies(jiffies + (HZ * sleep_time) / 1000); + } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: temperature[%lu] sleep[%lu]\n", tz->name, tz->temperature, sleep_time)); @@ -804,12 +808,11 @@ static void acpi_thermal_check(void *data) del_timer(&(tz->timer)); } else { if (timer_pending(&(tz->timer))) - mod_timer(&(tz->timer), - jiffies + (HZ * sleep_time) / 1000); + mod_timer(&(tz->timer), timeout_jiffies); else { tz->timer.data = (unsigned long)tz; tz->timer.function = acpi_thermal_run; - tz->timer.expires = jiffies + (HZ * sleep_time) / 1000; + tz->timer.expires = timeout_jiffies; add_timer(&(tz->timer)); } } -- cgit v1.1 From 6e2157858ac94530fddbf19dc59ab6b392baf1f3 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Sat, 1 Sep 2007 00:11:59 +0400 Subject: ACPI: Thermal: Drop concurrent thermal checks Fix for #3686, where get_temperature() may cause thermal notify, which causes one more get_temperature(). Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/thermal.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 15d5fdc..69ec73b 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -195,6 +195,7 @@ struct acpi_thermal { struct acpi_thermal_trips trips; struct acpi_handle_list devices; struct timer_list timer; + struct mutex lock; }; static const struct file_operations acpi_thermal_state_fops = { @@ -721,11 +722,15 @@ static void acpi_thermal_check(void *data) return; } + /* Check if someone else is already running */ + if (!mutex_trylock(&tz->lock)) + return; + state = tz->state; result = acpi_thermal_get_temperature(tz); if (result) - return; + goto unlock; memset(&tz->state, 0, sizeof(tz->state)); @@ -816,8 +821,8 @@ static void acpi_thermal_check(void *data) add_timer(&(tz->timer)); } } - - return; + unlock: + mutex_unlock(&tz->lock); } /* -------------------------------------------------------------------------- @@ -1254,7 +1259,7 @@ static int acpi_thermal_add(struct acpi_device *device) strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS); acpi_driver_data(device) = tz; - + mutex_init(&tz->lock); result = acpi_thermal_get_info(tz); if (result) goto end; @@ -1324,7 +1329,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type) } acpi_thermal_remove_fs(device); - + mutex_destroy(&tz->lock); kfree(tz); return 0; } -- cgit v1.1 From 4500ca8e221e72cc38e7c239b9b1a041031ee450 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Mon, 3 Sep 2007 16:29:58 +0400 Subject: ACPI: video: Don't call absent methods Signed-off-by: Ryan May Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/video.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 3c9bb85..83aa41c 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -409,14 +409,16 @@ acpi_video_device_lcd_query_levels(struct acpi_video_device *device, static int acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) { - int status; + int status = AE_OK; union acpi_object arg0 = { ACPI_TYPE_INTEGER }; struct acpi_object_list args = { 1, &arg0 }; arg0.integer.value = level; - status = acpi_evaluate_object(device->dev->handle, "_BCM", &args, NULL); - + if (device->cap._BCM) + status = acpi_evaluate_object(device->dev->handle, "_BCM", + &args, NULL); + device->brightness->curr = level; printk(KERN_DEBUG "set_level status: %x\n", status); return status; } @@ -425,11 +427,11 @@ static int acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, unsigned long *level) { - int status; - - status = acpi_evaluate_integer(device->dev->handle, "_BQC", NULL, level); - - return status; + if (device->cap._BQC) + return acpi_evaluate_integer(device->dev->handle, "_BQC", NULL, + level); + *level = device->brightness->curr; + return AE_OK; } static int -- cgit v1.1 From 63f0edfc0b7f8058f9d3f9b572615ec97ae011ba Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Mon, 3 Sep 2007 16:30:08 +0400 Subject: ACPI: VIDEO: Adjust current level to closest available one. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/video.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 83aa41c..8a60a3d 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -1636,9 +1636,20 @@ static int acpi_video_get_next_level(struct acpi_video_device *device, u32 level_current, u32 event) { - int min, max, min_above, max_below, i, l; + int min, max, min_above, max_below, i, l, delta = 255; max = max_below = 0; min = min_above = 255; + /* Find closest level to level_current */ + for (i = 0; i < device->brightness->count; i++) { + l = device->brightness->levels[i]; + if (abs(l - level_current) < abs(delta)) { + delta = l - level_current; + if (!delta) + break; + } + } + /* Ajust level_current to closest available level */ + level_current += delta; for (i = 0; i < device->brightness->count; i++) { l = device->brightness->levels[i]; if (l < min) -- cgit v1.1 From 4c611060660f0de3e9b8f02df207312bc6f5c331 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Wed, 5 Sep 2007 19:56:38 -0400 Subject: ACPI: EC: Drop ECDT-based boot_ec as soon as we find DSDT-based one. ASUS notebooks have numerous problems with EC initialization This patch tries to work around three known issues reported in bugzilla 8598, 8709 and 8909/8919. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/ec.c | 90 ++++++++++++++++++++++++------------------------------- 1 file changed, 39 insertions(+), 51 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 3f7935a..9cd7997 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -121,6 +121,7 @@ static struct acpi_ec { atomic_t event_count; wait_queue_head_t wait; struct list_head list; + u8 handlers_installed; } *boot_ec, *first_ec; /* -------------------------------------------------------------------------- @@ -680,32 +681,50 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe); if (ACPI_FAILURE(status)) return status; - /* Find and register all query methods */ acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1, acpi_ec_register_query_methods, ec, NULL); - /* Use the global lock for all EC transactions? */ acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); - ec->handle = handle; - - printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n", - ec->gpe, ec->command_addr, ec->data_addr); - return AE_CTRL_TERMINATE; } +static void ec_remove_handlers(struct acpi_ec *ec) +{ + if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, + ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) + printk(KERN_ERR PREFIX "failed to remove space handler\n"); + if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe, + &acpi_ec_gpe_handler))) + printk(KERN_ERR PREFIX "failed to remove gpe handler\n"); + ec->handlers_installed = 0; +} + static int acpi_ec_add(struct acpi_device *device) { struct acpi_ec *ec = NULL; if (!device) return -EINVAL; - strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_EC_CLASS); + /* Check for boot EC */ + if (boot_ec) { + if (boot_ec->handle == device->handle) { + /* Pre-loaded EC from DSDT, just move pointer */ + ec = boot_ec; + boot_ec = NULL; + goto end; + } else if (boot_ec->handle == ACPI_ROOT_OBJECT) { + /* ECDT-based EC, time to shut it down */ + ec_remove_handlers(boot_ec); + kfree(boot_ec); + first_ec = boot_ec = NULL; + } + } + ec = make_acpi_ec(); if (!ec) return -ENOMEM; @@ -715,25 +734,14 @@ static int acpi_ec_add(struct acpi_device *device) kfree(ec); return -EINVAL; } - - /* Check if we found the boot EC */ - if (boot_ec) { - if (boot_ec->gpe == ec->gpe) { - /* We might have incorrect info for GL at boot time */ - mutex_lock(&boot_ec->lock); - boot_ec->global_lock = ec->global_lock; - /* Copy handlers from new ec into boot ec */ - list_splice(&ec->list, &boot_ec->list); - mutex_unlock(&boot_ec->lock); - kfree(ec); - ec = boot_ec; - } - } else - first_ec = ec; ec->handle = device->handle; + end: + if (!first_ec) + first_ec = ec; acpi_driver_data(device) = ec; - acpi_ec_add_fs(device); + printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n", + ec->gpe, ec->command_addr, ec->data_addr); return 0; } @@ -756,10 +764,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type) acpi_driver_data(device) = NULL; if (ec == first_ec) first_ec = NULL; - - /* Don't touch boot EC */ - if (boot_ec != ec) - kfree(ec); + kfree(ec); return 0; } @@ -789,6 +794,8 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context) static int ec_install_handlers(struct acpi_ec *ec) { acpi_status status; + if (ec->handlers_installed) + return 0; status = acpi_install_gpe_handler(NULL, ec->gpe, ACPI_GPE_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec); @@ -807,6 +814,7 @@ static int ec_install_handlers(struct acpi_ec *ec) return -ENODEV; } + ec->handlers_installed = 1; return 0; } @@ -823,41 +831,22 @@ static int acpi_ec_start(struct acpi_device *device) if (!ec) return -EINVAL; - /* Boot EC is already working */ - if (ec != boot_ec) - ret = ec_install_handlers(ec); + ret = ec_install_handlers(ec); /* EC is fully operational, allow queries */ atomic_set(&ec->query_pending, 0); - return ret; } static int acpi_ec_stop(struct acpi_device *device, int type) { - acpi_status status; struct acpi_ec *ec; - if (!device) return -EINVAL; - ec = acpi_driver_data(device); if (!ec) return -EINVAL; - - /* Don't touch boot EC */ - if (ec == boot_ec) - return 0; - - status = acpi_remove_address_space_handler(ec->handle, - ACPI_ADR_SPACE_EC, - &acpi_ec_space_handler); - if (ACPI_FAILURE(status)) - return -ENODEV; - - status = acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); - if (ACPI_FAILURE(status)) - return -ENODEV; + ec_remove_handlers(ec); return 0; } @@ -877,7 +866,7 @@ int __init acpi_ec_ecdt_probe(void) status = acpi_get_table(ACPI_SIG_ECDT, 1, (struct acpi_table_header **)&ecdt_ptr); if (ACPI_SUCCESS(status)) { - printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n\n"); + printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n"); boot_ec->command_addr = ecdt_ptr->control.address; boot_ec->data_addr = ecdt_ptr->data.address; boot_ec->gpe = ecdt_ptr->gpe; @@ -899,7 +888,6 @@ int __init acpi_ec_ecdt_probe(void) error: kfree(boot_ec); boot_ec = NULL; - return -ENODEV; } -- cgit v1.1 From 03e2bf261e832abf48d40113ce08a70338dd18c9 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Mon, 17 Sep 2007 23:41:05 +0200 Subject: acpi_video: kernel build error if !INPUT Commit e9dab1960ac9746fa34eff726b81635147615a79 (ACPI video hotkey: export missing ACPI video hotkey events via input layer) exports ACPI video hotkey events via input layer. But this breaks kernel build if ACPI_VIDEO && !INPUT: LD .tmp_vmlinux1 drivers/built-in.o: In function `acpi_video_bus_remove': drivers/acpi/video.c:2007: undefined reference to `input_unregister_device' ... Signed-off-by: Andreas Herrmann Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 4875f01..9685b75 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -117,6 +117,7 @@ config ACPI_BUTTON config ACPI_VIDEO tristate "Video" depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL + depends on INPUT help This driver implement the ACPI Extensions For Display Adapters for integrated graphics devices on motherboard, as specified in -- cgit v1.1 From 9b039330808b83acac3597535da26f47ad1862ce Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Wed, 26 Sep 2007 19:47:30 +0400 Subject: ACPI: Hibernate erroneously disabled Suspend wakeup devices S4 suspend to disk will disable GPE's permanently because acpi_gpe_sleep_prepare() does not have a counterpart at resume time. Thus, those devices became unavailable for wakeup from subsequent S3 suspend-to-ram. Here acpi_gpe_sleep_prepare() is removed, and upon suspend acpi_enable_wakeup_device() gets its functionality. Upon resume, acpi_disable_wakeup_device() restores the state. https://bugzilla.novell.com/show_bug.cgi?id=292300 Signed-off-by: Alexey Starikovskiy Acked-by: Pavel Machek Signed-off-by: Len Brown --- drivers/acpi/sleep/main.c | 1 - drivers/acpi/sleep/sleep.h | 1 - drivers/acpi/sleep/wakeup.c | 117 +++++++++++++++----------------------------- 3 files changed, 40 insertions(+), 79 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 2cbb9aa..9426ac1 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -44,7 +44,6 @@ int acpi_sleep_prepare(u32 acpi_state) ACPI_FLUSH_CPU_CACHE(); acpi_enable_wakeup_device_prep(acpi_state); #endif - acpi_gpe_sleep_prepare(acpi_state); acpi_enter_sleep_state_prep(acpi_state); return 0; } diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep/sleep.h index ff1f850..a2ea125 100644 --- a/drivers/acpi/sleep/sleep.h +++ b/drivers/acpi/sleep/sleep.h @@ -5,6 +5,5 @@ extern int acpi_suspend (u32 state); extern void acpi_enable_wakeup_device_prep(u8 sleep_state); extern void acpi_enable_wakeup_device(u8 sleep_state); extern void acpi_disable_wakeup_device(u8 sleep_state); -extern void acpi_gpe_sleep_prepare(u32 sleep_state); extern int acpi_sleep_prepare(u32 acpi_state); diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/sleep/wakeup.c index 97c27dd..ed8e41b 100644 --- a/drivers/acpi/sleep/wakeup.c +++ b/drivers/acpi/sleep/wakeup.c @@ -64,36 +64,29 @@ void acpi_enable_wakeup_device(u8 sleep_state) ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device"); spin_lock(&acpi_device_lock); list_for_each_safe(node, next, &acpi_wakeup_device_list) { - struct acpi_device *dev = container_of(node, - struct acpi_device, - wakeup_list); - + struct acpi_device *dev = + container_of(node, struct acpi_device, wakeup_list); + if (!dev->wakeup.flags.valid) + continue; /* If users want to disable run-wake GPE, * we only disable it for wake and leave it for runtime */ - if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) { - spin_unlock(&acpi_device_lock); - acpi_set_gpe_type(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, - ACPI_GPE_TYPE_RUNTIME); - /* Re-enable it, since set_gpe_type will disable it */ - acpi_enable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, ACPI_ISR); - spin_lock(&acpi_device_lock); + if (!dev->wakeup.state.enabled || + sleep_state > (u32) dev->wakeup.sleep_state) { + if (dev->wakeup.flags.run_wake) { + spin_unlock(&acpi_device_lock); + /* set_gpe_type will disable GPE, leave it like that */ + acpi_set_gpe_type(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, + ACPI_GPE_TYPE_RUNTIME); + spin_lock(&acpi_device_lock); + } continue; } - - if (!dev->wakeup.flags.valid || - !dev->wakeup.state.enabled || - (sleep_state > (u32) dev->wakeup.sleep_state)) - continue; - spin_unlock(&acpi_device_lock); - /* run-wake GPE has been enabled */ if (!dev->wakeup.flags.run_wake) acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number, ACPI_ISR); - dev->wakeup.state.active = 1; spin_lock(&acpi_device_lock); } spin_unlock(&acpi_device_lock); @@ -112,26 +105,25 @@ void acpi_disable_wakeup_device(u8 sleep_state) spin_lock(&acpi_device_lock); list_for_each_safe(node, next, &acpi_wakeup_device_list) { - struct acpi_device *dev = container_of(node, - struct acpi_device, - wakeup_list); + struct acpi_device *dev = + container_of(node, struct acpi_device, wakeup_list); - if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) { - spin_unlock(&acpi_device_lock); - acpi_set_gpe_type(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, - ACPI_GPE_TYPE_WAKE_RUN); - /* Re-enable it, since set_gpe_type will disable it */ - acpi_enable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, ACPI_NOT_ISR); - spin_lock(&acpi_device_lock); + if (!dev->wakeup.flags.valid) continue; - } - - if (!dev->wakeup.flags.valid || - !dev->wakeup.state.active || - (sleep_state > (u32) dev->wakeup.sleep_state)) + if (!dev->wakeup.state.enabled || + sleep_state > (u32) dev->wakeup.sleep_state) { + if (dev->wakeup.flags.run_wake) { + spin_unlock(&acpi_device_lock); + acpi_set_gpe_type(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, + ACPI_GPE_TYPE_WAKE_RUN); + /* Re-enable it, since set_gpe_type will disable it */ + acpi_enable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_NOT_ISR); + spin_lock(&acpi_device_lock); + } continue; + } spin_unlock(&acpi_device_lock); acpi_disable_wakeup_device_power(dev); @@ -142,7 +134,6 @@ void acpi_disable_wakeup_device(u8 sleep_state) acpi_clear_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number, ACPI_NOT_ISR); } - dev->wakeup.state.active = 0; spin_lock(&acpi_device_lock); } spin_unlock(&acpi_device_lock); @@ -160,48 +151,20 @@ static int __init acpi_wakeup_device_init(void) struct acpi_device *dev = container_of(node, struct acpi_device, wakeup_list); - /* In case user doesn't load button driver */ - if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) { - spin_unlock(&acpi_device_lock); - acpi_set_gpe_type(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, - ACPI_GPE_TYPE_WAKE_RUN); - acpi_enable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, ACPI_NOT_ISR); - dev->wakeup.state.enabled = 1; - spin_lock(&acpi_device_lock); - } + if (!dev->wakeup.flags.run_wake || dev->wakeup.state.enabled) + continue; + spin_unlock(&acpi_device_lock); + acpi_set_gpe_type(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, + ACPI_GPE_TYPE_WAKE_RUN); + acpi_enable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_NOT_ISR); + dev->wakeup.state.enabled = 1; + spin_lock(&acpi_device_lock); } spin_unlock(&acpi_device_lock); - return 0; } late_initcall(acpi_wakeup_device_init); - -/* - * Disable all wakeup GPEs before entering requested sleep state. - * @sleep_state: ACPI state - * Since acpi_enter_sleep_state() will disable all - * RUNTIME GPEs, we simply mark all GPES that - * are not enabled for wakeup from requested state as RUNTIME. - */ -void acpi_gpe_sleep_prepare(u32 sleep_state) -{ - struct list_head *node, *next; - - list_for_each_safe(node, next, &acpi_wakeup_device_list) { - struct acpi_device *dev = container_of(node, - struct acpi_device, - wakeup_list); - - /* The GPE can wakeup system from this state, don't touch it */ - if ((u32) dev->wakeup.sleep_state >= sleep_state) - continue; - /* acpi_set_gpe_type will automatically disable GPE */ - acpi_set_gpe_type(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, - ACPI_GPE_TYPE_RUNTIME); - } -} -- cgit v1.1 From 038fdea2960be53f82353fd409526fb77a558c52 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Wed, 26 Sep 2007 19:42:46 +0400 Subject: ACPI: Battery: don't use acpi_extract_package() acpi_extract_package() creates more problems with memory management than it solves as helper for package handling. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/battery.c | 359 +++++++++++++++++++------------------------------ 1 file changed, 139 insertions(+), 220 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 9b2c0f7..de506f3 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -36,9 +36,6 @@ #define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF -#define ACPI_BATTERY_FORMAT_BIF "NNNNNNNNNSSSS" -#define ACPI_BATTERY_FORMAT_BST "NNNN" - #define ACPI_BATTERY_COMPONENT 0x00040000 #define ACPI_BATTERY_CLASS "battery" #define ACPI_BATTERY_DEVICE_NAME "Battery" @@ -90,61 +87,49 @@ static struct acpi_driver acpi_battery_driver = { }, }; -struct acpi_battery_state { - acpi_integer state; - acpi_integer present_rate; - acpi_integer remaining_capacity; - acpi_integer present_voltage; -}; - -struct acpi_battery_info { - acpi_integer power_unit; - acpi_integer design_capacity; - acpi_integer last_full_capacity; - acpi_integer battery_technology; - acpi_integer design_voltage; - acpi_integer design_capacity_warning; - acpi_integer design_capacity_low; - acpi_integer battery_capacity_granularity_1; - acpi_integer battery_capacity_granularity_2; - acpi_string model_number; - acpi_string serial_number; - acpi_string battery_type; - acpi_string oem_info; -}; - -enum acpi_battery_files{ +enum acpi_battery_files { ACPI_BATTERY_INFO = 0, ACPI_BATTERY_STATE, ACPI_BATTERY_ALARM, ACPI_BATTERY_NUMFILES, }; -struct acpi_battery_flags { - u8 battery_present_prev; - u8 alarm_present; - u8 init_update; - u8 update[ACPI_BATTERY_NUMFILES]; - u8 power_unit; -}; - struct acpi_battery { - struct mutex mutex; struct acpi_device *device; - struct acpi_battery_flags flags; - struct acpi_buffer bif_data; - struct acpi_buffer bst_data; + struct mutex lock; unsigned long alarm; unsigned long update_time[ACPI_BATTERY_NUMFILES]; + int state; + int present_rate; + int remaining_capacity; + int present_voltage; + int power_unit; + int design_capacity; + int last_full_capacity; + int technology; + int design_voltage; + int design_capacity_warning; + int design_capacity_low; + int capacity_granularity_1; + int capacity_granularity_2; + char model_number[32]; + char serial_number[32]; + char type[32]; + char oem_info[32]; + u8 present_prev; + u8 alarm_present; + u8 init_update; + u8 update[ACPI_BATTERY_NUMFILES]; }; inline int acpi_battery_present(struct acpi_battery *battery) { return battery->device->status.battery_present; } + inline char *acpi_battery_power_units(struct acpi_battery *battery) { - if (battery->flags.power_unit) + if (battery->power_unit) return ACPI_BATTERY_UNITS_AMPS; else return ACPI_BATTERY_UNITS_WATTS; @@ -165,43 +150,63 @@ static void acpi_battery_check_result(struct acpi_battery *battery, int result) return; if (result) { - battery->flags.init_update = 1; + battery->init_update = 1; } } -static int acpi_battery_extract_package(struct acpi_battery *battery, - union acpi_object *package, - struct acpi_buffer *format, - struct acpi_buffer *data, - char *package_name) -{ - acpi_status status = AE_OK; - struct acpi_buffer data_null = { 0, NULL }; +struct acpi_offsets { + size_t offset; /* offset inside struct acpi_sbs_battery */ + u8 mode; /* int or string? */ +}; - status = acpi_extract_package(package, format, &data_null); - if (status != AE_BUFFER_OVERFLOW) { - ACPI_EXCEPTION((AE_INFO, status, "Extracting size %s", - package_name)); - return -ENODEV; - } +static struct acpi_offsets state_offsets[] = { + {offsetof(struct acpi_battery, state), 0}, + {offsetof(struct acpi_battery, present_rate), 0}, + {offsetof(struct acpi_battery, remaining_capacity), 0}, + {offsetof(struct acpi_battery, present_voltage), 0}, +}; - if (data_null.length != data->length) { - kfree(data->pointer); - data->pointer = kzalloc(data_null.length, GFP_KERNEL); - if (!data->pointer) { - ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "kzalloc()")); - return -ENOMEM; - } - data->length = data_null.length; - } +static struct acpi_offsets info_offsets[] = { + {offsetof(struct acpi_battery, power_unit), 0}, + {offsetof(struct acpi_battery, design_capacity), 0}, + {offsetof(struct acpi_battery, last_full_capacity), 0}, + {offsetof(struct acpi_battery, technology), 0}, + {offsetof(struct acpi_battery, design_voltage), 0}, + {offsetof(struct acpi_battery, design_capacity_warning), 0}, + {offsetof(struct acpi_battery, design_capacity_low), 0}, + {offsetof(struct acpi_battery, capacity_granularity_1), 0}, + {offsetof(struct acpi_battery, capacity_granularity_2), 0}, + {offsetof(struct acpi_battery, model_number), 1}, + {offsetof(struct acpi_battery, serial_number), 1}, + {offsetof(struct acpi_battery, type), 1}, + {offsetof(struct acpi_battery, oem_info), 1}, +}; - status = acpi_extract_package(package, format, data); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Extracting %s", - package_name)); - return -ENODEV; +static int extract_package(struct acpi_battery *battery, + union acpi_object *package, + struct acpi_offsets *offsets, int num) +{ + int i, *x; + union acpi_object *element; + if (package->type != ACPI_TYPE_PACKAGE) + return -EFAULT; + for (i = 0; i < num; ++i) { + if (package->package.count <= i) + return -EFAULT; + element = &package->package.elements[i]; + if (offsets[i].mode) { + if (element->type != ACPI_TYPE_STRING && + element->type != ACPI_TYPE_BUFFER) + return -EFAULT; + strncpy((u8 *)battery + offsets[i].offset, + element->string.pointer, 32); + } else { + if (element->type != ACPI_TYPE_INTEGER) + return -EFAULT; + x = (int *)((u8 *)battery + offsets[i].offset); + *x = element->integer.value; + } } - return 0; } @@ -222,49 +227,21 @@ static int acpi_battery_get_info(struct acpi_battery *battery) int result = 0; acpi_status status = 0; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF), - ACPI_BATTERY_FORMAT_BIF - }; - union acpi_object *package = NULL; - struct acpi_buffer *data = NULL; - struct acpi_battery_info *bif = NULL; battery->update_time[ACPI_BATTERY_INFO] = get_seconds(); - if (!acpi_battery_present(battery)) return 0; - - /* Evaluate _BIF */ - - status = - acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", NULL, - &buffer); + mutex_lock(&battery->lock); + status = acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", + NULL, &buffer); + mutex_unlock(&battery->lock); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF")); return -ENODEV; } - - package = buffer.pointer; - - data = &battery->bif_data; - - /* Extract Package Data */ - - result = - acpi_battery_extract_package(battery, package, &format, data, - "_BIF"); - if (result) - goto end; - - end: - + result = extract_package(battery, buffer.pointer, + info_offsets, ARRAY_SIZE(info_offsets)); kfree(buffer.pointer); - - if (!result) { - bif = data->pointer; - battery->flags.power_unit = bif->power_unit; - } - return result; } @@ -273,42 +250,24 @@ static int acpi_battery_get_state(struct acpi_battery *battery) int result = 0; acpi_status status = 0; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST), - ACPI_BATTERY_FORMAT_BST - }; - union acpi_object *package = NULL; - struct acpi_buffer *data = NULL; battery->update_time[ACPI_BATTERY_STATE] = get_seconds(); if (!acpi_battery_present(battery)) return 0; - /* Evaluate _BST */ + mutex_lock(&battery->lock); + status = acpi_evaluate_object(acpi_battery_handle(battery), "_BST", + NULL, &buffer); + mutex_unlock(&battery->lock); - status = - acpi_evaluate_object(acpi_battery_handle(battery), "_BST", NULL, - &buffer); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST")); return -ENODEV; } - - package = buffer.pointer; - - data = &battery->bst_data; - - /* Extract Package Data */ - - result = - acpi_battery_extract_package(battery, package, &format, data, - "_BST"); - if (result) - goto end; - - end: + result = extract_package(battery, buffer.pointer, + state_offsets, ARRAY_SIZE(state_offsets)); kfree(buffer.pointer); - return result; } @@ -331,14 +290,15 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery, if (!acpi_battery_present(battery)) return -ENODEV; - if (!battery->flags.alarm_present) + if (!battery->alarm_present) return -ENODEV; arg0.integer.value = alarm; - status = - acpi_evaluate_object(acpi_battery_handle(battery), "_BTP", - &arg_list, NULL); + mutex_lock(&battery->lock); + status = acpi_evaluate_object(acpi_battery_handle(battery), "_BTP", + &arg_list, NULL); + mutex_unlock(&battery->lock); if (ACPI_FAILURE(status)) return -ENODEV; @@ -354,22 +314,21 @@ static int acpi_battery_init_alarm(struct acpi_battery *battery) int result = 0; acpi_status status = AE_OK; acpi_handle handle = NULL; - struct acpi_battery_info *bif = battery->bif_data.pointer; unsigned long alarm = battery->alarm; /* See if alarms are supported, and if so, set default */ status = acpi_get_handle(acpi_battery_handle(battery), "_BTP", &handle); if (ACPI_SUCCESS(status)) { - battery->flags.alarm_present = 1; - if (!alarm && bif) { - alarm = bif->design_capacity_warning; + battery->alarm_present = 1; + if (!alarm) { + alarm = battery->design_capacity_warning; } result = acpi_battery_set_alarm(battery, alarm); if (result) goto end; } else { - battery->flags.alarm_present = 0; + battery->alarm_present = 0; } end: @@ -385,7 +344,7 @@ static int acpi_battery_init_update(struct acpi_battery *battery) if (result) return result; - battery->flags.battery_present_prev = acpi_battery_present(battery); + battery->present_prev = acpi_battery_present(battery); if (acpi_battery_present(battery)) { result = acpi_battery_get_info(battery); @@ -411,7 +370,7 @@ static int acpi_battery_update(struct acpi_battery *battery, update = 1; } - if (battery->flags.init_update) { + if (battery->init_update) { result = acpi_battery_init_update(battery); if (result) goto end; @@ -420,8 +379,8 @@ static int acpi_battery_update(struct acpi_battery *battery, result = acpi_battery_get_status(battery); if (result) goto end; - if ((!battery->flags.battery_present_prev & acpi_battery_present(battery)) - || (battery->flags.battery_present_prev & !acpi_battery_present(battery))) { + if ((!battery->present_prev & acpi_battery_present(battery)) + || (battery->present_prev & !acpi_battery_present(battery))) { result = acpi_battery_init_update(battery); if (result) goto end; @@ -433,7 +392,7 @@ static int acpi_battery_update(struct acpi_battery *battery, end: - battery->flags.init_update = (result != 0); + battery->init_update = (result != 0); *update_result_ptr = update_result; @@ -444,19 +403,19 @@ static void acpi_battery_notify_update(struct acpi_battery *battery) { acpi_battery_get_status(battery); - if (battery->flags.init_update) { + if (battery->init_update) { return; } - if ((!battery->flags.battery_present_prev & + if ((!battery->present_prev & acpi_battery_present(battery)) || - (battery->flags.battery_present_prev & + (battery->present_prev & !acpi_battery_present(battery))) { - battery->flags.init_update = 1; + battery->init_update = 1; } else { - battery->flags.update[ACPI_BATTERY_INFO] = 1; - battery->flags.update[ACPI_BATTERY_STATE] = 1; - battery->flags.update[ACPI_BATTERY_ALARM] = 1; + battery->update[ACPI_BATTERY_INFO] = 1; + battery->update[ACPI_BATTERY_STATE] = 1; + battery->update[ACPI_BATTERY_ALARM] = 1; } } @@ -469,7 +428,6 @@ static struct proc_dir_entry *acpi_battery_dir; static int acpi_battery_print_info(struct seq_file *seq, int result) { struct acpi_battery *battery = seq->private; - struct acpi_battery_info *bif = NULL; char *units = "?"; if (result) @@ -482,30 +440,23 @@ static int acpi_battery_print_info(struct seq_file *seq, int result) goto end; } - bif = battery->bif_data.pointer; - if (!bif) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BIF buffer is NULL")); - result = -ENODEV; - goto end; - } - /* Battery Units */ units = acpi_battery_power_units(battery); - if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) + if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "design capacity: unknown\n"); else seq_printf(seq, "design capacity: %d %sh\n", - (u32) bif->design_capacity, units); + (u32) battery->design_capacity, units); - if (bif->last_full_capacity == ACPI_BATTERY_VALUE_UNKNOWN) + if (battery->last_full_capacity == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "last full capacity: unknown\n"); else seq_printf(seq, "last full capacity: %d %sh\n", - (u32) bif->last_full_capacity, units); + (u32) battery->last_full_capacity, units); - switch ((u32) bif->battery_technology) { + switch ((u32) battery->technology) { case 0: seq_printf(seq, "battery technology: non-rechargeable\n"); break; @@ -517,23 +468,23 @@ static int acpi_battery_print_info(struct seq_file *seq, int result) break; } - if (bif->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN) + if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "design voltage: unknown\n"); else seq_printf(seq, "design voltage: %d mV\n", - (u32) bif->design_voltage); + (u32) battery->design_voltage); seq_printf(seq, "design capacity warning: %d %sh\n", - (u32) bif->design_capacity_warning, units); + (u32) battery->design_capacity_warning, units); seq_printf(seq, "design capacity low: %d %sh\n", - (u32) bif->design_capacity_low, units); + (u32) battery->design_capacity_low, units); seq_printf(seq, "capacity granularity 1: %d %sh\n", - (u32) bif->battery_capacity_granularity_1, units); + (u32) battery->capacity_granularity_1, units); seq_printf(seq, "capacity granularity 2: %d %sh\n", - (u32) bif->battery_capacity_granularity_2, units); - seq_printf(seq, "model number: %s\n", bif->model_number); - seq_printf(seq, "serial number: %s\n", bif->serial_number); - seq_printf(seq, "battery type: %s\n", bif->battery_type); - seq_printf(seq, "OEM info: %s\n", bif->oem_info); + (u32) battery->capacity_granularity_2, units); + seq_printf(seq, "model number: %s\n", battery->model_number); + seq_printf(seq, "serial number: %s\n", battery->serial_number); + seq_printf(seq, "battery type: %s\n", battery->type); + seq_printf(seq, "OEM info: %s\n", battery->oem_info); end: @@ -546,7 +497,6 @@ static int acpi_battery_print_info(struct seq_file *seq, int result) static int acpi_battery_print_state(struct seq_file *seq, int result) { struct acpi_battery *battery = seq->private; - struct acpi_battery_state *bst = NULL; char *units = "?"; if (result) @@ -559,50 +509,43 @@ static int acpi_battery_print_state(struct seq_file *seq, int result) goto end; } - bst = battery->bst_data.pointer; - if (!bst) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BST buffer is NULL")); - result = -ENODEV; - goto end; - } - /* Battery Units */ units = acpi_battery_power_units(battery); - if (!(bst->state & 0x04)) + if (!(battery->state & 0x04)) seq_printf(seq, "capacity state: ok\n"); else seq_printf(seq, "capacity state: critical\n"); - if ((bst->state & 0x01) && (bst->state & 0x02)) { + if ((battery->state & 0x01) && (battery->state & 0x02)) { seq_printf(seq, "charging state: charging/discharging\n"); - } else if (bst->state & 0x01) + } else if (battery->state & 0x01) seq_printf(seq, "charging state: discharging\n"); - else if (bst->state & 0x02) + else if (battery->state & 0x02) seq_printf(seq, "charging state: charging\n"); else { seq_printf(seq, "charging state: charged\n"); } - if (bst->present_rate == ACPI_BATTERY_VALUE_UNKNOWN) + if (battery->present_rate == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "present rate: unknown\n"); else seq_printf(seq, "present rate: %d %s\n", - (u32) bst->present_rate, units); + (u32) battery->present_rate, units); - if (bst->remaining_capacity == ACPI_BATTERY_VALUE_UNKNOWN) + if (battery->remaining_capacity == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "remaining capacity: unknown\n"); else seq_printf(seq, "remaining capacity: %d %sh\n", - (u32) bst->remaining_capacity, units); + (u32) battery->remaining_capacity, units); - if (bst->present_voltage == ACPI_BATTERY_VALUE_UNKNOWN) + if (battery->present_voltage == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "present voltage: unknown\n"); else seq_printf(seq, "present voltage: %d mV\n", - (u32) bst->present_voltage); + (u32) battery->present_voltage); end: @@ -658,8 +601,6 @@ acpi_battery_write_alarm(struct file *file, if (!battery || (count > sizeof(alarm_string) - 1)) return -EINVAL; - mutex_lock(&battery->mutex); - result = acpi_battery_update(battery, 1, &update_result); if (result) { result = -ENODEV; @@ -689,9 +630,6 @@ acpi_battery_write_alarm(struct file *file, if (!result) result = count; - - mutex_unlock(&battery->mutex); - return result; } @@ -714,10 +652,8 @@ static int acpi_battery_read(int fid, struct seq_file *seq) int update_result = ACPI_BATTERY_NONE_UPDATE; int update = 0; - mutex_lock(&battery->mutex); - update = (get_seconds() - battery->update_time[fid] >= update_time); - update = (update | battery->flags.update[fid]); + update = (update | battery->update[fid]); result = acpi_battery_update(battery, update, &update_result); if (result) @@ -732,8 +668,7 @@ static int acpi_battery_read(int fid, struct seq_file *seq) end: result = acpi_read_funcs[fid].print(seq, result); acpi_battery_check_result(battery, result); - battery->flags.update[fid] = result; - mutex_unlock(&battery->mutex); + battery->update[fid] = result; return result; } @@ -900,20 +835,16 @@ static int acpi_battery_add(struct acpi_device *device) if (!battery) return -ENOMEM; - mutex_init(&battery->mutex); - - mutex_lock(&battery->mutex); - battery->device = device; strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); acpi_driver_data(device) = battery; - + mutex_init(&battery->lock); result = acpi_battery_get_status(battery); if (result) goto end; - battery->flags.init_update = 1; + battery->init_update = 1; result = acpi_battery_add_fs(device); if (result) @@ -939,8 +870,6 @@ static int acpi_battery_add(struct acpi_device *device) kfree(battery); } - mutex_unlock(&battery->mutex); - return result; } @@ -954,22 +883,12 @@ static int acpi_battery_remove(struct acpi_device *device, int type) battery = acpi_driver_data(device); - mutex_lock(&battery->mutex); - status = acpi_remove_notify_handler(device->handle, ACPI_ALL_NOTIFY, acpi_battery_notify); acpi_battery_remove_fs(device); - - kfree(battery->bif_data.pointer); - - kfree(battery->bst_data.pointer); - - mutex_unlock(&battery->mutex); - - mutex_destroy(&battery->mutex); - + mutex_destroy(&battery->lock); kfree(battery); return 0; @@ -985,7 +904,7 @@ static int acpi_battery_resume(struct acpi_device *device) battery = device->driver_data; - battery->flags.init_update = 1; + battery->init_update = 1; return 0; } -- cgit v1.1 From f1d4661abe05d0a2c014166042d15ed8b69ae8f2 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Wed, 26 Sep 2007 19:42:52 +0400 Subject: ACPI: Battery: simplify update scheme Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/battery.c | 280 ++++++++++--------------------------------------- 1 file changed, 57 insertions(+), 223 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index de506f3..faa70a5 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -41,27 +42,18 @@ #define ACPI_BATTERY_DEVICE_NAME "Battery" #define ACPI_BATTERY_NOTIFY_STATUS 0x80 #define ACPI_BATTERY_NOTIFY_INFO 0x81 -#define ACPI_BATTERY_UNITS_WATTS "mW" -#define ACPI_BATTERY_UNITS_AMPS "mA" #define _COMPONENT ACPI_BATTERY_COMPONENT -#define ACPI_BATTERY_UPDATE_TIME 0 - -#define ACPI_BATTERY_NONE_UPDATE 0 -#define ACPI_BATTERY_EASY_UPDATE 1 -#define ACPI_BATTERY_INIT_UPDATE 2 - ACPI_MODULE_NAME("battery"); MODULE_AUTHOR("Paul Diefenbaugh"); MODULE_DESCRIPTION("ACPI Battery Driver"); MODULE_LICENSE("GPL"); -static unsigned int update_time = ACPI_BATTERY_UPDATE_TIME; - -/* 0 - every time, > 0 - by update_time */ -module_param(update_time, uint, 0644); +static unsigned int cache_time = 1000; +module_param(cache_time, uint, 0644); +MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); extern struct proc_dir_entry *acpi_lock_battery_dir(void); extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); @@ -95,15 +87,12 @@ enum acpi_battery_files { }; struct acpi_battery { - struct acpi_device *device; struct mutex lock; - unsigned long alarm; - unsigned long update_time[ACPI_BATTERY_NUMFILES]; - int state; + struct acpi_device *device; + unsigned long update_time; int present_rate; int remaining_capacity; int present_voltage; - int power_unit; int design_capacity; int last_full_capacity; int technology; @@ -112,14 +101,14 @@ struct acpi_battery { int design_capacity_low; int capacity_granularity_1; int capacity_granularity_2; + int alarm; char model_number[32]; char serial_number[32]; char type[32]; char oem_info[32]; - u8 present_prev; + int state; + int power_unit; u8 alarm_present; - u8 init_update; - u8 update[ACPI_BATTERY_NUMFILES]; }; inline int acpi_battery_present(struct acpi_battery *battery) @@ -127,33 +116,15 @@ inline int acpi_battery_present(struct acpi_battery *battery) return battery->device->status.battery_present; } -inline char *acpi_battery_power_units(struct acpi_battery *battery) +inline char *acpi_battery_units(struct acpi_battery *battery) { - if (battery->power_unit) - return ACPI_BATTERY_UNITS_AMPS; - else - return ACPI_BATTERY_UNITS_WATTS; -} - -inline acpi_handle acpi_battery_handle(struct acpi_battery *battery) -{ - return battery->device->handle; + return (battery->power_unit)?"mA":"mW"; } /* -------------------------------------------------------------------------- Battery Management -------------------------------------------------------------------------- */ -static void acpi_battery_check_result(struct acpi_battery *battery, int result) -{ - if (!battery) - return; - - if (result) { - battery->init_update = 1; - } -} - struct acpi_offsets { size_t offset; /* offset inside struct acpi_sbs_battery */ u8 mode; /* int or string? */ @@ -228,11 +199,10 @@ static int acpi_battery_get_info(struct acpi_battery *battery) acpi_status status = 0; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - battery->update_time[ACPI_BATTERY_INFO] = get_seconds(); if (!acpi_battery_present(battery)) return 0; mutex_lock(&battery->lock); - status = acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", + status = acpi_evaluate_object(battery->device->handle, "_BIF", NULL, &buffer); mutex_unlock(&battery->lock); if (ACPI_FAILURE(status)) { @@ -251,13 +221,16 @@ static int acpi_battery_get_state(struct acpi_battery *battery) acpi_status status = 0; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - battery->update_time[ACPI_BATTERY_STATE] = get_seconds(); - if (!acpi_battery_present(battery)) return 0; + if (battery->update_time && + time_before(jiffies, battery->update_time + + msecs_to_jiffies(cache_time))) + return 0; + mutex_lock(&battery->lock); - status = acpi_evaluate_object(acpi_battery_handle(battery), "_BST", + status = acpi_evaluate_object(battery->device->handle, "_BST", NULL, &buffer); mutex_unlock(&battery->lock); @@ -267,14 +240,13 @@ static int acpi_battery_get_state(struct acpi_battery *battery) } result = extract_package(battery, buffer.pointer, state_offsets, ARRAY_SIZE(state_offsets)); + battery->update_time = jiffies; kfree(buffer.pointer); return result; } static int acpi_battery_get_alarm(struct acpi_battery *battery) { - battery->update_time[ACPI_BATTERY_ALARM] = get_seconds(); - return 0; } @@ -285,8 +257,6 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery, union acpi_object arg0 = { ACPI_TYPE_INTEGER }; struct acpi_object_list arg_list = { 1, &arg0 }; - battery->update_time[ACPI_BATTERY_ALARM] = get_seconds(); - if (!acpi_battery_present(battery)) return -ENODEV; @@ -296,8 +266,8 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery, arg0.integer.value = alarm; mutex_lock(&battery->lock); - status = acpi_evaluate_object(acpi_battery_handle(battery), "_BTP", - &arg_list, NULL); + status = acpi_evaluate_object(battery->device->handle, "_BTP", + &arg_list, NULL); mutex_unlock(&battery->lock); if (ACPI_FAILURE(status)) return -ENODEV; @@ -311,112 +281,36 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery, static int acpi_battery_init_alarm(struct acpi_battery *battery) { - int result = 0; acpi_status status = AE_OK; acpi_handle handle = NULL; - unsigned long alarm = battery->alarm; /* See if alarms are supported, and if so, set default */ - - status = acpi_get_handle(acpi_battery_handle(battery), "_BTP", &handle); - if (ACPI_SUCCESS(status)) { - battery->alarm_present = 1; - if (!alarm) { - alarm = battery->design_capacity_warning; - } - result = acpi_battery_set_alarm(battery, alarm); - if (result) - goto end; - } else { + status = acpi_get_handle(battery->device->handle, "_BTP", &handle); + if (ACPI_FAILURE(status)) { battery->alarm_present = 0; + return 0; } - - end: - - return result; + battery->alarm_present = 1; + if (!battery->alarm) + battery->alarm = battery->design_capacity_warning; + return acpi_battery_set_alarm(battery, battery->alarm); } -static int acpi_battery_init_update(struct acpi_battery *battery) +static int acpi_battery_update(struct acpi_battery *battery) { - int result = 0; - - result = acpi_battery_get_status(battery); - if (result) + int saved_present = acpi_battery_present(battery); + int result = acpi_battery_get_status(battery); + if (result || !acpi_battery_present(battery)) return result; - - battery->present_prev = acpi_battery_present(battery); - - if (acpi_battery_present(battery)) { + if (saved_present != acpi_battery_present(battery) || + !battery->update_time) { + battery->update_time = 0; result = acpi_battery_get_info(battery); if (result) return result; - result = acpi_battery_get_state(battery); - if (result) - return result; - acpi_battery_init_alarm(battery); } - - return result; -} - -static int acpi_battery_update(struct acpi_battery *battery, - int update, int *update_result_ptr) -{ - int result = 0; - int update_result = ACPI_BATTERY_NONE_UPDATE; - - if (!acpi_battery_present(battery)) { - update = 1; - } - - if (battery->init_update) { - result = acpi_battery_init_update(battery); - if (result) - goto end; - update_result = ACPI_BATTERY_INIT_UPDATE; - } else if (update) { - result = acpi_battery_get_status(battery); - if (result) - goto end; - if ((!battery->present_prev & acpi_battery_present(battery)) - || (battery->present_prev & !acpi_battery_present(battery))) { - result = acpi_battery_init_update(battery); - if (result) - goto end; - update_result = ACPI_BATTERY_INIT_UPDATE; - } else { - update_result = ACPI_BATTERY_EASY_UPDATE; - } - } - - end: - - battery->init_update = (result != 0); - - *update_result_ptr = update_result; - - return result; -} - -static void acpi_battery_notify_update(struct acpi_battery *battery) -{ - acpi_battery_get_status(battery); - - if (battery->init_update) { - return; - } - - if ((!battery->present_prev & - acpi_battery_present(battery)) || - (battery->present_prev & - !acpi_battery_present(battery))) { - battery->init_update = 1; - } else { - battery->update[ACPI_BATTERY_INFO] = 1; - battery->update[ACPI_BATTERY_STATE] = 1; - battery->update[ACPI_BATTERY_ALARM] = 1; - } + return acpi_battery_get_state(battery); } /* -------------------------------------------------------------------------- @@ -442,7 +336,7 @@ static int acpi_battery_print_info(struct seq_file *seq, int result) /* Battery Units */ - units = acpi_battery_power_units(battery); + units = acpi_battery_units(battery); if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "design capacity: unknown\n"); @@ -511,7 +405,7 @@ static int acpi_battery_print_state(struct seq_file *seq, int result) /* Battery Units */ - units = acpi_battery_power_units(battery); + units = acpi_battery_units(battery); if (!(battery->state & 0x04)) seq_printf(seq, "capacity state: ok\n"); @@ -571,13 +465,13 @@ static int acpi_battery_print_alarm(struct seq_file *seq, int result) /* Battery Units */ - units = acpi_battery_power_units(battery); + units = acpi_battery_units(battery); seq_printf(seq, "alarm: "); if (!battery->alarm) seq_printf(seq, "unsupported\n"); else - seq_printf(seq, "%lu %sh\n", battery->alarm, units); + seq_printf(seq, "%u %sh\n", battery->alarm, units); end: @@ -587,49 +481,35 @@ static int acpi_battery_print_alarm(struct seq_file *seq, int result) return result; } -static ssize_t -acpi_battery_write_alarm(struct file *file, - const char __user * buffer, - size_t count, loff_t * ppos) +static ssize_t acpi_battery_write_alarm(struct file *file, + const char __user * buffer, + size_t count, loff_t * ppos) { int result = 0; char alarm_string[12] = { '\0' }; struct seq_file *m = file->private_data; struct acpi_battery *battery = m->private; - int update_result = ACPI_BATTERY_NONE_UPDATE; if (!battery || (count > sizeof(alarm_string) - 1)) return -EINVAL; - - result = acpi_battery_update(battery, 1, &update_result); if (result) { result = -ENODEV; goto end; } - if (!acpi_battery_present(battery)) { result = -ENODEV; goto end; } - if (copy_from_user(alarm_string, buffer, count)) { result = -EFAULT; goto end; } - alarm_string[count] = '\0'; - - result = acpi_battery_set_alarm(battery, - simple_strtoul(alarm_string, NULL, 0)); - if (result) - goto end; - + battery->alarm = simple_strtol(alarm_string, NULL, 0); + result = acpi_battery_set_alarm(battery, battery->alarm); end: - - acpi_battery_check_result(battery, result); - if (!result) - result = count; + return count; return result; } @@ -648,28 +528,8 @@ static struct acpi_read_mux { static int acpi_battery_read(int fid, struct seq_file *seq) { struct acpi_battery *battery = seq->private; - int result = 0; - int update_result = ACPI_BATTERY_NONE_UPDATE; - int update = 0; - - update = (get_seconds() - battery->update_time[fid] >= update_time); - update = (update | battery->update[fid]); - - result = acpi_battery_update(battery, update, &update_result); - if (result) - goto end; - - if (update_result == ACPI_BATTERY_EASY_UPDATE) { - result = acpi_read_funcs[fid].get(battery); - if (result) - goto end; - } - - end: - result = acpi_read_funcs[fid].print(seq, result); - acpi_battery_check_result(battery, result); - battery->update[fid] = result; - return result; + int result = acpi_battery_update(battery); + return acpi_read_funcs[fid].print(seq, result); } static int acpi_battery_read_info(struct seq_file *seq, void *offset) @@ -793,33 +653,16 @@ static int acpi_battery_remove_fs(struct acpi_device *device) static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) { struct acpi_battery *battery = data; - struct acpi_device *device = NULL; - + struct acpi_device *device; if (!battery) return; - device = battery->device; - - switch (event) { - case ACPI_BATTERY_NOTIFY_STATUS: - case ACPI_BATTERY_NOTIFY_INFO: - case ACPI_NOTIFY_BUS_CHECK: - case ACPI_NOTIFY_DEVICE_CHECK: - device = battery->device; - acpi_battery_notify_update(battery); - acpi_bus_generate_proc_event(device, event, + acpi_battery_update(battery); + acpi_bus_generate_proc_event(device, event, + acpi_battery_present(battery)); + acpi_bus_generate_netlink_event(device->pnp.device_class, + device->dev.bus_id, event, acpi_battery_present(battery)); - acpi_bus_generate_netlink_event(device->pnp.device_class, - device->dev.bus_id, event, - acpi_battery_present(battery)); - break; - default: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Unsupported event [0x%x]\n", event)); - break; - } - - return; } static int acpi_battery_add(struct acpi_device *device) @@ -840,12 +683,7 @@ static int acpi_battery_add(struct acpi_device *device) strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); acpi_driver_data(device) = battery; mutex_init(&battery->lock); - result = acpi_battery_get_status(battery); - if (result) - goto end; - - battery->init_update = 1; - + acpi_battery_update(battery); result = acpi_battery_add_fs(device); if (result) goto end; @@ -898,14 +736,10 @@ static int acpi_battery_remove(struct acpi_device *device, int type) static int acpi_battery_resume(struct acpi_device *device) { struct acpi_battery *battery; - if (!device) return -EINVAL; - - battery = device->driver_data; - - battery->init_update = 1; - + battery = acpi_driver_data(device); + battery->update_time = 0; return 0; } -- cgit v1.1 From aa650bbdcb94bde4292eabc44490970825c98669 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Wed, 26 Sep 2007 19:42:58 +0400 Subject: ACPI: Battery: Misc clean-ups, no functional changes Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/battery.c | 342 ++++++++++++++++++------------------------------- 1 file changed, 125 insertions(+), 217 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index faa70a5..db725bf 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -1,6 +1,8 @@ /* - * acpi_battery.c - ACPI Battery Driver ($Revision: 37 $) + * battery.c - ACPI Battery Driver (Revision: 2.0) * + * Copyright (C) 2007 Alexey Starikovskiy + * Copyright (C) 2004-2007 Vladimir Lebedev * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh * @@ -48,6 +50,7 @@ ACPI_MODULE_NAME("battery"); MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_AUTHOR("Alexey Starikovskiy "); MODULE_DESCRIPTION("ACPI Battery Driver"); MODULE_LICENSE("GPL"); @@ -58,31 +61,17 @@ MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); extern struct proc_dir_entry *acpi_lock_battery_dir(void); extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); -static int acpi_battery_add(struct acpi_device *device); -static int acpi_battery_remove(struct acpi_device *device, int type); -static int acpi_battery_resume(struct acpi_device *device); - static const struct acpi_device_id battery_device_ids[] = { {"PNP0C0A", 0}, {"", 0}, }; -MODULE_DEVICE_TABLE(acpi, battery_device_ids); -static struct acpi_driver acpi_battery_driver = { - .name = "battery", - .class = ACPI_BATTERY_CLASS, - .ids = battery_device_ids, - .ops = { - .add = acpi_battery_add, - .resume = acpi_battery_resume, - .remove = acpi_battery_remove, - }, -}; +MODULE_DEVICE_TABLE(acpi, battery_device_ids); enum acpi_battery_files { - ACPI_BATTERY_INFO = 0, - ACPI_BATTERY_STATE, - ACPI_BATTERY_ALARM, + info_tag = 0, + state_tag, + alarm_tag, ACPI_BATTERY_NUMFILES, }; @@ -124,7 +113,6 @@ inline char *acpi_battery_units(struct acpi_battery *battery) /* -------------------------------------------------------------------------- Battery Management -------------------------------------------------------------------------- */ - struct acpi_offsets { size_t offset; /* offset inside struct acpi_sbs_battery */ u8 mode; /* int or string? */ @@ -183,19 +171,16 @@ static int extract_package(struct acpi_battery *battery, static int acpi_battery_get_status(struct acpi_battery *battery) { - int result = 0; - - result = acpi_bus_get_status(battery->device); - if (result) { + if (acpi_bus_get_status(battery->device)) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA")); return -ENODEV; } - return result; + return 0; } static int acpi_battery_get_info(struct acpi_battery *battery) { - int result = 0; + int result = -EFAULT; acpi_status status = 0; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -205,10 +190,12 @@ static int acpi_battery_get_info(struct acpi_battery *battery) status = acpi_evaluate_object(battery->device->handle, "_BIF", NULL, &buffer); mutex_unlock(&battery->lock); + if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF")); return -ENODEV; } + result = extract_package(battery, buffer.pointer, info_offsets, ARRAY_SIZE(info_offsets)); kfree(buffer.pointer); @@ -238,6 +225,7 @@ static int acpi_battery_get_state(struct acpi_battery *battery) ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST")); return -ENODEV; } + result = extract_package(battery, buffer.pointer, state_offsets, ARRAY_SIZE(state_offsets)); battery->update_time = jiffies; @@ -245,37 +233,26 @@ static int acpi_battery_get_state(struct acpi_battery *battery) return result; } -static int acpi_battery_get_alarm(struct acpi_battery *battery) -{ - return 0; -} - -static int acpi_battery_set_alarm(struct acpi_battery *battery, - unsigned long alarm) +static int acpi_battery_set_alarm(struct acpi_battery *battery) { acpi_status status = 0; - union acpi_object arg0 = { ACPI_TYPE_INTEGER }; + union acpi_object arg0 = { .type = ACPI_TYPE_INTEGER }; struct acpi_object_list arg_list = { 1, &arg0 }; - if (!acpi_battery_present(battery)) - return -ENODEV; - - if (!battery->alarm_present) + if (!acpi_battery_present(battery)|| !battery->alarm_present) return -ENODEV; - arg0.integer.value = alarm; + arg0.integer.value = battery->alarm; mutex_lock(&battery->lock); status = acpi_evaluate_object(battery->device->handle, "_BTP", &arg_list, NULL); mutex_unlock(&battery->lock); + if (ACPI_FAILURE(status)) return -ENODEV; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", (u32) alarm)); - - battery->alarm = alarm; - + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", battery->alarm)); return 0; } @@ -293,7 +270,7 @@ static int acpi_battery_init_alarm(struct acpi_battery *battery) battery->alarm_present = 1; if (!battery->alarm) battery->alarm = battery->design_capacity_warning; - return acpi_battery_set_alarm(battery, battery->alarm); + return acpi_battery_set_alarm(battery); } static int acpi_battery_update(struct acpi_battery *battery) @@ -322,130 +299,101 @@ static struct proc_dir_entry *acpi_battery_dir; static int acpi_battery_print_info(struct seq_file *seq, int result) { struct acpi_battery *battery = seq->private; - char *units = "?"; if (result) goto end; - if (acpi_battery_present(battery)) - seq_printf(seq, "present: yes\n"); - else { - seq_printf(seq, "present: no\n"); + seq_printf(seq, "present: %s\n", + acpi_battery_present(battery)?"yes":"no"); + if (!acpi_battery_present(battery)) goto end; - } - - /* Battery Units */ - - units = acpi_battery_units(battery); - if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "design capacity: unknown\n"); else seq_printf(seq, "design capacity: %d %sh\n", - (u32) battery->design_capacity, units); + battery->design_capacity, + acpi_battery_units(battery)); if (battery->last_full_capacity == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "last full capacity: unknown\n"); else seq_printf(seq, "last full capacity: %d %sh\n", - (u32) battery->last_full_capacity, units); - - switch ((u32) battery->technology) { - case 0: - seq_printf(seq, "battery technology: non-rechargeable\n"); - break; - case 1: - seq_printf(seq, "battery technology: rechargeable\n"); - break; - default: - seq_printf(seq, "battery technology: unknown\n"); - break; - } + battery->last_full_capacity, + acpi_battery_units(battery)); + + seq_printf(seq, "battery technology: %srechargeable\n", + (!battery->technology)?"non-":""); if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "design voltage: unknown\n"); else seq_printf(seq, "design voltage: %d mV\n", - (u32) battery->design_voltage); + battery->design_voltage); seq_printf(seq, "design capacity warning: %d %sh\n", - (u32) battery->design_capacity_warning, units); + battery->design_capacity_warning, + acpi_battery_units(battery)); seq_printf(seq, "design capacity low: %d %sh\n", - (u32) battery->design_capacity_low, units); + battery->design_capacity_low, + acpi_battery_units(battery)); seq_printf(seq, "capacity granularity 1: %d %sh\n", - (u32) battery->capacity_granularity_1, units); + battery->capacity_granularity_1, + acpi_battery_units(battery)); seq_printf(seq, "capacity granularity 2: %d %sh\n", - (u32) battery->capacity_granularity_2, units); + battery->capacity_granularity_2, + acpi_battery_units(battery)); seq_printf(seq, "model number: %s\n", battery->model_number); seq_printf(seq, "serial number: %s\n", battery->serial_number); seq_printf(seq, "battery type: %s\n", battery->type); seq_printf(seq, "OEM info: %s\n", battery->oem_info); - end: - if (result) seq_printf(seq, "ERROR: Unable to read battery info\n"); - return result; } static int acpi_battery_print_state(struct seq_file *seq, int result) { struct acpi_battery *battery = seq->private; - char *units = "?"; if (result) goto end; - if (acpi_battery_present(battery)) - seq_printf(seq, "present: yes\n"); - else { - seq_printf(seq, "present: no\n"); + seq_printf(seq, "present: %s\n", + acpi_battery_present(battery)?"yes":"no"); + if (!acpi_battery_present(battery)) goto end; - } - - /* Battery Units */ - - units = acpi_battery_units(battery); - if (!(battery->state & 0x04)) - seq_printf(seq, "capacity state: ok\n"); - else - seq_printf(seq, "capacity state: critical\n"); - - if ((battery->state & 0x01) && (battery->state & 0x02)) { + seq_printf(seq, "capacity state: %s\n", + (battery->state & 0x04)?"critical":"ok"); + if ((battery->state & 0x01) && (battery->state & 0x02)) seq_printf(seq, "charging state: charging/discharging\n"); - } else if (battery->state & 0x01) + else if (battery->state & 0x01) seq_printf(seq, "charging state: discharging\n"); else if (battery->state & 0x02) seq_printf(seq, "charging state: charging\n"); - else { + else seq_printf(seq, "charging state: charged\n"); - } if (battery->present_rate == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "present rate: unknown\n"); else seq_printf(seq, "present rate: %d %s\n", - (u32) battery->present_rate, units); + battery->present_rate, acpi_battery_units(battery)); if (battery->remaining_capacity == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "remaining capacity: unknown\n"); else seq_printf(seq, "remaining capacity: %d %sh\n", - (u32) battery->remaining_capacity, units); - + battery->remaining_capacity, acpi_battery_units(battery)); if (battery->present_voltage == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "present voltage: unknown\n"); else seq_printf(seq, "present voltage: %d mV\n", - (u32) battery->present_voltage); - + battery->present_voltage); end: - - if (result) { + if (result) seq_printf(seq, "ERROR: Unable to read battery state\n"); - } return result; } @@ -453,7 +401,6 @@ static int acpi_battery_print_state(struct seq_file *seq, int result) static int acpi_battery_print_alarm(struct seq_file *seq, int result) { struct acpi_battery *battery = seq->private; - char *units = "?"; if (result) goto end; @@ -462,22 +409,15 @@ static int acpi_battery_print_alarm(struct seq_file *seq, int result) seq_printf(seq, "present: no\n"); goto end; } - - /* Battery Units */ - - units = acpi_battery_units(battery); - seq_printf(seq, "alarm: "); if (!battery->alarm) seq_printf(seq, "unsupported\n"); else - seq_printf(seq, "%u %sh\n", battery->alarm, units); - + seq_printf(seq, "%u %sh\n", battery->alarm, + acpi_battery_units(battery)); end: - if (result) seq_printf(seq, "ERROR: Unable to read battery alarm\n"); - return result; } @@ -506,7 +446,7 @@ static ssize_t acpi_battery_write_alarm(struct file *file, } alarm_string[count] = '\0'; battery->alarm = simple_strtol(alarm_string, NULL, 0); - result = acpi_battery_set_alarm(battery, battery->alarm); + result = acpi_battery_set_alarm(battery); end: if (!result) return count; @@ -514,95 +454,76 @@ static ssize_t acpi_battery_write_alarm(struct file *file, } typedef int(*print_func)(struct seq_file *seq, int result); -typedef int(*get_func)(struct acpi_battery *battery); - -static struct acpi_read_mux { - print_func print; - get_func get; -} acpi_read_funcs[ACPI_BATTERY_NUMFILES] = { - {.get = acpi_battery_get_info, .print = acpi_battery_print_info}, - {.get = acpi_battery_get_state, .print = acpi_battery_print_state}, - {.get = acpi_battery_get_alarm, .print = acpi_battery_print_alarm}, + +static print_func acpi_print_funcs[ACPI_BATTERY_NUMFILES] = { + acpi_battery_print_info, + acpi_battery_print_state, + acpi_battery_print_alarm, }; static int acpi_battery_read(int fid, struct seq_file *seq) { struct acpi_battery *battery = seq->private; int result = acpi_battery_update(battery); - return acpi_read_funcs[fid].print(seq, result); -} - -static int acpi_battery_read_info(struct seq_file *seq, void *offset) -{ - return acpi_battery_read(ACPI_BATTERY_INFO, seq); -} - -static int acpi_battery_read_state(struct seq_file *seq, void *offset) -{ - return acpi_battery_read(ACPI_BATTERY_STATE, seq); -} - -static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) -{ - return acpi_battery_read(ACPI_BATTERY_ALARM, seq); + return acpi_print_funcs[fid](seq, result); } -static int acpi_battery_info_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_battery_read_info, PDE(inode)->data); +#define DECLARE_FILE_FUNCTIONS(_name) \ +static int acpi_battery_read_##_name(struct seq_file *seq, void *offset) \ +{ \ + return acpi_battery_read(_name##_tag, seq); \ +} \ +static int acpi_battery_##_name##_open_fs(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, acpi_battery_read_##_name, PDE(inode)->data); \ } -static int acpi_battery_state_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_battery_read_state, PDE(inode)->data); -} +DECLARE_FILE_FUNCTIONS(info); +DECLARE_FILE_FUNCTIONS(state); +DECLARE_FILE_FUNCTIONS(alarm); + +#undef DECLARE_FILE_FUNCTIONS + +#define FILE_DESCRIPTION_RO(_name) \ + { \ + .name = __stringify(_name), \ + .mode = S_IRUGO, \ + .ops = { \ + .open = acpi_battery_##_name##_open_fs, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ + .owner = THIS_MODULE, \ + }, \ + } -static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_battery_read_alarm, PDE(inode)->data); -} +#define FILE_DESCRIPTION_RW(_name) \ + { \ + .name = __stringify(_name), \ + .mode = S_IFREG | S_IRUGO | S_IWUSR, \ + .ops = { \ + .open = acpi_battery_##_name##_open_fs, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .write = acpi_battery_write_##_name, \ + .release = single_release, \ + .owner = THIS_MODULE, \ + }, \ + } static struct battery_file { struct file_operations ops; mode_t mode; char *name; } acpi_battery_file[] = { - { - .name = "info", - .mode = S_IRUGO, - .ops = { - .open = acpi_battery_info_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, - }, - }, - { - .name = "state", - .mode = S_IRUGO, - .ops = { - .open = acpi_battery_state_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, - }, - }, - { - .name = "alarm", - .mode = S_IFREG | S_IRUGO | S_IWUSR, - .ops = { - .open = acpi_battery_alarm_open_fs, - .read = seq_read, - .write = acpi_battery_write_alarm, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, - }, - }, + FILE_DESCRIPTION_RO(info), + FILE_DESCRIPTION_RO(state), + FILE_DESCRIPTION_RW(alarm), }; +#undef FILE_DESCRIPTION_RO +#undef FILE_DESCRIPTION_RW + static int acpi_battery_add_fs(struct acpi_device *device) { struct proc_dir_entry *entry = NULL; @@ -627,23 +548,20 @@ static int acpi_battery_add_fs(struct acpi_device *device) entry->owner = THIS_MODULE; } } - return 0; } -static int acpi_battery_remove_fs(struct acpi_device *device) +static void acpi_battery_remove_fs(struct acpi_device *device) { int i; - if (acpi_device_dir(device)) { - for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) { - remove_proc_entry(acpi_battery_file[i].name, + if (!acpi_device_dir(device)) + return; + for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) + remove_proc_entry(acpi_battery_file[i].name, acpi_device_dir(device)); - } - remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); - acpi_device_dir(device) = NULL; - } - return 0; + remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); + acpi_device_dir(device) = NULL; } /* -------------------------------------------------------------------------- @@ -670,14 +588,11 @@ 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; - battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL); if (!battery) return -ENOMEM; - battery->device = device; strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); @@ -687,7 +602,6 @@ static int acpi_battery_add(struct acpi_device *device) result = acpi_battery_add_fs(device); if (result) goto end; - status = acpi_install_notify_handler(device->handle, ACPI_ALL_NOTIFY, acpi_battery_notify, battery); @@ -696,18 +610,14 @@ static int acpi_battery_add(struct acpi_device *device) 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"); - end: - if (result) { acpi_battery_remove_fs(device); kfree(battery); } - return result; } @@ -718,17 +628,13 @@ static int acpi_battery_remove(struct acpi_device *device, int type) 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); - acpi_battery_remove_fs(device); mutex_destroy(&battery->lock); kfree(battery); - return 0; } @@ -743,33 +649,35 @@ static int acpi_battery_resume(struct acpi_device *device) return 0; } +static struct acpi_driver acpi_battery_driver = { + .name = "battery", + .class = ACPI_BATTERY_CLASS, + .ids = battery_device_ids, + .ops = { + .add = acpi_battery_add, + .resume = acpi_battery_resume, + .remove = acpi_battery_remove, + }, +}; + static int __init acpi_battery_init(void) { - int result; - if (acpi_disabled) return -ENODEV; - acpi_battery_dir = acpi_lock_battery_dir(); if (!acpi_battery_dir) return -ENODEV; - - result = acpi_bus_register_driver(&acpi_battery_driver); - if (result < 0) { + if (acpi_bus_register_driver(&acpi_battery_driver) < 0) { acpi_unlock_battery_dir(acpi_battery_dir); return -ENODEV; } - return 0; } static void __exit acpi_battery_exit(void) { acpi_bus_unregister_driver(&acpi_battery_driver); - acpi_unlock_battery_dir(acpi_battery_dir); - - return; } module_init(acpi_battery_init); -- cgit v1.1 From d7380965752505951668e85de59c128d1d6fd21f Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Wed, 26 Sep 2007 19:43:04 +0400 Subject: ACPI: Battery: Add sysfs support Refer to Documentation/power_supply_class.txt for interface description. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 2 +- drivers/acpi/battery.c | 186 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 165 insertions(+), 23 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 4875f01..8560bc3 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -97,7 +97,7 @@ config ACPI_AC config ACPI_BATTERY tristate "Battery" - depends on X86 + depends on X86 && POWER_SUPPLY default y help This driver adds support for battery information through diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index db725bf..057a5eb 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -30,13 +30,18 @@ #include #include #include + +#ifdef CONFIG_ACPI_PROCFS #include #include #include +#endif #include #include +#include + #define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF #define ACPI_BATTERY_COMPONENT 0x00040000 @@ -58,9 +63,19 @@ static unsigned int cache_time = 1000; module_param(cache_time, uint, 0644); MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); +#ifdef CONFIG_ACPI_PROCFS extern struct proc_dir_entry *acpi_lock_battery_dir(void); extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); +enum acpi_battery_files { + info_tag = 0, + state_tag, + alarm_tag, + ACPI_BATTERY_NUMFILES, +}; + +#endif + static const struct acpi_device_id battery_device_ids[] = { {"PNP0C0A", 0}, {"", 0}, @@ -68,22 +83,17 @@ static const struct acpi_device_id battery_device_ids[] = { MODULE_DEVICE_TABLE(acpi, battery_device_ids); -enum acpi_battery_files { - info_tag = 0, - state_tag, - alarm_tag, - ACPI_BATTERY_NUMFILES, -}; struct acpi_battery { struct mutex lock; + struct power_supply bat; struct acpi_device *device; unsigned long update_time; - int present_rate; - int remaining_capacity; - int present_voltage; + int current_now; + int capacity_now; + int voltage_now; int design_capacity; - int last_full_capacity; + int full_charge_capacity; int technology; int design_voltage; int design_capacity_warning; @@ -100,15 +110,117 @@ struct acpi_battery { u8 alarm_present; }; +#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat); + inline int acpi_battery_present(struct acpi_battery *battery) { return battery->device->status.battery_present; } +static int acpi_battery_technology(struct acpi_battery *battery) +{ + if (!strcasecmp("NiCd", battery->type)) + return POWER_SUPPLY_TECHNOLOGY_NiCd; + if (!strcasecmp("NiMH", battery->type)) + return POWER_SUPPLY_TECHNOLOGY_NiMH; + if (!strcasecmp("LION", battery->type)) + return POWER_SUPPLY_TECHNOLOGY_LION; + if (!strcasecmp("LiP", battery->type)) + return POWER_SUPPLY_TECHNOLOGY_LIPO; + return POWER_SUPPLY_TECHNOLOGY_UNKNOWN; +} + +static int acpi_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct acpi_battery *battery = to_acpi_battery(psy); + + if ((!acpi_battery_present(battery)) && + psp != POWER_SUPPLY_PROP_PRESENT) + return -ENODEV; + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + if (battery->state & 0x01) + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + else if (battery->state & 0x02) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + else if (battery->state == 0) + val->intval = POWER_SUPPLY_STATUS_FULL; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = acpi_battery_present(battery); + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = acpi_battery_technology(battery); + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = battery->design_voltage * 1000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = battery->voltage_now * 1000; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = battery->current_now * 1000; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: + val->intval = battery->design_capacity * 1000; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + case POWER_SUPPLY_PROP_ENERGY_FULL: + val->intval = battery->full_charge_capacity * 1000; + break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + case POWER_SUPPLY_PROP_ENERGY_NOW: + val->intval = battery->capacity_now * 1000; + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = battery->model_number; + break; + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = battery->oem_info; + break; + default: + return -EINVAL; + } + return 0; +} + +static enum power_supply_property charge_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +static enum power_supply_property energy_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, + POWER_SUPPLY_PROP_ENERGY_FULL, + POWER_SUPPLY_PROP_ENERGY_NOW, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +#ifdef CONFIG_ACPI_PROCFS inline char *acpi_battery_units(struct acpi_battery *battery) { return (battery->power_unit)?"mA":"mW"; } +#endif /* -------------------------------------------------------------------------- Battery Management @@ -120,15 +232,15 @@ struct acpi_offsets { static struct acpi_offsets state_offsets[] = { {offsetof(struct acpi_battery, state), 0}, - {offsetof(struct acpi_battery, present_rate), 0}, - {offsetof(struct acpi_battery, remaining_capacity), 0}, - {offsetof(struct acpi_battery, present_voltage), 0}, + {offsetof(struct acpi_battery, current_now), 0}, + {offsetof(struct acpi_battery, capacity_now), 0}, + {offsetof(struct acpi_battery, voltage_now), 0}, }; static struct acpi_offsets info_offsets[] = { {offsetof(struct acpi_battery, power_unit), 0}, {offsetof(struct acpi_battery, design_capacity), 0}, - {offsetof(struct acpi_battery, last_full_capacity), 0}, + {offsetof(struct acpi_battery, full_charge_capacity), 0}, {offsetof(struct acpi_battery, technology), 0}, {offsetof(struct acpi_battery, design_voltage), 0}, {offsetof(struct acpi_battery, design_capacity_warning), 0}, @@ -285,6 +397,15 @@ static int acpi_battery_update(struct acpi_battery *battery) result = acpi_battery_get_info(battery); if (result) return result; + if (battery->power_unit) { + battery->bat.properties = charge_battery_props; + battery->bat.num_properties = + ARRAY_SIZE(charge_battery_props); + } else { + battery->bat.properties = energy_battery_props; + battery->bat.num_properties = + ARRAY_SIZE(energy_battery_props); + } acpi_battery_init_alarm(battery); } return acpi_battery_get_state(battery); @@ -294,6 +415,7 @@ static int acpi_battery_update(struct acpi_battery *battery) FS Interface (/proc) -------------------------------------------------------------------------- */ +#ifdef CONFIG_ACPI_PROCFS static struct proc_dir_entry *acpi_battery_dir; static int acpi_battery_print_info(struct seq_file *seq, int result) @@ -314,11 +436,11 @@ static int acpi_battery_print_info(struct seq_file *seq, int result) battery->design_capacity, acpi_battery_units(battery)); - if (battery->last_full_capacity == ACPI_BATTERY_VALUE_UNKNOWN) + if (battery->full_charge_capacity == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "last full capacity: unknown\n"); else seq_printf(seq, "last full capacity: %d %sh\n", - battery->last_full_capacity, + battery->full_charge_capacity, acpi_battery_units(battery)); seq_printf(seq, "battery technology: %srechargeable\n", @@ -375,22 +497,22 @@ static int acpi_battery_print_state(struct seq_file *seq, int result) else seq_printf(seq, "charging state: charged\n"); - if (battery->present_rate == ACPI_BATTERY_VALUE_UNKNOWN) + if (battery->current_now == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "present rate: unknown\n"); else seq_printf(seq, "present rate: %d %s\n", - battery->present_rate, acpi_battery_units(battery)); + battery->current_now, acpi_battery_units(battery)); - if (battery->remaining_capacity == ACPI_BATTERY_VALUE_UNKNOWN) + if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "remaining capacity: unknown\n"); else seq_printf(seq, "remaining capacity: %d %sh\n", - battery->remaining_capacity, acpi_battery_units(battery)); - if (battery->present_voltage == ACPI_BATTERY_VALUE_UNKNOWN) + battery->capacity_now, acpi_battery_units(battery)); + if (battery->voltage_now == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "present voltage: unknown\n"); else seq_printf(seq, "present voltage: %d mV\n", - battery->present_voltage); + battery->voltage_now); end: if (result) seq_printf(seq, "ERROR: Unable to read battery state\n"); @@ -564,6 +686,7 @@ static void acpi_battery_remove_fs(struct acpi_device *device) acpi_device_dir(device) = NULL; } +#endif /* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */ @@ -581,6 +704,7 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) acpi_bus_generate_netlink_event(device->pnp.device_class, device->dev.bus_id, event, acpi_battery_present(battery)); + kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE); } static int acpi_battery_add(struct acpi_device *device) @@ -599,9 +723,15 @@ static int acpi_battery_add(struct acpi_device *device) acpi_driver_data(device) = battery; mutex_init(&battery->lock); acpi_battery_update(battery); +#ifdef CONFIG_ACPI_PROCFS result = acpi_battery_add_fs(device); if (result) goto end; +#endif + battery->bat.name = acpi_device_bid(device); + battery->bat.type = POWER_SUPPLY_TYPE_BATTERY; + battery->bat.get_property = acpi_battery_get_property; + result = power_supply_register(&battery->device->dev, &battery->bat); status = acpi_install_notify_handler(device->handle, ACPI_ALL_NOTIFY, acpi_battery_notify, battery); @@ -615,7 +745,9 @@ static int acpi_battery_add(struct acpi_device *device) device->status.battery_present ? "present" : "absent"); end: if (result) { +#ifdef CONFIG_ACPI_PROCFS acpi_battery_remove_fs(device); +#endif kfree(battery); } return result; @@ -632,7 +764,11 @@ static int acpi_battery_remove(struct acpi_device *device, int type) status = acpi_remove_notify_handler(device->handle, ACPI_ALL_NOTIFY, acpi_battery_notify); +#ifdef CONFIG_ACPI_PROCFS acpi_battery_remove_fs(device); +#endif + if (battery->bat.dev) + power_supply_unregister(&battery->bat); mutex_destroy(&battery->lock); kfree(battery); return 0; @@ -664,11 +800,15 @@ static int __init acpi_battery_init(void) { if (acpi_disabled) return -ENODEV; +#ifdef CONFIG_ACPI_PROCFS acpi_battery_dir = acpi_lock_battery_dir(); if (!acpi_battery_dir) return -ENODEV; +#endif if (acpi_bus_register_driver(&acpi_battery_driver) < 0) { +#ifdef CONFIG_ACPI_PROCFS acpi_unlock_battery_dir(acpi_battery_dir); +#endif return -ENODEV; } return 0; @@ -677,7 +817,9 @@ static int __init acpi_battery_init(void) static void __exit acpi_battery_exit(void) { acpi_bus_unregister_driver(&acpi_battery_driver); +#ifdef CONFIG_ACPI_PROCFS acpi_unlock_battery_dir(acpi_battery_dir); +#endif } module_init(acpi_battery_init); -- cgit v1.1 From 3e58ea0d31659b22ba5753f7abf3d7db346eab81 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Wed, 26 Sep 2007 19:43:11 +0400 Subject: ACPI: Battery: add sysfs alarm Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/battery.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 057a5eb..681e26b 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -687,6 +687,34 @@ static void acpi_battery_remove_fs(struct acpi_device *device) } #endif + +static ssize_t acpi_battery_alarm_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); + return sprintf(buf, "%d\n", battery->alarm * 1000); +} + +static ssize_t acpi_battery_alarm_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long x; + struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); + if (sscanf(buf, "%ld\n", &x) == 1) + battery->alarm = x/1000; + if (acpi_battery_present(battery)) + acpi_battery_set_alarm(battery); + return count; +} + +static struct device_attribute alarm_attr = { + .attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE}, + .show = acpi_battery_alarm_show, + .store = acpi_battery_alarm_store, +}; + /* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */ @@ -732,6 +760,7 @@ static int acpi_battery_add(struct acpi_device *device) battery->bat.type = POWER_SUPPLY_TYPE_BATTERY; battery->bat.get_property = acpi_battery_get_property; result = power_supply_register(&battery->device->dev, &battery->bat); + result = device_create_file(battery->bat.dev, &alarm_attr); status = acpi_install_notify_handler(device->handle, ACPI_ALL_NOTIFY, acpi_battery_notify, battery); @@ -767,8 +796,10 @@ static int acpi_battery_remove(struct acpi_device *device, int type) #ifdef CONFIG_ACPI_PROCFS acpi_battery_remove_fs(device); #endif - if (battery->bat.dev) + if (battery->bat.dev) { + device_remove_file(battery->bat.dev, &alarm_attr); power_supply_unregister(&battery->bat); + } mutex_destroy(&battery->lock); kfree(battery); return 0; -- cgit v1.1 From 8db85d4c9a0cc131242c80ef8456362d66561dc2 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Wed, 26 Sep 2007 19:43:16 +0400 Subject: ACPI: Add acpi_bus_generate_event4() function acpi_bus_generate_event() takes two strings out of passed device object. SBS needs to supply these strings directly. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/bus.c | 23 +++++++++++++++-------- drivers/acpi/sbs.c | 46 ++++++++++++++-------------------------------- 2 files changed, 29 insertions(+), 40 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 9ba778a..a54234d 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -284,15 +284,11 @@ DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue); extern int event_is_open; -int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data) +int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id, u8 type, int data) { - struct acpi_bus_event *event = NULL; + struct acpi_bus_event *event; unsigned long flags = 0; - - if (!device) - return -EINVAL; - /* drop event on the floor if no one's listening */ if (!event_is_open) return 0; @@ -301,8 +297,8 @@ int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data) if (!event) return -ENOMEM; - strcpy(event->device_class, device->pnp.device_class); - strcpy(event->bus_id, device->pnp.bus_id); + strcpy(event->device_class, device_class); + strcpy(event->bus_id, bus_id); event->type = type; event->data = data; @@ -313,6 +309,17 @@ int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data) wake_up_interruptible(&acpi_bus_event_queue); return 0; + +} + +EXPORT_SYMBOL_GPL(acpi_bus_generate_proc_event4); + +int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data) +{ + if (!device) + return -EINVAL; + return acpi_bus_generate_proc_event4(device->pnp.device_class, + device->pnp.bus_id, type, data); } EXPORT_SYMBOL(acpi_bus_generate_proc_event); diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index a578986..33ba4bf 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -427,28 +427,6 @@ static int acpi_check_update_proc(struct acpi_sbs *sbs) return 0; } -static int acpi_sbs_generate_event(struct acpi_device *device, - int event, int state, char *bid, char *class) -{ - char bid_saved[5]; - char class_saved[20]; - int result = 0; - - strcpy(bid_saved, acpi_device_bid(device)); - strcpy(class_saved, acpi_device_class(device)); - - strcpy(acpi_device_bid(device), bid); - strcpy(acpi_device_class(device), class); - - result = acpi_bus_generate_proc_event(device, event, state); - - strcpy(acpi_device_bid(device), bid_saved); - strcpy(acpi_device_class(device), class_saved); - - acpi_bus_generate_netlink_event(class, bid, event, state); - return result; -} - static int acpi_battery_get_present(struct acpi_battery *battery) { s16 state; @@ -1452,15 +1430,17 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type) } if (do_ac_init) { - result = acpi_sbs_generate_event(sbs->device, - ACPI_SBS_AC_NOTIFY_STATUS, - new_ac_present, + result = acpi_bus_generate_proc_event4(ACPI_AC_CLASS, ACPI_AC_DIR_NAME, - ACPI_AC_CLASS); + ACPI_SBS_AC_NOTIFY_STATUS, + new_ac_present); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_generate_event() failed")); + "acpi_bus_generate_event4() failed")); } + acpi_bus_generate_netlink_event(ACPI_AC_CLASS, ACPI_AC_DIR_NAME, + ACPI_SBS_AC_NOTIFY_STATUS, + new_ac_present); } if (data_type == DATA_TYPE_COMMON) { @@ -1568,14 +1548,16 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type) old_remaining_capacity != battery->state.remaining_capacity) { sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id); - result = acpi_sbs_generate_event(sbs->device, - ACPI_SBS_BATTERY_NOTIFY_STATUS, - new_battery_present, + result = acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS, dir_name, - ACPI_BATTERY_CLASS); + ACPI_SBS_BATTERY_NOTIFY_STATUS, + new_battery_present); + acpi_bus_generate_netlink_event(ACPI_BATTERY_CLASS, dir_name, + ACPI_SBS_BATTERY_NOTIFY_STATUS, + new_battery_present); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_generate_event() " + "acpi_bus_generate_proc_event4() " "failed")); } } -- cgit v1.1 From 30c08574da0ead1a47797ce028218ce5b2de61c7 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Wed, 26 Sep 2007 19:43:22 +0400 Subject: ACPI: EC: Add new query handler to list head. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/ec.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 3f7935a..e9a0405 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -425,7 +425,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, handler->func = func; handler->data = data; mutex_lock(&ec->lock); - list_add_tail(&handler->node, &ec->list); + list_add(&handler->node, &ec->list); mutex_unlock(&ec->lock); return 0; } @@ -440,7 +440,6 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) if (query_bit == handler->query_bit) { list_del(&handler->node); kfree(handler); - break; } } mutex_unlock(&ec->lock); -- cgit v1.1 From 91087dfa51a29b3c190e99339c4c32eb13646c51 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Wed, 26 Sep 2007 19:43:28 +0400 Subject: ACPI: SBS: Split host controller (ACPI0001) from SBS driver (ACPI0002) Replace poll-based host controller driver with the notify-based one. Split it out of sbs.c. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/Makefile | 1 + drivers/acpi/sbs.c | 374 ++++++++++---------------------------------------- drivers/acpi/sbshc.c | 309 +++++++++++++++++++++++++++++++++++++++++ drivers/acpi/sbshc.h | 27 ++++ 4 files changed, 412 insertions(+), 299 deletions(-) create mode 100644 drivers/acpi/sbshc.c create mode 100644 drivers/acpi/sbshc.h (limited to 'drivers/acpi') diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index d4336f1..54e3ab0 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -60,3 +60,4 @@ obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o obj-y += cm_sbs.o obj-$(CONFIG_ACPI_SBS) += sbs.o +obj-$(CONFIG_ACPI_SBS) += sbshc.o diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 33ba4bf..7bb8c62 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -34,6 +34,8 @@ #include #include +#include "sbshc.h" + #define ACPI_SBS_COMPONENT 0x00080000 #define ACPI_SBS_CLASS "sbs" #define ACPI_AC_CLASS "ac_adapter" @@ -59,28 +61,6 @@ MODULE_AUTHOR("Rich Townsend"); MODULE_DESCRIPTION("Smart Battery System ACPI interface driver"); MODULE_LICENSE("GPL"); -#define xmsleep(t) msleep(t) - -#define ACPI_EC_SMB_PRTCL 0x00 /* protocol, PEC */ - -#define ACPI_EC_SMB_STS 0x01 /* status */ -#define ACPI_EC_SMB_ADDR 0x02 /* address */ -#define ACPI_EC_SMB_CMD 0x03 /* command */ -#define ACPI_EC_SMB_DATA 0x04 /* 32 data registers */ -#define ACPI_EC_SMB_BCNT 0x24 /* number of data bytes */ - -#define ACPI_EC_SMB_STS_DONE 0x80 -#define ACPI_EC_SMB_STS_STATUS 0x1f - -#define ACPI_EC_SMB_PRTCL_WRITE 0x00 -#define ACPI_EC_SMB_PRTCL_READ 0x01 -#define ACPI_EC_SMB_PRTCL_WORD_DATA 0x08 -#define ACPI_EC_SMB_PRTCL_BLOCK_DATA 0x0a - -#define ACPI_EC_SMB_TRANSACTION_SLEEP 1 -#define ACPI_EC_SMB_ACCESS_SLEEP1 1 -#define ACPI_EC_SMB_ACCESS_SLEEP2 10 - #define DEF_CAPACITY_UNIT 3 #define MAH_CAPACITY_UNIT 1 #define MWH_CAPACITY_UNIT 2 @@ -103,12 +83,6 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); #define MAX_SBS_BAT 4 #define ACPI_SBS_BLOCK_MAX 32 -#define ACPI_SBS_SMBUS_READ 1 -#define ACPI_SBS_SMBUS_WRITE 2 - -#define ACPI_SBS_WORD_DATA 1 -#define ACPI_SBS_BLOCK_DATA 2 - #define UPDATE_DELAY 10 /* 0 - every time, > 0 - by update_time */ @@ -124,8 +98,7 @@ static int acpi_sbs_remove(struct acpi_device *device, int type); static int acpi_sbs_resume(struct acpi_device *device); static const struct acpi_device_id sbs_device_ids[] = { - {"ACPI0001", 0}, - {"ACPI0005", 0}, + {"ACPI0002", 0}, {"", 0}, }; MODULE_DEVICE_TABLE(acpi, sbs_device_ids); @@ -182,8 +155,8 @@ struct acpi_battery { }; struct acpi_sbs { - int base; struct acpi_device *device; + struct acpi_smb_hc *hc; struct mutex mutex; int sbsm_present; int sbsm_batteries_supported; @@ -199,190 +172,6 @@ struct acpi_sbs { static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type); static void acpi_sbs_update_time(void *data); -union sbs_rw_data { - u16 word; - u8 block[ACPI_SBS_BLOCK_MAX + 2]; -}; - -static int acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr, - char read_write, u8 command, int size, - union sbs_rw_data *data); - -/* -------------------------------------------------------------------------- - SMBus Communication - -------------------------------------------------------------------------- */ - -static int acpi_ec_sbs_read(struct acpi_sbs *sbs, u8 address, u8 * data) -{ - u8 val; - int err; - - err = ec_read(sbs->base + address, &val); - if (!err) { - *data = val; - } - xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP); - return (err); -} - -static int acpi_ec_sbs_write(struct acpi_sbs *sbs, u8 address, u8 data) -{ - int err; - - err = ec_write(sbs->base + address, data); - return (err); -} - -static int -acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr, - char read_write, u8 command, int size, - union sbs_rw_data *data) -{ - unsigned char protocol, len = 0, temp[2] = { 0, 0 }; - int i; - - if (read_write == ACPI_SBS_SMBUS_READ) { - protocol = ACPI_EC_SMB_PRTCL_READ; - } else { - protocol = ACPI_EC_SMB_PRTCL_WRITE; - } - - switch (size) { - - case ACPI_SBS_WORD_DATA: - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command); - if (read_write == ACPI_SBS_SMBUS_WRITE) { - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA, data->word); - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + 1, - data->word >> 8); - } - protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA; - break; - case ACPI_SBS_BLOCK_DATA: - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command); - if (read_write == ACPI_SBS_SMBUS_WRITE) { - len = min_t(u8, data->block[0], 32); - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_BCNT, len); - for (i = 0; i < len; i++) - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + i, - data->block[i + 1]); - } - protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA; - break; - default: - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "unsupported transaction %d", size)); - return (-1); - } - - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_ADDR, addr << 1); - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_PRTCL, protocol); - - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp); - - if (~temp[0] & ACPI_EC_SMB_STS_DONE) { - xmsleep(ACPI_EC_SMB_ACCESS_SLEEP1); - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp); - } - if (~temp[0] & ACPI_EC_SMB_STS_DONE) { - xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2); - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp); - } - if ((~temp[0] & ACPI_EC_SMB_STS_DONE) - || (temp[0] & ACPI_EC_SMB_STS_STATUS)) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "transaction %d error", size)); - return (-1); - } - - if (read_write == ACPI_SBS_SMBUS_WRITE) { - return (0); - } - - switch (size) { - - case ACPI_SBS_WORD_DATA: - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA, temp); - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + 1, temp + 1); - data->word = (temp[1] << 8) | temp[0]; - break; - - case ACPI_SBS_BLOCK_DATA: - len = 0; - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_BCNT, &len); - len = min_t(u8, len, 32); - for (i = 0; i < len; i++) - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + i, - data->block + i + 1); - data->block[0] = len; - break; - default: - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "unsupported transaction %d", size)); - return (-1); - } - - return (0); -} - -static int -acpi_sbs_read_word(struct acpi_sbs *sbs, int addr, int func, u16 * word) -{ - union sbs_rw_data data; - int result = 0; - - result = acpi_ec_sbs_access(sbs, addr, - ACPI_SBS_SMBUS_READ, func, - ACPI_SBS_WORD_DATA, &data); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_ec_sbs_access() failed")); - } else { - *word = data.word; - } - - return result; -} - -static int -acpi_sbs_read_str(struct acpi_sbs *sbs, int addr, int func, char *str) -{ - union sbs_rw_data data; - int result = 0; - - result = acpi_ec_sbs_access(sbs, addr, - ACPI_SBS_SMBUS_READ, func, - ACPI_SBS_BLOCK_DATA, &data); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_ec_sbs_access() failed")); - } else { - strncpy(str, (const char *)data.block + 1, data.block[0]); - str[data.block[0]] = 0; - } - - return result; -} - -static int -acpi_sbs_write_word(struct acpi_sbs *sbs, int addr, int func, int word) -{ - union sbs_rw_data data; - int result = 0; - - data.word = word; - - result = acpi_ec_sbs_access(sbs, addr, - ACPI_SBS_SMBUS_WRITE, func, - ACPI_SBS_WORD_DATA, &data); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_ec_sbs_access() failed")); - } - - return result; -} - static int sbs_zombie(struct acpi_sbs *sbs) { return (sbs->zombie); @@ -433,11 +222,11 @@ static int acpi_battery_get_present(struct acpi_battery *battery) int result = 0; int is_present = 0; - result = acpi_sbs_read_word(battery->sbs, - ACPI_SBSM_SMBUS_ADDR, 0x01, &state); + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, + ACPI_SBSM_SMBUS_ADDR, 0x01, (u8 *)&state); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + "acpi_smbus_read() failed")); } if (!result) { is_present = (state & 0x000f) & (1 << battery->id); @@ -461,19 +250,19 @@ static int acpi_battery_select(struct acpi_battery *battery) * it causes charging to halt on SBSELs */ result = - acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, &state); + acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SBSM_SMBUS_ADDR, 0x01, (u8 *)&state); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + "acpi_smbus_read() failed")); goto end; } foo = (state & 0x0fff) | (1 << (battery->id + 12)); result = - acpi_sbs_write_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, foo); + acpi_smbus_write(battery->sbs->hc, SMBUS_WRITE_WORD, ACPI_SBSM_SMBUS_ADDR, 0x01, (u8 *)&foo, 2); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_write_word() failed")); + "acpi_smbus_write() failed")); goto end; } } @@ -487,11 +276,11 @@ static int acpi_sbsm_get_info(struct acpi_sbs *sbs) int result = 0; s16 battery_system_info; - result = acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x04, - &battery_system_info); + result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBSM_SMBUS_ADDR, 0x04, + (u8 *)&battery_system_info); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + "acpi_smbus_read() failed")); goto end; } sbs->sbsm_present = 1; @@ -504,50 +293,49 @@ static int acpi_sbsm_get_info(struct acpi_sbs *sbs) static int acpi_battery_get_info(struct acpi_battery *battery) { - struct acpi_sbs *sbs = battery->sbs; int result = 0; s16 battery_mode; s16 specification_info; - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03, - &battery_mode); + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x03, + (u8 *)&battery_mode); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + "acpi_smbus_read() failed")); goto end; } battery->info.capacity_mode = (battery_mode & 0x8000) >> 15; - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x10, - &battery->info.full_charge_capacity); + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x10, + (u8 *)&battery->info.full_charge_capacity); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + "acpi_smbus_read() failed")); goto end; } - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x18, - &battery->info.design_capacity); + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x18, + (u8 *)&battery->info.design_capacity); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + "acpi_smbus_read() failed")); goto end; } - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x19, - &battery->info.design_voltage); + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x19, + (u8 *)&battery->info.design_voltage); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + "acpi_smbus_read() failed")); goto end; } - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1a, - &specification_info); + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x1a, + (u8 *)&specification_info); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + "acpi_smbus_read() failed")); goto end; } @@ -579,32 +367,32 @@ static int acpi_battery_get_info(struct acpi_battery *battery) battery->info.ipscale = 1; } - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1c, - &battery->info.serial_number); + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x1c, + (u8 *)&battery->info.serial_number); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + "acpi_smbus_read() failed")); goto end; } - result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x20, - battery->info.manufacturer_name); + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_BLOCK, ACPI_SB_SMBUS_ADDR, 0x20, + (u8 *)battery->info.manufacturer_name); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_sbs_read_str() failed")); goto end; } - result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x21, - battery->info.device_name); + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_BLOCK, ACPI_SB_SMBUS_ADDR, 0x21, + (u8 *)battery->info.device_name); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_sbs_read_str() failed")); goto end; } - result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x22, - battery->info.device_chemistry); + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_BLOCK, ACPI_SB_SMBUS_ADDR, 0x22, + (u8 *)battery->info.device_chemistry); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_sbs_read_str() failed")); @@ -617,38 +405,37 @@ static int acpi_battery_get_info(struct acpi_battery *battery) static int acpi_battery_get_state(struct acpi_battery *battery) { - struct acpi_sbs *sbs = battery->sbs; int result = 0; - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x09, - &battery->state.voltage); + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x09, + (u8 *)&battery->state.voltage); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + "acpi_smbus_read() failed")); goto end; } - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0a, - &battery->state.amperage); + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x0a, + (u8 *)&battery->state.amperage); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + "acpi_smbus_read() failed")); goto end; } - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0f, - &battery->state.remaining_capacity); + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x0f, + (u8 *)&battery->state.remaining_capacity); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + "acpi_smbus_read() failed")); goto end; } - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x16, - &battery->state.battery_state); + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x16, + (u8 *)&battery->state.battery_state); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + "acpi_smbus_read() failed")); goto end; } @@ -658,14 +445,13 @@ static int acpi_battery_get_state(struct acpi_battery *battery) static int acpi_battery_get_alarm(struct acpi_battery *battery) { - struct acpi_sbs *sbs = battery->sbs; int result = 0; - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01, - &battery->alarm.remaining_capacity); + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x01, + (u8 *)&battery->alarm.remaining_capacity); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + "acpi_smbus_read() failed")); goto end; } @@ -677,7 +463,6 @@ static int acpi_battery_get_alarm(struct acpi_battery *battery) static int acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm) { - struct acpi_sbs *sbs = battery->sbs; int result = 0; s16 battery_mode; int foo; @@ -693,29 +478,30 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery, if (alarm > 0) { result = - acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03, - &battery_mode); + acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x03, + (u8 *)&battery_mode); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + "acpi_smbus_read() failed")); goto end; } + battery_mode &= 0xbfff; result = - acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01, - battery_mode & 0xbfff); + acpi_smbus_write(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x01, + (u8 *)&battery_mode, 2); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_write_word() failed")); + "acpi_smbus_write() failed")); goto end; } } foo = alarm / (battery->info.capacity_mode ? 10 : 1); - result = acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01, foo); + result = acpi_smbus_write(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x01, (u8 *)&foo, 2); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_write_word() failed")); + "acpi_smbus_write() failed")); goto end; } @@ -726,7 +512,6 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery, static int acpi_battery_set_mode(struct acpi_battery *battery) { - struct acpi_sbs *sbs = battery->sbs; int result = 0; s16 battery_mode; @@ -734,11 +519,11 @@ static int acpi_battery_set_mode(struct acpi_battery *battery) goto end; } - result = acpi_sbs_read_word(sbs, - ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode); + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, + ACPI_SB_SMBUS_ADDR, 0x03, (u8 *)&battery_mode); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + "acpi_smbus_read() failed")); goto end; } @@ -747,19 +532,19 @@ static int acpi_battery_set_mode(struct acpi_battery *battery) } else { battery_mode |= 0x8000; } - result = acpi_sbs_write_word(sbs, - ACPI_SB_SMBUS_ADDR, 0x03, battery_mode); + result = acpi_smbus_write(battery->sbs->hc, SMBUS_READ_WORD, + ACPI_SB_SMBUS_ADDR, 0x03, (u8 *)&battery_mode, 2); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_write_word() failed")); + "acpi_smbus_write() failed")); goto end; } - result = acpi_sbs_read_word(sbs, - ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode); + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, + ACPI_SB_SMBUS_ADDR, 0x03, (u8 *)&battery_mode); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + "acpi_smbus_read() failed")); goto end; } @@ -815,12 +600,12 @@ static int acpi_ac_get_present(struct acpi_sbs *sbs) int result = 0; s16 charger_status; - result = acpi_sbs_read_word(sbs, ACPI_SBC_SMBUS_ADDR, 0x13, - &charger_status); + result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBC_SMBUS_ADDR, 0x13, + (u8 *)&charger_status); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + "acpi_smbus_read() failed")); goto end; } @@ -1614,15 +1399,6 @@ static int acpi_sbs_add(struct acpi_device *device) struct acpi_sbs *sbs = NULL; int result = 0, remove_result = 0; int id; - acpi_status status = AE_OK; - unsigned long val; - - status = - acpi_evaluate_integer(device->handle, "_EC", NULL, &val); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Error obtaining _EC")); - return -EIO; - } sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL); if (!sbs) { @@ -1635,8 +1411,8 @@ static int acpi_sbs_add(struct acpi_device *device) sbs_mutex_lock(sbs); - sbs->base = 0xff & (val >> 8); sbs->device = device; + sbs->hc = acpi_driver_data(device->parent); strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_SBS_CLASS); diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c new file mode 100644 index 0000000..046d7c3 --- /dev/null +++ b/drivers/acpi/sbshc.c @@ -0,0 +1,309 @@ +/* + * SMBus driver for ACPI Embedded Controller (v0.1) + * + * Copyright (c) 2007 Alexey Starikovskiy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2. + */ + +#include +#include +#include +#include +#include +#include +#include "sbshc.h" + +#define ACPI_SMB_HC_CLASS "smbus_host_controller" +#define ACPI_SMB_HC_DEVICE_NAME "ACPI SMBus HC" + +struct acpi_smb_hc { + struct acpi_ec *ec; + struct mutex lock; + wait_queue_head_t wait; + u8 offset; + u8 query_bit; + smbus_alarm_callback callback; + void *context; +}; + +static int acpi_smbus_hc_add(struct acpi_device *device); +static int acpi_smbus_hc_remove(struct acpi_device *device, int type); + +static const struct acpi_device_id sbs_device_ids[] = { + {"ACPI0001", 0}, + {"ACPI0005", 0}, + {"", 0}, +}; + +MODULE_DEVICE_TABLE(acpi, sbs_device_ids); + +static struct acpi_driver acpi_smb_hc_driver = { + .name = "smbus_hc", + .class = ACPI_SMB_HC_CLASS, + .ids = sbs_device_ids, + .ops = { + .add = acpi_smbus_hc_add, + .remove = acpi_smbus_hc_remove, + }, +}; + +union acpi_smb_status { + u8 raw; + struct { + u8 status:5; + u8 reserved:1; + u8 alarm:1; + u8 done:1; + } fields; +}; + +enum acpi_smb_status_codes { + SMBUS_OK = 0, + SMBUS_UNKNOWN_FAILURE = 0x07, + SMBUS_DEVICE_ADDRESS_NACK = 0x10, + SMBUS_DEVICE_ERROR = 0x11, + SMBUS_DEVICE_COMMAND_ACCESS_DENIED = 0x12, + SMBUS_UNKNOWN_ERROR = 0x13, + SMBUS_DEVICE_ACCESS_DENIED = 0x17, + SMBUS_TIMEOUT = 0x18, + SMBUS_HOST_UNSUPPORTED_PROTOCOL = 0x19, + SMBUS_BUSY = 0x1a, + SMBUS_PEC_ERROR = 0x1f, +}; + +enum acpi_smb_offset { + ACPI_SMB_PROTOCOL = 0, /* protocol, PEC */ + ACPI_SMB_STATUS = 1, /* status */ + ACPI_SMB_ADDRESS = 2, /* address */ + ACPI_SMB_COMMAND = 3, /* command */ + ACPI_SMB_DATA = 4, /* 32 data registers */ + ACPI_SMB_BLOCK_COUNT = 0x24, /* number of data bytes */ + ACPI_SMB_ALARM_ADDRESS = 0x25, /* alarm address */ + ACPI_SMB_ALARM_DATA = 0x26, /* 2 bytes alarm data */ +}; + +static inline int smb_hc_read(struct acpi_smb_hc *hc, u8 address, u8 *data) +{ + return ec_read(hc->offset + address, data); +} + +static inline int smb_hc_write(struct acpi_smb_hc *hc, u8 address, u8 data) +{ + return ec_write(hc->offset + address, data); +} + +static inline int smb_check_done(struct acpi_smb_hc *hc) +{ + union acpi_smb_status status = {.raw = 0}; + smb_hc_read(hc, ACPI_SMB_STATUS, &status.raw); + return status.fields.done && (status.fields.status == SMBUS_OK); +} + +static int wait_transaction_complete(struct acpi_smb_hc *hc, int timeout) +{ + if (wait_event_timeout(hc->wait, smb_check_done(hc), + msecs_to_jiffies(timeout))) + return 0; + else + return -ETIME; +} + +int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol, u8 address, + u8 command, u8 *data, u8 length) +{ + int ret = -EFAULT, i; + u8 temp, sz = 0; + + mutex_lock(&hc->lock); + if (smb_hc_read(hc, ACPI_SMB_PROTOCOL, &temp)) + goto end; + if (temp) { + ret = -EBUSY; + goto end; + } + smb_hc_write(hc, ACPI_SMB_COMMAND, command); + smb_hc_write(hc, ACPI_SMB_COMMAND, command); + if (!(protocol & 0x01)) { + smb_hc_write(hc, ACPI_SMB_BLOCK_COUNT, length); + for (i = 0; i < length; ++i) + smb_hc_write(hc, ACPI_SMB_DATA + i, data[i]); + } + smb_hc_write(hc, ACPI_SMB_ADDRESS, address << 1); + smb_hc_write(hc, ACPI_SMB_PROTOCOL, protocol); + /* + * Wait for completion. Save the status code, data size, + * and data into the return package (if required by the protocol). + */ + ret = wait_transaction_complete(hc, 1000); + if (ret || !(protocol & 0x01)) + goto end; + switch (protocol) { + case SMBUS_RECEIVE_BYTE: + case SMBUS_READ_BYTE: + sz = 1; + break; + case SMBUS_READ_WORD: + sz = 2; + break; + case SMBUS_READ_BLOCK: + if (smb_hc_read(hc, ACPI_SMB_BLOCK_COUNT, &sz)) { + ret = -EFAULT; + goto end; + } + sz &= 0x1f; + break; + } + for (i = 0; i < sz; ++i) + smb_hc_read(hc, ACPI_SMB_DATA + i, &data[i]); + end: + mutex_unlock(&hc->lock); + return ret; +} + +int acpi_smbus_read(struct acpi_smb_hc *hc, u8 protocol, u8 address, + u8 command, u8 *data) +{ + return acpi_smbus_transaction(hc, protocol, address, command, data, 0); +} + +EXPORT_SYMBOL_GPL(acpi_smbus_read); + +int acpi_smbus_write(struct acpi_smb_hc *hc, u8 protocol, u8 address, + u8 command, u8 *data, u8 length) +{ + return acpi_smbus_transaction(hc, protocol, address, command, data, length); +} + +EXPORT_SYMBOL_GPL(acpi_smbus_write); + +int acpi_smbus_register_callback(struct acpi_smb_hc *hc, + smbus_alarm_callback callback, void *context) +{ + mutex_lock(&hc->lock); + hc->callback = callback; + hc->context = context; + mutex_unlock(&hc->lock); + return 0; +} + +EXPORT_SYMBOL_GPL(acpi_smbus_register_callback); + +int acpi_smbus_unregister_callback(struct acpi_smb_hc *hc) +{ + mutex_lock(&hc->lock); + hc->callback = NULL; + hc->context = NULL; + mutex_unlock(&hc->lock); + return 0; +} + +EXPORT_SYMBOL_GPL(acpi_smbus_unregister_callback); + +static void acpi_smbus_callback(void *context) +{ + struct acpi_smb_hc *hc = context; + + if (hc->callback) + hc->callback(hc->context); +} + +static int smbus_alarm(void *context) +{ + struct acpi_smb_hc *hc = context; + union acpi_smb_status status; + if (smb_hc_read(hc, ACPI_SMB_STATUS, &status.raw)) + return 0; + /* Check if it is only a completion notify */ + if (status.fields.done) + wake_up(&hc->wait); + if (!status.fields.alarm) + return 0; + mutex_lock(&hc->lock); + smb_hc_write(hc, ACPI_SMB_STATUS, status.raw); + if (hc->callback) + acpi_os_execute(OSL_GPE_HANDLER, acpi_smbus_callback, hc); + mutex_unlock(&hc->lock); + return 0; +} + +typedef int (*acpi_ec_query_func) (void *data); + +extern int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, + acpi_handle handle, acpi_ec_query_func func, + void *data); + +static int acpi_smbus_hc_add(struct acpi_device *device) +{ + int status; + unsigned long val; + struct acpi_smb_hc *hc; + + if (!device) + return -EINVAL; + + status = acpi_evaluate_integer(device->handle, "_EC", NULL, &val); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "error obtaining _EC.\n"); + return -EIO; + } + + strcpy(acpi_device_name(device), ACPI_SMB_HC_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_SMB_HC_CLASS); + + hc = kzalloc(sizeof(struct acpi_smb_hc), GFP_KERNEL); + if (!hc) + return -ENOMEM; + mutex_init(&hc->lock); + init_waitqueue_head(&hc->wait); + + hc->ec = acpi_driver_data(device->parent); + hc->offset = (val >> 8) & 0xff; + hc->query_bit = val & 0xff; + acpi_driver_data(device) = hc; + + acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc); + printk(KERN_INFO PREFIX "SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x\n", + hc->ec, hc->offset, hc->query_bit); + + return 0; +} + +extern void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit); + +static int acpi_smbus_hc_remove(struct acpi_device *device, int type) +{ + struct acpi_smb_hc *hc; + + if (!device) + return -EINVAL; + + hc = acpi_driver_data(device); + acpi_ec_remove_query_handler(hc->ec, hc->query_bit); + kfree(hc); + return 0; +} + +static int __init acpi_smb_hc_init(void) +{ + int result; + + result = acpi_bus_register_driver(&acpi_smb_hc_driver); + if (result < 0) + return -ENODEV; + return 0; +} + +static void __exit acpi_smb_hc_exit(void) +{ + acpi_bus_unregister_driver(&acpi_smb_hc_driver); +} + +module_init(acpi_smb_hc_init); +module_exit(acpi_smb_hc_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Alexey Starikovskiy"); +MODULE_DESCRIPTION("ACPI SMBus HC driver"); diff --git a/drivers/acpi/sbshc.h b/drivers/acpi/sbshc.h new file mode 100644 index 0000000..3bda349 --- /dev/null +++ b/drivers/acpi/sbshc.h @@ -0,0 +1,27 @@ +struct acpi_smb_hc; +enum acpi_smb_protocol { + SMBUS_WRITE_QUICK = 2, + SMBUS_READ_QUICK = 3, + SMBUS_SEND_BYTE = 4, + SMBUS_RECEIVE_BYTE = 5, + SMBUS_WRITE_BYTE = 6, + SMBUS_READ_BYTE = 7, + SMBUS_WRITE_WORD = 8, + SMBUS_READ_WORD = 9, + SMBUS_WRITE_BLOCK = 0xa, + SMBUS_READ_BLOCK = 0xb, + SMBUS_PROCESS_CALL = 0xc, + SMBUS_BLOCK_PROCESS_CALL = 0xd, +}; + +static const u8 SMBUS_PEC = 0x80; + +typedef void (*smbus_alarm_callback)(void *context); + +extern int acpi_smbus_read(struct acpi_smb_hc *hc, u8 protocol, u8 address, + u8 command, u8 * data); +extern int acpi_smbus_write(struct acpi_smb_hc *hc, u8 protocol, u8 slave_address, + u8 command, u8 * data, u8 length); +extern int acpi_smbus_register_callback(struct acpi_smb_hc *hc, + smbus_alarm_callback callback, void *context); +extern int acpi_smbus_unregister_callback(struct acpi_smb_hc *hc); -- cgit v1.1 From 89862e3be1ba387c738fc2c3a5875cfd7e51c5a8 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Wed, 26 Sep 2007 19:43:35 +0400 Subject: ACPI: SBS: Simplify data structures in SBS Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/sbs.c | 282 +++++++++++++++++++++++++---------------------------- 1 file changed, 135 insertions(+), 147 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 7bb8c62..f35fe63 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -88,10 +88,10 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); /* 0 - every time, > 0 - by update_time */ static unsigned int update_time = 120; -static unsigned int capacity_mode = CAPACITY_UNIT; +static unsigned int mode = CAPACITY_UNIT; module_param(update_time, uint, 0644); -module_param(capacity_mode, uint, 0444); +module_param(mode, uint, 0444); static int acpi_sbs_add(struct acpi_device *device); static int acpi_sbs_remove(struct acpi_device *device, int type); @@ -114,59 +114,43 @@ static struct acpi_driver acpi_sbs_driver = { }, }; -struct acpi_ac { - int ac_present; -}; - -struct acpi_battery_info { - int capacity_mode; - s16 full_charge_capacity; - s16 design_capacity; - s16 design_voltage; - int vscale; - int ipscale; - s16 serial_number; - char manufacturer_name[ACPI_SBS_BLOCK_MAX + 3]; - char device_name[ACPI_SBS_BLOCK_MAX + 3]; - char device_chemistry[ACPI_SBS_BLOCK_MAX + 3]; -}; - -struct acpi_battery_state { - s16 voltage; - s16 amperage; - s16 remaining_capacity; - s16 battery_state; -}; - -struct acpi_battery_alarm { - s16 remaining_capacity; -}; - struct acpi_battery { - int alive; - int id; - int init_state; - int battery_present; struct acpi_sbs *sbs; - struct acpi_battery_info info; - struct acpi_battery_state state; - struct acpi_battery_alarm alarm; - struct proc_dir_entry *battery_entry; + struct proc_dir_entry *proc_entry; + int vscale; + int ipscale; + char manufacturer_name[ACPI_SBS_BLOCK_MAX]; + char device_name[ACPI_SBS_BLOCK_MAX]; + char device_chemistry[ACPI_SBS_BLOCK_MAX]; + u16 full_charge_capacity; + u16 design_capacity; + u16 design_voltage; + u16 serial_number; + u16 voltage_now; + s16 current_now; + u16 capacity_now; + u16 state; + u16 alarm_capacity; + u16 mode; + u8 id; + u8 alive:1; + u8 init_state:1; + u8 present:1; }; struct acpi_sbs { struct acpi_device *device; struct acpi_smb_hc *hc; struct mutex mutex; - int sbsm_present; - int sbsm_batteries_supported; struct proc_dir_entry *ac_entry; - struct acpi_ac ac; struct acpi_battery battery[MAX_SBS_BAT]; int zombie; struct timer_list update_timer; int run_cnt; int update_proc_flg; + u8 batteries_supported; + u8 manager_present:1; + u8 charger_present:1; }; static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type); @@ -231,7 +215,7 @@ static int acpi_battery_get_present(struct acpi_battery *battery) if (!result) { is_present = (state & 0x000f) & (1 << battery->id); } - battery->battery_present = is_present; + battery->present = is_present; return result; } @@ -243,14 +227,14 @@ static int acpi_battery_select(struct acpi_battery *battery) s16 state; int foo; - if (sbs->sbsm_present) { + if (sbs->manager_present) { /* Take special care not to knobble other nibbles of * state (aka selector_state), since * it causes charging to halt on SBSELs */ - result = - acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SBSM_SMBUS_ADDR, 0x01, (u8 *)&state); + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, + ACPI_SBSM_SMBUS_ADDR, 0x01, (u8 *)&state); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_smbus_read() failed")); @@ -258,8 +242,8 @@ static int acpi_battery_select(struct acpi_battery *battery) } foo = (state & 0x0fff) | (1 << (battery->id + 12)); - result = - acpi_smbus_write(battery->sbs->hc, SMBUS_WRITE_WORD, ACPI_SBSM_SMBUS_ADDR, 0x01, (u8 *)&foo, 2); + result = acpi_smbus_write(battery->sbs->hc, SMBUS_WRITE_WORD, + ACPI_SBSM_SMBUS_ADDR, 0x01, (u8 *)&foo, 2); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_smbus_write() failed")); @@ -283,8 +267,7 @@ static int acpi_sbsm_get_info(struct acpi_sbs *sbs) "acpi_smbus_read() failed")); goto end; } - sbs->sbsm_present = 1; - sbs->sbsm_batteries_supported = battery_system_info & 0x000f; + sbs->manager_present = 1; end: @@ -304,10 +287,10 @@ static int acpi_battery_get_info(struct acpi_battery *battery) "acpi_smbus_read() failed")); goto end; } - battery->info.capacity_mode = (battery_mode & 0x8000) >> 15; + battery->mode = (battery_mode & 0x8000) >> 15; result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x10, - (u8 *)&battery->info.full_charge_capacity); + (u8 *)&battery->full_charge_capacity); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_smbus_read() failed")); @@ -315,7 +298,7 @@ static int acpi_battery_get_info(struct acpi_battery *battery) } result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x18, - (u8 *)&battery->info.design_capacity); + (u8 *)&battery->design_capacity); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, @@ -324,7 +307,7 @@ static int acpi_battery_get_info(struct acpi_battery *battery) } result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x19, - (u8 *)&battery->info.design_voltage); + (u8 *)&battery->design_voltage); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_smbus_read() failed")); @@ -341,34 +324,34 @@ static int acpi_battery_get_info(struct acpi_battery *battery) switch ((specification_info & 0x0f00) >> 8) { case 1: - battery->info.vscale = 10; + battery->vscale = 10; break; case 2: - battery->info.vscale = 100; + battery->vscale = 100; break; case 3: - battery->info.vscale = 1000; + battery->vscale = 1000; break; default: - battery->info.vscale = 1; + battery->vscale = 1; } switch ((specification_info & 0xf000) >> 12) { case 1: - battery->info.ipscale = 10; + battery->ipscale = 10; break; case 2: - battery->info.ipscale = 100; + battery->ipscale = 100; break; case 3: - battery->info.ipscale = 1000; + battery->ipscale = 1000; break; default: - battery->info.ipscale = 1; + battery->ipscale = 1; } result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x1c, - (u8 *)&battery->info.serial_number); + (u8 *)&battery->serial_number); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_smbus_read() failed")); @@ -376,7 +359,7 @@ static int acpi_battery_get_info(struct acpi_battery *battery) } result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_BLOCK, ACPI_SB_SMBUS_ADDR, 0x20, - (u8 *)battery->info.manufacturer_name); + (u8 *)battery->manufacturer_name); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_sbs_read_str() failed")); @@ -384,7 +367,7 @@ static int acpi_battery_get_info(struct acpi_battery *battery) } result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_BLOCK, ACPI_SB_SMBUS_ADDR, 0x21, - (u8 *)battery->info.device_name); + (u8 *)battery->device_name); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_sbs_read_str() failed")); @@ -392,7 +375,7 @@ static int acpi_battery_get_info(struct acpi_battery *battery) } result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_BLOCK, ACPI_SB_SMBUS_ADDR, 0x22, - (u8 *)battery->info.device_chemistry); + (u8 *)battery->device_chemistry); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_sbs_read_str() failed")); @@ -408,7 +391,7 @@ static int acpi_battery_get_state(struct acpi_battery *battery) int result = 0; result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x09, - (u8 *)&battery->state.voltage); + (u8 *)&battery->voltage_now); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_smbus_read() failed")); @@ -416,7 +399,7 @@ static int acpi_battery_get_state(struct acpi_battery *battery) } result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x0a, - (u8 *)&battery->state.amperage); + (u8 *)&battery->current_now); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_smbus_read() failed")); @@ -424,7 +407,7 @@ static int acpi_battery_get_state(struct acpi_battery *battery) } result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x0f, - (u8 *)&battery->state.remaining_capacity); + (u8 *)&battery->capacity_now); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_smbus_read() failed")); @@ -432,7 +415,7 @@ static int acpi_battery_get_state(struct acpi_battery *battery) } result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x16, - (u8 *)&battery->state.battery_state); + (u8 *)&battery->state); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_smbus_read() failed")); @@ -448,7 +431,7 @@ static int acpi_battery_get_alarm(struct acpi_battery *battery) int result = 0; result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x01, - (u8 *)&battery->alarm.remaining_capacity); + (u8 *)&battery->alarm_capacity); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_smbus_read() failed")); @@ -497,8 +480,9 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery, } } - foo = alarm / (battery->info.capacity_mode ? 10 : 1); - result = acpi_smbus_write(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x01, (u8 *)&foo, 2); + foo = alarm / (battery->mode ? 10 : 1); + result = acpi_smbus_write(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x01, + (u8 *)&foo, 2); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_smbus_write() failed")); @@ -515,25 +499,25 @@ static int acpi_battery_set_mode(struct acpi_battery *battery) int result = 0; s16 battery_mode; - if (capacity_mode == DEF_CAPACITY_UNIT) { + if (mode == DEF_CAPACITY_UNIT) { goto end; } result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, - ACPI_SB_SMBUS_ADDR, 0x03, (u8 *)&battery_mode); + ACPI_SB_SMBUS_ADDR, 0x03, (u8 *)&battery_mode); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_smbus_read() failed")); goto end; } - if (capacity_mode == MAH_CAPACITY_UNIT) { + if (mode == MAH_CAPACITY_UNIT) { battery_mode &= 0x7fff; } else { battery_mode |= 0x8000; } result = acpi_smbus_write(battery->sbs->hc, SMBUS_READ_WORD, - ACPI_SB_SMBUS_ADDR, 0x03, (u8 *)&battery_mode, 2); + ACPI_SB_SMBUS_ADDR, 0x03, (u8 *)&battery_mode, 2); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_smbus_write() failed")); @@ -541,7 +525,7 @@ static int acpi_battery_set_mode(struct acpi_battery *battery) } result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, - ACPI_SB_SMBUS_ADDR, 0x03, (u8 *)&battery_mode); + ACPI_SB_SMBUS_ADDR, 0x03, (u8 *)&battery_mode); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_smbus_read() failed")); @@ -601,7 +585,7 @@ static int acpi_ac_get_present(struct acpi_sbs *sbs) s16 charger_status; result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBC_SMBUS_ADDR, 0x13, - (u8 *)&charger_status); + (u8 *)&charger_status); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, @@ -609,7 +593,7 @@ static int acpi_ac_get_present(struct acpi_sbs *sbs) goto end; } - sbs->ac.ac_present = (charger_status & 0x8000) >> 15; + sbs->charger_present = (charger_status & 0x8000) >> 15; end: @@ -726,30 +710,30 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset) } } - if (battery->battery_present) { + if (battery->present) { seq_printf(seq, "present: yes\n"); } else { seq_printf(seq, "present: no\n"); goto end; } - if (battery->info.capacity_mode) { - cscale = battery->info.vscale * battery->info.ipscale; + if (battery->mode) { + cscale = battery->vscale * battery->ipscale; } else { - cscale = battery->info.ipscale; + cscale = battery->ipscale; } seq_printf(seq, "design capacity: %i%s\n", - battery->info.design_capacity * cscale, - battery->info.capacity_mode ? "0 mWh" : " mAh"); + battery->design_capacity * cscale, + battery->mode ? "0 mWh" : " mAh"); seq_printf(seq, "last full capacity: %i%s\n", - battery->info.full_charge_capacity * cscale, - battery->info.capacity_mode ? "0 mWh" : " mAh"); + battery->full_charge_capacity * cscale, + battery->mode ? "0 mWh" : " mAh"); seq_printf(seq, "battery technology: rechargeable\n"); seq_printf(seq, "design voltage: %i mV\n", - battery->info.design_voltage * battery->info.vscale); + battery->design_voltage * battery->vscale); seq_printf(seq, "design capacity warning: unknown\n"); seq_printf(seq, "design capacity low: unknown\n"); @@ -757,16 +741,16 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset) seq_printf(seq, "capacity granularity 2: unknown\n"); seq_printf(seq, "model number: %s\n", - battery->info.device_name); + battery->device_name); seq_printf(seq, "serial number: %i\n", - battery->info.serial_number); + battery->serial_number); seq_printf(seq, "battery type: %s\n", - battery->info.device_chemistry); + battery->device_chemistry); seq_printf(seq, "OEM info: %s\n", - battery->info.manufacturer_name); + battery->manufacturer_name); end: @@ -804,49 +788,49 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset) } } - if (battery->battery_present) { + if (battery->present) { seq_printf(seq, "present: yes\n"); } else { seq_printf(seq, "present: no\n"); goto end; } - if (battery->info.capacity_mode) { - cscale = battery->info.vscale * battery->info.ipscale; + if (battery->mode) { + cscale = battery->vscale * battery->ipscale; } else { - cscale = battery->info.ipscale; + cscale = battery->ipscale; } - if (battery->state.battery_state & 0x0010) { + if (battery->state & 0x0010) { seq_printf(seq, "capacity state: critical\n"); } else { seq_printf(seq, "capacity state: ok\n"); } - foo = (s16) battery->state.amperage * battery->info.ipscale; - if (battery->info.capacity_mode) { - foo = foo * battery->info.design_voltage / 1000; + foo = (s16) battery->current_now * battery->ipscale; + if (battery->mode) { + foo = foo * battery->design_voltage / 1000; } - if (battery->state.amperage < 0) { + if (battery->current_now < 0) { seq_printf(seq, "charging state: discharging\n"); seq_printf(seq, "present rate: %d %s\n", - -foo, battery->info.capacity_mode ? "mW" : "mA"); - } else if (battery->state.amperage > 0) { + -foo, battery->mode ? "mW" : "mA"); + } else if (battery->current_now > 0) { seq_printf(seq, "charging state: charging\n"); seq_printf(seq, "present rate: %d %s\n", - foo, battery->info.capacity_mode ? "mW" : "mA"); + foo, battery->mode ? "mW" : "mA"); } else { seq_printf(seq, "charging state: charged\n"); seq_printf(seq, "present rate: 0 %s\n", - battery->info.capacity_mode ? "mW" : "mA"); + battery->mode ? "mW" : "mA"); } seq_printf(seq, "remaining capacity: %i%s\n", - battery->state.remaining_capacity * cscale, - battery->info.capacity_mode ? "0 mWh" : " mAh"); + battery->capacity_now * cscale, + battery->mode ? "0 mWh" : " mAh"); seq_printf(seq, "present voltage: %i mV\n", - battery->state.voltage * battery->info.vscale); + battery->voltage_now * battery->vscale); end: @@ -883,22 +867,22 @@ static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) } } - if (!battery->battery_present) { + if (!battery->present) { seq_printf(seq, "present: no\n"); goto end; } - if (battery->info.capacity_mode) { - cscale = battery->info.vscale * battery->info.ipscale; + if (battery->mode) { + cscale = battery->vscale * battery->ipscale; } else { - cscale = battery->info.ipscale; + cscale = battery->ipscale; } seq_printf(seq, "alarm: "); - if (battery->alarm.remaining_capacity) { + if (battery->alarm_capacity) { seq_printf(seq, "%i%s\n", - battery->alarm.remaining_capacity * cscale, - battery->info.capacity_mode ? "0 mWh" : " mAh"); + battery->alarm_capacity * cscale, + battery->mode ? "0 mWh" : " mAh"); } else { seq_printf(seq, "disabled\n"); } @@ -928,7 +912,7 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer, if (result) goto end; - if (!battery->battery_present) { + if (!battery->present) { result = -ENODEV; goto end; } @@ -945,7 +929,7 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer, alarm_string[count] = 0; - old_alarm = battery->alarm.remaining_capacity; + old_alarm = battery->alarm_capacity; new_alarm = simple_strtoul(alarm_string, NULL, 0); result = acpi_battery_set_alarm(battery, new_alarm); @@ -1025,7 +1009,7 @@ static int acpi_ac_read_state(struct seq_file *seq, void *offset) } seq_printf(seq, "state: %s\n", - sbs->ac.ac_present ? "on-line" : "off-line"); + sbs->charger_present ? "on-line" : "off-line"); sbs_mutex_unlock(sbs); @@ -1080,7 +1064,7 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) goto end; } - is_present = battery->battery_present; + is_present = battery->present; if (is_present) { result = acpi_battery_init(battery); @@ -1094,7 +1078,7 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id); - result = acpi_sbs_generic_add_fs(&battery->battery_entry, + result = acpi_sbs_generic_add_fs(&battery->proc_entry, acpi_battery_dir, dir_name, &acpi_battery_info_fops, @@ -1109,7 +1093,7 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n", ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), dir_name, - sbs->battery->battery_present ? "present" : "absent"); + sbs->battery->present ? "present" : "absent"); end: return result; @@ -1118,8 +1102,8 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) static void acpi_battery_remove(struct acpi_sbs *sbs, int id) { - if (sbs->battery[id].battery_entry) { - acpi_sbs_generic_remove_fs(&(sbs->battery[id].battery_entry), + if (sbs->battery[id].proc_entry) { + acpi_sbs_generic_remove_fs(&(sbs->battery[id].proc_entry), acpi_battery_dir); } } @@ -1147,7 +1131,7 @@ static int acpi_ac_add(struct acpi_sbs *sbs) printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n", ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), - ACPI_AC_DIR_NAME, sbs->ac.ac_present ? "on-line" : "off-line"); + ACPI_AC_DIR_NAME, sbs->charger_present ? "on-line" : "off-line"); end: @@ -1172,9 +1156,9 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type) struct acpi_battery *battery; int result = 0, cnt; int old_ac_present = -1; - int old_battery_present = -1; + int old_present = -1; int new_ac_present = -1; - int new_battery_present = -1; + int new_present = -1; int id_min = 0, id_max = MAX_SBS_BAT - 1; char dir_name[32]; int do_battery_init = 0, do_ac_init = 0; @@ -1199,7 +1183,11 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type) sbs->run_cnt++; - old_ac_present = sbs->ac.ac_present; + if (!update_battery) { + goto end; + } + + old_ac_present = sbs->charger_present; result = acpi_ac_get_present(sbs); if (result) { @@ -1207,7 +1195,7 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type) "acpi_ac_get_present() failed")); } - new_ac_present = sbs->ac.ac_present; + new_ac_present = sbs->charger_present; do_ac_init = (old_ac_present != new_ac_present); if (sbs->run_cnt == 1 && data_type == DATA_TYPE_COMMON) { @@ -1244,9 +1232,9 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type) continue; } - old_remaining_capacity = battery->state.remaining_capacity; + old_remaining_capacity = battery->capacity_now; - old_battery_present = battery->battery_present; + old_present = battery->present; result = acpi_battery_select(battery); if (result) { @@ -1260,11 +1248,11 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type) "acpi_battery_get_present() failed")); } - new_battery_present = battery->battery_present; + new_present = battery->present; - do_battery_init = ((old_battery_present != new_battery_present) - && new_battery_present); - if (!new_battery_present) + do_battery_init = ((old_present != new_present) + && new_present); + if (!new_present) goto event; if (do_ac_init || do_battery_init) { result = acpi_battery_init(battery); @@ -1280,7 +1268,7 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type) if ((data_type == DATA_TYPE_COMMON || data_type == DATA_TYPE_INFO) - && new_battery_present) { + && new_present) { result = acpi_battery_get_info(battery); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, @@ -1296,7 +1284,7 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type) if ((data_type == DATA_TYPE_COMMON || data_type == DATA_TYPE_STATE) - && new_battery_present) { + && new_present) { result = acpi_battery_get_state(battery); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, @@ -1312,7 +1300,7 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type) if ((data_type == DATA_TYPE_COMMON || data_type == DATA_TYPE_ALARM) - && new_battery_present) { + && new_present) { result = acpi_battery_get_alarm(battery); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, @@ -1329,17 +1317,17 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type) event: - if (old_battery_present != new_battery_present || do_ac_init || + if (old_present != new_present || do_ac_init || old_remaining_capacity != - battery->state.remaining_capacity) { + battery->capacity_now) { sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id); result = acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS, dir_name, ACPI_SBS_BATTERY_NOTIFY_STATUS, - new_battery_present); + new_present); acpi_bus_generate_netlink_event(ACPI_BATTERY_CLASS, dir_name, ACPI_SBS_BATTERY_NOTIFY_STATUS, - new_battery_present); + new_present); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_bus_generate_proc_event4() " @@ -1426,7 +1414,7 @@ static int acpi_sbs_add(struct acpi_device *device) acpi_sbsm_get_info(sbs); - if (!sbs->sbsm_present) { + if (!sbs->manager_present) { result = acpi_battery_add(sbs, 0); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, @@ -1435,7 +1423,7 @@ static int acpi_sbs_add(struct acpi_device *device) } } else { for (id = 0; id < MAX_SBS_BAT; id++) { - if ((sbs->sbsm_batteries_supported & (1 << id))) { + if ((sbs->batteries_supported & (1 << id))) { result = acpi_battery_add(sbs, id); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, @@ -1535,11 +1523,11 @@ static int __init acpi_sbs_init(void) if (acpi_disabled) return -ENODEV; - if (capacity_mode != DEF_CAPACITY_UNIT - && capacity_mode != MAH_CAPACITY_UNIT - && capacity_mode != MWH_CAPACITY_UNIT) { + if (mode != DEF_CAPACITY_UNIT + && mode != MAH_CAPACITY_UNIT + && mode != MWH_CAPACITY_UNIT) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "invalid capacity_mode = %d", capacity_mode)); + "invalid mode = %d", mode)); return -EINVAL; } -- cgit v1.1 From db1c291af7ad748777371f25b9ff92e3e5aba38e Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Wed, 26 Sep 2007 19:43:41 +0400 Subject: ACPI: SBS: Make SBS reads table-driven. Re-factor SBS functions to use tables and cycles for repeated operations. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/sbs.c | 1292 +++++++++++----------------------------------------- 1 file changed, 275 insertions(+), 1017 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index f35fe63..3351dea 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -1,6 +1,8 @@ /* - * acpi_sbs.c - ACPI Smart Battery System Driver ($Revision: 1.16 $) + * sbs.c - ACPI Smart Battery System Driver ($Revision: 2.0 $) * + * Copyright (c) 2007 Alexey Starikovskiy + * Copyright (c) 2005-2007 Vladimir Lebedev * Copyright (c) 2005 Rich Townsend * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -46,53 +48,34 @@ #define ACPI_SBS_FILE_ALARM "alarm" #define ACPI_BATTERY_DIR_NAME "BAT%i" #define ACPI_AC_DIR_NAME "AC0" -#define ACPI_SBC_SMBUS_ADDR 0x9 -#define ACPI_SBSM_SMBUS_ADDR 0xa -#define ACPI_SB_SMBUS_ADDR 0xb -#define ACPI_SBS_AC_NOTIFY_STATUS 0x80 -#define ACPI_SBS_BATTERY_NOTIFY_STATUS 0x80 -#define ACPI_SBS_BATTERY_NOTIFY_INFO 0x81 -#define _COMPONENT ACPI_SBS_COMPONENT +enum acpi_sbs_device_addr { + ACPI_SBS_CHARGER = 0x9, + ACPI_SBS_MANAGER = 0xa, + ACPI_SBS_BATTERY = 0xb, +}; + +#define ACPI_SBS_NOTIFY_STATUS 0x80 +#define ACPI_SBS_NOTIFY_INFO 0x81 ACPI_MODULE_NAME("sbs"); -MODULE_AUTHOR("Rich Townsend"); +MODULE_AUTHOR("Alexey Starikovskiy "); MODULE_DESCRIPTION("Smart Battery System ACPI interface driver"); MODULE_LICENSE("GPL"); -#define DEF_CAPACITY_UNIT 3 -#define MAH_CAPACITY_UNIT 1 -#define MWH_CAPACITY_UNIT 2 -#define CAPACITY_UNIT DEF_CAPACITY_UNIT - -#define REQUEST_UPDATE_MODE 1 -#define QUEUE_UPDATE_MODE 2 - -#define DATA_TYPE_COMMON 0 -#define DATA_TYPE_INFO 1 -#define DATA_TYPE_STATE 2 -#define DATA_TYPE_ALARM 3 -#define DATA_TYPE_AC_STATE 4 +static unsigned int cache_time = 1000; +module_param(cache_time, uint, 0644); +MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); extern struct proc_dir_entry *acpi_lock_ac_dir(void); extern struct proc_dir_entry *acpi_lock_battery_dir(void); extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir); extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); -#define MAX_SBS_BAT 4 +#define MAX_SBS_BAT 4 #define ACPI_SBS_BLOCK_MAX 32 -#define UPDATE_DELAY 10 - -/* 0 - every time, > 0 - by update_time */ -static unsigned int update_time = 120; - -static unsigned int mode = CAPACITY_UNIT; - -module_param(update_time, uint, 0644); -module_param(mode, uint, 0444); - static int acpi_sbs_add(struct acpi_device *device); static int acpi_sbs_remove(struct acpi_device *device, int type); static int acpi_sbs_resume(struct acpi_device *device); @@ -117,486 +100,187 @@ static struct acpi_driver acpi_sbs_driver = { struct acpi_battery { struct acpi_sbs *sbs; struct proc_dir_entry *proc_entry; - int vscale; - int ipscale; + unsigned long update_time; + char name[8]; char manufacturer_name[ACPI_SBS_BLOCK_MAX]; char device_name[ACPI_SBS_BLOCK_MAX]; char device_chemistry[ACPI_SBS_BLOCK_MAX]; + u32 alarm_capacity; u16 full_charge_capacity; u16 design_capacity; u16 design_voltage; u16 serial_number; + u16 cycle_count; + u16 temp_now; u16 voltage_now; s16 current_now; + s16 current_avg; u16 capacity_now; + u16 state_of_charge; u16 state; - u16 alarm_capacity; u16 mode; + u16 spec; u8 id; - u8 alive:1; - u8 init_state:1; u8 present:1; }; struct acpi_sbs { struct acpi_device *device; struct acpi_smb_hc *hc; - struct mutex mutex; - struct proc_dir_entry *ac_entry; + struct mutex lock; + struct proc_dir_entry *charger_entry; struct acpi_battery battery[MAX_SBS_BAT]; - int zombie; - struct timer_list update_timer; - int run_cnt; - int update_proc_flg; - u8 batteries_supported; + u8 batteries_supported:4; u8 manager_present:1; u8 charger_present:1; }; -static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type); -static void acpi_sbs_update_time(void *data); - -static int sbs_zombie(struct acpi_sbs *sbs) +static inline int battery_scale(int log) { - return (sbs->zombie); + int scale = 1; + while (log--) + scale *= 10; + return scale; } -static int sbs_mutex_lock(struct acpi_sbs *sbs) +static inline int acpi_battery_vscale(struct acpi_battery *battery) { - if (sbs_zombie(sbs)) { - return -ENODEV; - } - mutex_lock(&sbs->mutex); - return 0; + return battery_scale((battery->spec & 0x0f00) >> 8); } -static void sbs_mutex_unlock(struct acpi_sbs *sbs) +static inline int acpi_battery_ipscale(struct acpi_battery *battery) { - mutex_unlock(&sbs->mutex); + return battery_scale((battery->spec & 0xf000) >> 12); } -/* -------------------------------------------------------------------------- - Smart Battery System Management - -------------------------------------------------------------------------- */ - -static int acpi_check_update_proc(struct acpi_sbs *sbs) +static inline int acpi_battery_mode(struct acpi_battery *battery) { - acpi_status status = AE_OK; - - if (update_time == 0) { - sbs->update_proc_flg = 0; - return 0; - } - if (sbs->update_proc_flg == 0) { - status = acpi_os_execute(OSL_GPE_HANDLER, - acpi_sbs_update_time, sbs); - if (status != AE_OK) { - ACPI_EXCEPTION((AE_INFO, status, - "acpi_os_execute() failed")); - return 1; - } - sbs->update_proc_flg = 1; - } - return 0; + return (battery->mode & 0x8000); } -static int acpi_battery_get_present(struct acpi_battery *battery) +static inline int acpi_battery_scale(struct acpi_battery *battery) { - s16 state; - int result = 0; - int is_present = 0; - - result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, - ACPI_SBSM_SMBUS_ADDR, 0x01, (u8 *)&state); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_read() failed")); - } - if (!result) { - is_present = (state & 0x000f) & (1 << battery->id); - } - battery->present = is_present; - - return result; + return (acpi_battery_mode(battery) ? 10 : 1) * + acpi_battery_ipscale(battery); } -static int acpi_battery_select(struct acpi_battery *battery) -{ - struct acpi_sbs *sbs = battery->sbs; - int result = 0; - s16 state; - int foo; - - if (sbs->manager_present) { - - /* Take special care not to knobble other nibbles of - * state (aka selector_state), since - * it causes charging to halt on SBSELs */ +/* -------------------------------------------------------------------------- + Smart Battery System Management + -------------------------------------------------------------------------- */ - result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, - ACPI_SBSM_SMBUS_ADDR, 0x01, (u8 *)&state); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_read() failed")); - goto end; - } +struct acpi_battery_reader { + u8 command; /* command for battery */ + u8 mode; /* word or block? */ + size_t offset; /* offset inside struct acpi_sbs_battery */ +}; - foo = (state & 0x0fff) | (1 << (battery->id + 12)); - result = acpi_smbus_write(battery->sbs->hc, SMBUS_WRITE_WORD, - ACPI_SBSM_SMBUS_ADDR, 0x01, (u8 *)&foo, 2); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_write() failed")); - goto end; - } - } +static struct acpi_battery_reader info_readers[] = { + {0x01, SMBUS_READ_WORD, offsetof(struct acpi_battery, alarm_capacity)}, + {0x03, SMBUS_READ_WORD, offsetof(struct acpi_battery, mode)}, + {0x10, SMBUS_READ_WORD, offsetof(struct acpi_battery, full_charge_capacity)}, + {0x17, SMBUS_READ_WORD, offsetof(struct acpi_battery, cycle_count)}, + {0x18, SMBUS_READ_WORD, offsetof(struct acpi_battery, design_capacity)}, + {0x19, SMBUS_READ_WORD, offsetof(struct acpi_battery, design_voltage)}, + {0x1a, SMBUS_READ_WORD, offsetof(struct acpi_battery, spec)}, + {0x1c, SMBUS_READ_WORD, offsetof(struct acpi_battery, serial_number)}, + {0x20, SMBUS_READ_BLOCK, offsetof(struct acpi_battery, manufacturer_name)}, + {0x21, SMBUS_READ_BLOCK, offsetof(struct acpi_battery, device_name)}, + {0x22, SMBUS_READ_BLOCK, offsetof(struct acpi_battery, device_chemistry)}, +}; - end: - return result; -} +static struct acpi_battery_reader state_readers[] = { + {0x08, SMBUS_READ_WORD, offsetof(struct acpi_battery, temp_now)}, + {0x09, SMBUS_READ_WORD, offsetof(struct acpi_battery, voltage_now)}, + {0x0a, SMBUS_READ_WORD, offsetof(struct acpi_battery, current_now)}, + {0x0b, SMBUS_READ_WORD, offsetof(struct acpi_battery, current_avg)}, + {0x0f, SMBUS_READ_WORD, offsetof(struct acpi_battery, capacity_now)}, + {0x0e, SMBUS_READ_WORD, offsetof(struct acpi_battery, state_of_charge)}, + {0x16, SMBUS_READ_WORD, offsetof(struct acpi_battery, state)}, +}; -static int acpi_sbsm_get_info(struct acpi_sbs *sbs) +static int acpi_manager_get_info(struct acpi_sbs *sbs) { int result = 0; - s16 battery_system_info; - - result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBSM_SMBUS_ADDR, 0x04, - (u8 *)&battery_system_info); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_read() failed")); - goto end; - } - sbs->manager_present = 1; - - end: + u16 battery_system_info; + result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER, + 0x04, (u8 *) & battery_system_info); + if (!result) + sbs->batteries_supported = battery_system_info & 0x000f; return result; } static int acpi_battery_get_info(struct acpi_battery *battery) { - int result = 0; - s16 battery_mode; - s16 specification_info; - - result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x03, - (u8 *)&battery_mode); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_read() failed")); - goto end; - } - battery->mode = (battery_mode & 0x8000) >> 15; - - result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x10, - (u8 *)&battery->full_charge_capacity); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_read() failed")); - goto end; - } - - result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x18, - (u8 *)&battery->design_capacity); + int i, result = 0; - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_read() failed")); - goto end; - } - - result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x19, - (u8 *)&battery->design_voltage); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_read() failed")); - goto end; + for (i = 0; i < ARRAY_SIZE(info_readers); ++i) { + result = acpi_smbus_read(battery->sbs->hc, info_readers[i].mode, + ACPI_SBS_BATTERY, info_readers[i].command, + (u8 *) battery + info_readers[i].offset); + if (result) + break; } - - result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x1a, - (u8 *)&specification_info); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_read() failed")); - goto end; - } - - switch ((specification_info & 0x0f00) >> 8) { - case 1: - battery->vscale = 10; - break; - case 2: - battery->vscale = 100; - break; - case 3: - battery->vscale = 1000; - break; - default: - battery->vscale = 1; - } - - switch ((specification_info & 0xf000) >> 12) { - case 1: - battery->ipscale = 10; - break; - case 2: - battery->ipscale = 100; - break; - case 3: - battery->ipscale = 1000; - break; - default: - battery->ipscale = 1; - } - - result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x1c, - (u8 *)&battery->serial_number); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_read() failed")); - goto end; - } - - result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_BLOCK, ACPI_SB_SMBUS_ADDR, 0x20, - (u8 *)battery->manufacturer_name); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_str() failed")); - goto end; - } - - result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_BLOCK, ACPI_SB_SMBUS_ADDR, 0x21, - (u8 *)battery->device_name); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_str() failed")); - goto end; - } - - result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_BLOCK, ACPI_SB_SMBUS_ADDR, 0x22, - (u8 *)battery->device_chemistry); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_str() failed")); - goto end; - } - - end: return result; } static int acpi_battery_get_state(struct acpi_battery *battery) { - int result = 0; - - result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x09, - (u8 *)&battery->voltage_now); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_read() failed")); - goto end; - } - - result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x0a, - (u8 *)&battery->current_now); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_read() failed")); - goto end; - } - - result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x0f, - (u8 *)&battery->capacity_now); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_read() failed")); - goto end; - } - - result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x16, - (u8 *)&battery->state); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_read() failed")); - goto end; - } - - end: - return result; -} - -static int acpi_battery_get_alarm(struct acpi_battery *battery) -{ - int result = 0; - - result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x01, - (u8 *)&battery->alarm_capacity); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_read() failed")); - goto end; - } - - end: - - return result; -} - -static int acpi_battery_set_alarm(struct acpi_battery *battery, - unsigned long alarm) -{ - int result = 0; - s16 battery_mode; - int foo; + int i, result = 0; - result = acpi_battery_select(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_select() failed")); - goto end; - } - - /* If necessary, enable the alarm */ - - if (alarm > 0) { - result = - acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x03, - (u8 *)&battery_mode); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_read() failed")); - goto end; - } - - battery_mode &= 0xbfff; - result = - acpi_smbus_write(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x01, - (u8 *)&battery_mode, 2); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_write() failed")); + if (time_before(jiffies, battery->update_time + + msecs_to_jiffies(cache_time))) + return 0; + for (i = 0; i < ARRAY_SIZE(state_readers); ++i) { + result = acpi_smbus_read(battery->sbs->hc, + state_readers[i].mode, + ACPI_SBS_BATTERY, + state_readers[i].command, + (u8 *)battery + + state_readers[i].offset); + if (result) goto end; - } } - - foo = alarm / (battery->mode ? 10 : 1); - result = acpi_smbus_write(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x01, - (u8 *)&foo, 2); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_write() failed")); - goto end; - } - end: - + battery->update_time = jiffies; return result; } -static int acpi_battery_set_mode(struct acpi_battery *battery) +static int acpi_battery_get_alarm(struct acpi_battery *battery) { - int result = 0; - s16 battery_mode; - - if (mode == DEF_CAPACITY_UNIT) { - goto end; - } - - result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, - ACPI_SB_SMBUS_ADDR, 0x03, (u8 *)&battery_mode); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_read() failed")); - goto end; - } - - if (mode == MAH_CAPACITY_UNIT) { - battery_mode &= 0x7fff; - } else { - battery_mode |= 0x8000; - } - result = acpi_smbus_write(battery->sbs->hc, SMBUS_READ_WORD, - ACPI_SB_SMBUS_ADDR, 0x03, (u8 *)&battery_mode, 2); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_write() failed")); - goto end; - } - - result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, - ACPI_SB_SMBUS_ADDR, 0x03, (u8 *)&battery_mode); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_read() failed")); - goto end; - } - - end: - return result; + return acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, + ACPI_SBS_BATTERY, 0x01, + (u8 *) & battery->alarm_capacity); } -static int acpi_battery_init(struct acpi_battery *battery) +static int acpi_battery_set_alarm(struct acpi_battery *battery) { - int result = 0; - - result = acpi_battery_select(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_select() failed")); - goto end; - } - - result = acpi_battery_set_mode(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_set_mode() failed")); - goto end; - } - - result = acpi_battery_get_info(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_info() failed")); - goto end; - } - - result = acpi_battery_get_state(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_state() failed")); - goto end; - } + struct acpi_sbs *sbs = battery->sbs; + u16 value; + return 0; - result = acpi_battery_get_alarm(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_alarm() failed")); - goto end; + if (sbs->manager_present) { + acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER, + 0x01, (u8 *)&value); + value &= 0x0fff; + value |= 1 << (battery->id + 12); + acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, ACPI_SBS_MANAGER, + 0x01, (u8 *)&value, 2); } - - end: - return result; + value = battery->alarm_capacity / (acpi_battery_mode(battery) ? 10 : 1); + return acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, ACPI_SBS_BATTERY, + 0x01, (u8 *)&value, 2); } static int acpi_ac_get_present(struct acpi_sbs *sbs) { - int result = 0; - s16 charger_status; - - result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBC_SMBUS_ADDR, 0x13, - (u8 *)&charger_status); - - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_smbus_read() failed")); - goto end; - } - - sbs->charger_present = (charger_status & 0x8000) >> 15; - - end: + int result; + u16 status; + result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_CHARGER, + 0x13, (u8 *) & status); + if (!result) + sbs->charger_present = (status >> 15) & 0x1; return result; } @@ -607,7 +291,7 @@ static int acpi_ac_get_present(struct acpi_sbs *sbs) /* Generic Routines */ static int -acpi_sbs_generic_add_fs(struct proc_dir_entry **dir, +acpi_sbs_add_fs(struct proc_dir_entry **dir, struct proc_dir_entry *parent_dir, char *dir_name, struct file_operations *info_fops, @@ -669,7 +353,7 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir, } static void -acpi_sbs_generic_remove_fs(struct proc_dir_entry **dir, +acpi_sbs_remove_fs(struct proc_dir_entry **dir, struct proc_dir_entry *parent_dir) { @@ -687,75 +371,47 @@ acpi_sbs_generic_remove_fs(struct proc_dir_entry **dir, static struct proc_dir_entry *acpi_battery_dir = NULL; +static inline char *acpi_battery_units(struct acpi_battery *battery) +{ + return acpi_battery_mode(battery) ? " mWh" : " mAh"; +} + + static int acpi_battery_read_info(struct seq_file *seq, void *offset) { struct acpi_battery *battery = seq->private; struct acpi_sbs *sbs = battery->sbs; - int cscale; int result = 0; - if (sbs_mutex_lock(sbs)) { - return -ENODEV; - } + mutex_lock(&sbs->lock); - result = acpi_check_update_proc(sbs); - if (result) + seq_printf(seq, "present: %s\n", + (battery->present) ? "yes" : "no"); + if (!battery->present) goto end; - if (update_time == 0) { - result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_INFO); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_update_run() failed")); - } - } - - if (battery->present) { - seq_printf(seq, "present: yes\n"); - } else { - seq_printf(seq, "present: no\n"); - goto end; - } - - if (battery->mode) { - cscale = battery->vscale * battery->ipscale; - } else { - cscale = battery->ipscale; - } seq_printf(seq, "design capacity: %i%s\n", - battery->design_capacity * cscale, - battery->mode ? "0 mWh" : " mAh"); - + battery->design_capacity * acpi_battery_scale(battery), + acpi_battery_units(battery)); seq_printf(seq, "last full capacity: %i%s\n", - battery->full_charge_capacity * cscale, - battery->mode ? "0 mWh" : " mAh"); - + battery->full_charge_capacity * acpi_battery_scale(battery), + acpi_battery_units(battery)); seq_printf(seq, "battery technology: rechargeable\n"); - seq_printf(seq, "design voltage: %i mV\n", - battery->design_voltage * battery->vscale); - + battery->design_voltage * acpi_battery_vscale(battery)); seq_printf(seq, "design capacity warning: unknown\n"); seq_printf(seq, "design capacity low: unknown\n"); seq_printf(seq, "capacity granularity 1: unknown\n"); seq_printf(seq, "capacity granularity 2: unknown\n"); - - seq_printf(seq, "model number: %s\n", - battery->device_name); - + seq_printf(seq, "model number: %s\n", battery->device_name); seq_printf(seq, "serial number: %i\n", battery->serial_number); - seq_printf(seq, "battery type: %s\n", battery->device_chemistry); - seq_printf(seq, "OEM info: %s\n", battery->manufacturer_name); - end: - - sbs_mutex_unlock(sbs); - + mutex_unlock(&sbs->lock); return result; } @@ -769,73 +425,29 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset) struct acpi_battery *battery = seq->private; struct acpi_sbs *sbs = battery->sbs; int result = 0; - int cscale; - int foo; - - if (sbs_mutex_lock(sbs)) { - return -ENODEV; - } - - result = acpi_check_update_proc(sbs); - if (result) - goto end; - - if (update_time == 0) { - result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_STATE); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_update_run() failed")); - } - } - if (battery->present) { - seq_printf(seq, "present: yes\n"); - } else { - seq_printf(seq, "present: no\n"); + mutex_lock(&sbs->lock); + seq_printf(seq, "present: %s\n", + (battery->present) ? "yes" : "no"); + if (!battery->present) goto end; - } - - if (battery->mode) { - cscale = battery->vscale * battery->ipscale; - } else { - cscale = battery->ipscale; - } - - if (battery->state & 0x0010) { - seq_printf(seq, "capacity state: critical\n"); - } else { - seq_printf(seq, "capacity state: ok\n"); - } - - foo = (s16) battery->current_now * battery->ipscale; - if (battery->mode) { - foo = foo * battery->design_voltage / 1000; - } - if (battery->current_now < 0) { - seq_printf(seq, "charging state: discharging\n"); - seq_printf(seq, "present rate: %d %s\n", - -foo, battery->mode ? "mW" : "mA"); - } else if (battery->current_now > 0) { - seq_printf(seq, "charging state: charging\n"); - seq_printf(seq, "present rate: %d %s\n", - foo, battery->mode ? "mW" : "mA"); - } else { - seq_printf(seq, "charging state: charged\n"); - seq_printf(seq, "present rate: 0 %s\n", - battery->mode ? "mW" : "mA"); - } + acpi_battery_get_state(battery); + seq_printf(seq, "capacity state: %s\n", + (battery->state & 0x0010) ? "critical" : "ok"); + seq_printf(seq, "charging state: %s\n", + (battery->current_now < 0) ? "discharging" : + ((battery->current_now > 0) ? "charging" : "charged")); + seq_printf(seq, "present rate: %d mA\n", + abs(battery->current_now) * acpi_battery_ipscale(battery)); seq_printf(seq, "remaining capacity: %i%s\n", - battery->capacity_now * cscale, - battery->mode ? "0 mWh" : " mAh"); - + battery->capacity_now * acpi_battery_scale(battery), + acpi_battery_units(battery)); seq_printf(seq, "present voltage: %i mV\n", - battery->voltage_now * battery->vscale); + battery->voltage_now * acpi_battery_vscale(battery)); end: - - sbs_mutex_unlock(sbs); - + mutex_unlock(&sbs->lock); return result; } @@ -849,48 +461,25 @@ static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) struct acpi_battery *battery = seq->private; struct acpi_sbs *sbs = battery->sbs; int result = 0; - int cscale; - - if (sbs_mutex_lock(sbs)) { - return -ENODEV; - } - result = acpi_check_update_proc(sbs); - if (result) - goto end; - - if (update_time == 0) { - result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_ALARM); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_update_run() failed")); - } - } + mutex_lock(&sbs->lock); if (!battery->present) { seq_printf(seq, "present: no\n"); goto end; } - if (battery->mode) { - cscale = battery->vscale * battery->ipscale; - } else { - cscale = battery->ipscale; - } - + acpi_battery_get_alarm(battery); seq_printf(seq, "alarm: "); - if (battery->alarm_capacity) { + if (battery->alarm_capacity) seq_printf(seq, "%i%s\n", - battery->alarm_capacity * cscale, - battery->mode ? "0 mWh" : " mAh"); - } else { + battery->alarm_capacity * + acpi_battery_scale(battery), + acpi_battery_units(battery)); + else seq_printf(seq, "disabled\n"); - } - end: - - sbs_mutex_unlock(sbs); - + mutex_unlock(&sbs->lock); return result; } @@ -902,59 +491,28 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer, struct acpi_battery *battery = seq->private; struct acpi_sbs *sbs = battery->sbs; char alarm_string[12] = { '\0' }; - int result, old_alarm, new_alarm; - - if (sbs_mutex_lock(sbs)) { - return -ENODEV; - } - - result = acpi_check_update_proc(sbs); - if (result) - goto end; - + int result = 0; + mutex_lock(&sbs->lock); if (!battery->present) { result = -ENODEV; goto end; } - if (count > sizeof(alarm_string) - 1) { result = -EINVAL; goto end; } - if (copy_from_user(alarm_string, buffer, count)) { result = -EFAULT; goto end; } - alarm_string[count] = 0; - - old_alarm = battery->alarm_capacity; - new_alarm = simple_strtoul(alarm_string, NULL, 0); - - result = acpi_battery_set_alarm(battery, new_alarm); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_set_alarm() failed")); - acpi_battery_set_alarm(battery, old_alarm); - goto end; - } - result = acpi_battery_get_alarm(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_alarm() failed")); - acpi_battery_set_alarm(battery, old_alarm); - goto end; - } - + battery->alarm_capacity = simple_strtoul(alarm_string, NULL, 0); + acpi_battery_set_alarm(battery); end: - sbs_mutex_unlock(sbs); - - if (result) { + mutex_unlock(&sbs->lock); + if (result) return result; - } else { - return count; - } + return count; } static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file) @@ -993,26 +551,15 @@ static struct proc_dir_entry *acpi_ac_dir = NULL; static int acpi_ac_read_state(struct seq_file *seq, void *offset) { - struct acpi_sbs *sbs = seq->private; - int result; - if (sbs_mutex_lock(sbs)) { - return -ENODEV; - } + struct acpi_sbs *sbs = seq->private; - if (update_time == 0) { - result = acpi_sbs_update_run(sbs, -1, DATA_TYPE_AC_STATE); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_update_run() failed")); - } - } + mutex_lock(&sbs->lock); seq_printf(seq, "state: %s\n", sbs->charger_present ? "on-line" : "off-line"); - sbs_mutex_unlock(sbs); - + mutex_unlock(&sbs->lock); return 0; } @@ -1035,67 +582,54 @@ static struct file_operations acpi_ac_state_fops = { /* Smart Battery */ -static int acpi_battery_add(struct acpi_sbs *sbs, int id) +static int acpi_battery_read(struct acpi_battery *battery) { - int is_present; - int result; - char dir_name[32]; - struct acpi_battery *battery; + int result = 0, saved_present = battery->present; + u16 state; - battery = &sbs->battery[id]; + if (battery->sbs->manager_present) { + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, + ACPI_SBS_MANAGER, 0x01, (u8 *)&state); + if (!result) + battery->present = state & (1 << battery->id); + state &= 0x0fff; + state |= 1 << (battery->id + 12); + acpi_smbus_write(battery->sbs->hc, SMBUS_WRITE_WORD, + ACPI_SBS_MANAGER, 0x01, (u8 *)&state, 2); + } else if (battery->id == 0) + battery->present = 1; + if (result || !battery->present) + return result; - battery->alive = 0; + if (saved_present != battery->present) { + battery->update_time = 0; + result = acpi_battery_get_info(battery); + if (result) + return result; + } + result = acpi_battery_get_state(battery); + return result; +} - battery->init_state = 0; +static int acpi_battery_add(struct acpi_sbs *sbs, int id) +{ + int result; + struct acpi_battery *battery = &sbs->battery[id]; battery->id = id; battery->sbs = sbs; + battery->update_time = 0; + result = acpi_battery_read(battery); + if (result) + return result; - result = acpi_battery_select(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_select() failed")); - goto end; - } - - result = acpi_battery_get_present(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_present() failed")); - goto end; - } - - is_present = battery->present; - - if (is_present) { - result = acpi_battery_init(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_init() failed")); - goto end; - } - battery->init_state = 1; - } - - sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id); - - result = acpi_sbs_generic_add_fs(&battery->proc_entry, - acpi_battery_dir, - dir_name, - &acpi_battery_info_fops, - &acpi_battery_state_fops, - &acpi_battery_alarm_fops, battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_generic_add_fs() failed")); - goto end; - } - battery->alive = 1; - + sprintf(battery->name, ACPI_BATTERY_DIR_NAME, id); + acpi_sbs_add_fs(&battery->proc_entry, acpi_battery_dir, + battery->name, &acpi_battery_info_fops, + &acpi_battery_state_fops, &acpi_battery_alarm_fops, + battery); printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n", - ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), dir_name, - sbs->battery->present ? "present" : "absent"); - - end: + ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), + battery->name, sbs->battery->present ? "present" : "absent"); return result; } @@ -1103,354 +637,105 @@ static void acpi_battery_remove(struct acpi_sbs *sbs, int id) { if (sbs->battery[id].proc_entry) { - acpi_sbs_generic_remove_fs(&(sbs->battery[id].proc_entry), - acpi_battery_dir); + acpi_sbs_remove_fs(&(sbs->battery[id].proc_entry), + acpi_battery_dir); } } -static int acpi_ac_add(struct acpi_sbs *sbs) +static int acpi_charger_add(struct acpi_sbs *sbs) { int result; result = acpi_ac_get_present(sbs); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_ac_get_present() failed")); + if (result) goto end; - } - - result = acpi_sbs_generic_add_fs(&sbs->ac_entry, - acpi_ac_dir, - ACPI_AC_DIR_NAME, - NULL, &acpi_ac_state_fops, NULL, sbs); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_generic_add_fs() failed")); + result = acpi_sbs_add_fs(&sbs->charger_entry, acpi_ac_dir, + ACPI_AC_DIR_NAME, NULL, + &acpi_ac_state_fops, NULL, sbs); + if (result) goto end; - } - printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n", ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), ACPI_AC_DIR_NAME, sbs->charger_present ? "on-line" : "off-line"); - end: - return result; } -static void acpi_ac_remove(struct acpi_sbs *sbs) +static void acpi_charger_remove(struct acpi_sbs *sbs) { - if (sbs->ac_entry) { - acpi_sbs_generic_remove_fs(&sbs->ac_entry, acpi_ac_dir); - } -} - -static void acpi_sbs_update_time_run(unsigned long data) -{ - acpi_os_execute(OSL_GPE_HANDLER, acpi_sbs_update_time, (void *)data); + if (sbs->charger_entry) + acpi_sbs_remove_fs(&sbs->charger_entry, acpi_ac_dir); } -static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type) +void acpi_sbs_callback(void *context) { - struct acpi_battery *battery; - int result = 0, cnt; - int old_ac_present = -1; - int old_present = -1; - int new_ac_present = -1; - int new_present = -1; - int id_min = 0, id_max = MAX_SBS_BAT - 1; - char dir_name[32]; - int do_battery_init = 0, do_ac_init = 0; - int old_remaining_capacity = 0; - int update_battery = 1; - int up_tm = update_time; - - if (sbs_zombie(sbs)) { - goto end; - } - - if (id >= 0) { - id_min = id_max = id; - } - - if (data_type == DATA_TYPE_COMMON && up_tm > 0) { - cnt = up_tm / (up_tm > UPDATE_DELAY ? UPDATE_DELAY : up_tm); - if (sbs->run_cnt % cnt != 0) { - update_battery = 0; - } - } - - sbs->run_cnt++; - - if (!update_battery) { - goto end; - } - - old_ac_present = sbs->charger_present; - - result = acpi_ac_get_present(sbs); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_ac_get_present() failed")); - } - - new_ac_present = sbs->charger_present; - - do_ac_init = (old_ac_present != new_ac_present); - if (sbs->run_cnt == 1 && data_type == DATA_TYPE_COMMON) { - do_ac_init = 1; - } - - if (do_ac_init) { - result = acpi_bus_generate_proc_event4(ACPI_AC_CLASS, - ACPI_AC_DIR_NAME, - ACPI_SBS_AC_NOTIFY_STATUS, - new_ac_present); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_bus_generate_event4() failed")); - } - acpi_bus_generate_netlink_event(ACPI_AC_CLASS, ACPI_AC_DIR_NAME, - ACPI_SBS_AC_NOTIFY_STATUS, - new_ac_present); - } - - if (data_type == DATA_TYPE_COMMON) { - if (!do_ac_init && !update_battery) { - goto end; - } - } - - if (data_type == DATA_TYPE_AC_STATE && !do_ac_init) { - goto end; + int id; + struct acpi_sbs *sbs = context; + struct acpi_battery *bat; + u8 saved_charger_state = sbs->charger_present; + u8 saved_battery_state; + acpi_ac_get_present(sbs); + if (sbs->charger_present != saved_charger_state) { + acpi_bus_generate_proc_event4(ACPI_AC_CLASS, ACPI_AC_DIR_NAME, + ACPI_SBS_NOTIFY_STATUS, + sbs->charger_present); } - - for (id = id_min; id <= id_max; id++) { - battery = &sbs->battery[id]; - if (battery->alive == 0) { - continue; - } - - old_remaining_capacity = battery->capacity_now; - - old_present = battery->present; - - result = acpi_battery_select(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_select() failed")); - } - - result = acpi_battery_get_present(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_present() failed")); - } - - new_present = battery->present; - - do_battery_init = ((old_present != new_present) - && new_present); - if (!new_present) - goto event; - if (do_ac_init || do_battery_init) { - result = acpi_battery_init(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_init() " - "failed")); - } - } - if (sbs_zombie(sbs)) { - goto end; - } - - if ((data_type == DATA_TYPE_COMMON - || data_type == DATA_TYPE_INFO) - && new_present) { - result = acpi_battery_get_info(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_info() failed")); - } - } - if (data_type == DATA_TYPE_INFO) { - continue; - } - if (sbs_zombie(sbs)) { - goto end; - } - - if ((data_type == DATA_TYPE_COMMON - || data_type == DATA_TYPE_STATE) - && new_present) { - result = acpi_battery_get_state(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_state() failed")); - } - } - if (data_type == DATA_TYPE_STATE) { - goto event; - } - if (sbs_zombie(sbs)) { - goto end; - } - - if ((data_type == DATA_TYPE_COMMON - || data_type == DATA_TYPE_ALARM) - && new_present) { - result = acpi_battery_get_alarm(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_alarm() " - "failed")); - } - } - if (data_type == DATA_TYPE_ALARM) { - continue; - } - if (sbs_zombie(sbs)) { - goto end; - } - - event: - - if (old_present != new_present || do_ac_init || - old_remaining_capacity != - battery->capacity_now) { - sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id); - result = acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS, - dir_name, - ACPI_SBS_BATTERY_NOTIFY_STATUS, - new_present); - acpi_bus_generate_netlink_event(ACPI_BATTERY_CLASS, dir_name, - ACPI_SBS_BATTERY_NOTIFY_STATUS, - new_present); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_bus_generate_proc_event4() " - "failed")); - } + if (sbs->manager_present) { + for (id = 0; id < MAX_SBS_BAT; ++id) { + if (!(sbs->batteries_supported & (1 << id))) + continue; + bat = &sbs->battery[id]; + saved_battery_state = bat->present; + acpi_battery_read(bat); + if (saved_battery_state == bat->present) + continue; + acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS, + bat->name, + ACPI_SBS_NOTIFY_STATUS, + bat->present); } } - - end: - - return result; } -static void acpi_sbs_update_time(void *data) -{ - struct acpi_sbs *sbs = data; - unsigned long delay = -1; - int result; - unsigned int up_tm = update_time; - - if (sbs_mutex_lock(sbs)) - return; - - result = acpi_sbs_update_run(sbs, -1, DATA_TYPE_COMMON); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_update_run() failed")); - } - - if (sbs_zombie(sbs)) { - goto end; - } - - if (!up_tm) { - if (timer_pending(&sbs->update_timer)) - del_timer(&sbs->update_timer); - } else { - delay = (up_tm > UPDATE_DELAY ? UPDATE_DELAY : up_tm); - delay = jiffies + HZ * delay; - if (timer_pending(&sbs->update_timer)) { - mod_timer(&sbs->update_timer, delay); - } else { - sbs->update_timer.data = (unsigned long)data; - sbs->update_timer.function = acpi_sbs_update_time_run; - sbs->update_timer.expires = delay; - add_timer(&sbs->update_timer); - } - } - - end: - - sbs_mutex_unlock(sbs); -} +static int acpi_sbs_remove(struct acpi_device *device, int type); static int acpi_sbs_add(struct acpi_device *device) { - struct acpi_sbs *sbs = NULL; - int result = 0, remove_result = 0; + struct acpi_sbs *sbs; + int result = 0; int id; sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL); if (!sbs) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, "kzalloc() failed")); result = -ENOMEM; goto end; } - mutex_init(&sbs->mutex); - - sbs_mutex_lock(sbs); + mutex_init(&sbs->lock); - sbs->device = device; sbs->hc = acpi_driver_data(device->parent); - + sbs->device = device; strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_SBS_CLASS); acpi_driver_data(device) = sbs; - result = acpi_ac_add(sbs); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_ac_add() failed")); - goto end; - } - - acpi_sbsm_get_info(sbs); - - if (!sbs->manager_present) { - result = acpi_battery_add(sbs, 0); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_add() failed")); - goto end; - } - } else { - for (id = 0; id < MAX_SBS_BAT; id++) { - if ((sbs->batteries_supported & (1 << id))) { - result = acpi_battery_add(sbs, id); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_add() failed")); - goto end; - } - } - } - } - - init_timer(&sbs->update_timer); - result = acpi_check_update_proc(sbs); + result = acpi_charger_add(sbs); if (result) goto end; + result = acpi_manager_get_info(sbs); + if (!result) { + sbs->manager_present = 1; + for (id = 0; id < MAX_SBS_BAT; ++id) + if ((sbs->batteries_supported & (1 << id))) + acpi_battery_add(sbs, id); + } else + acpi_battery_add(sbs, 0); + acpi_smbus_register_callback(sbs->hc, acpi_sbs_callback, sbs); end: - - sbs_mutex_unlock(sbs); - - if (result) { - remove_result = acpi_sbs_remove(device, 0); - if (remove_result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_remove() failed")); - } - } - + if (result) + acpi_sbs_remove(device, 0); return result; } @@ -1459,34 +744,19 @@ static int acpi_sbs_remove(struct acpi_device *device, int type) struct acpi_sbs *sbs; int id; - if (!device) { + if (!device) return -EINVAL; - } - sbs = acpi_driver_data(device); - if (!sbs) { + if (!sbs) return -EINVAL; - } - - sbs_mutex_lock(sbs); - - sbs->zombie = 1; - del_timer_sync(&sbs->update_timer); - acpi_os_wait_events_complete(NULL); - del_timer_sync(&sbs->update_timer); - - for (id = 0; id < MAX_SBS_BAT; id++) { + mutex_lock(&sbs->lock); + acpi_smbus_unregister_callback(sbs->hc); + for (id = 0; id < MAX_SBS_BAT; ++id) acpi_battery_remove(sbs, id); - } - - acpi_ac_remove(sbs); - - sbs_mutex_unlock(sbs); - - mutex_destroy(&sbs->mutex); - + acpi_charger_remove(sbs); + mutex_unlock(&sbs->lock); + mutex_destroy(&sbs->lock); kfree(sbs); - return 0; } @@ -1505,14 +775,10 @@ static void acpi_sbs_rmdirs(void) static int acpi_sbs_resume(struct acpi_device *device) { struct acpi_sbs *sbs; - if (!device) return -EINVAL; - sbs = device->driver_data; - - sbs->run_cnt = 0; - + acpi_sbs_callback(sbs); return 0; } @@ -1523,14 +789,6 @@ static int __init acpi_sbs_init(void) if (acpi_disabled) return -ENODEV; - if (mode != DEF_CAPACITY_UNIT - && mode != MAH_CAPACITY_UNIT - && mode != MWH_CAPACITY_UNIT) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "invalid mode = %d", mode)); - return -EINVAL; - } - acpi_ac_dir = acpi_lock_ac_dir(); if (!acpi_ac_dir) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, -- cgit v1.1 From 94f6c0860139da9219255b8ff45ad42117dda859 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Wed, 26 Sep 2007 19:43:48 +0400 Subject: ACPI: SBS: Add support for power_supply class (and sysfs) Add support for power_supply class and sysfs interface of it. Refer to Documentation/power_supply_class.txt for interface description. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 9 +- drivers/acpi/sbs.c | 314 ++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 237 insertions(+), 86 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 8560bc3..ba6a61f 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -349,12 +349,11 @@ config ACPI_HOTPLUG_MEMORY $>modprobe acpi_memhotplug config ACPI_SBS - tristate "Smart Battery System (EXPERIMENTAL)" + tristate "Smart Battery System" depends on X86 - depends on EXPERIMENTAL + depends on POWER_SUPPLY help - This driver adds support for the Smart Battery System. - A "Smart Battery" is quite old and quite rare compared - to today's ACPI "Control Method" battery. + This driver adds support for the Smart Battery System, another + type of access to battery information, found on some laptops. endif # ACPI diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 3351dea..c4f9641 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -28,17 +28,20 @@ #include #include #include + #include #include #include + #include #include #include #include +#include + #include "sbshc.h" -#define ACPI_SBS_COMPONENT 0x00080000 #define ACPI_SBS_CLASS "sbs" #define ACPI_AC_CLASS "ac_adapter" #define ACPI_BATTERY_CLASS "battery" @@ -58,8 +61,6 @@ enum acpi_sbs_device_addr { #define ACPI_SBS_NOTIFY_STATUS 0x80 #define ACPI_SBS_NOTIFY_INFO 0x81 -ACPI_MODULE_NAME("sbs"); - MODULE_AUTHOR("Alexey Starikovskiy "); MODULE_DESCRIPTION("Smart Battery System ACPI interface driver"); MODULE_LICENSE("GPL"); @@ -76,28 +77,14 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); #define MAX_SBS_BAT 4 #define ACPI_SBS_BLOCK_MAX 32 -static int acpi_sbs_add(struct acpi_device *device); -static int acpi_sbs_remove(struct acpi_device *device, int type); -static int acpi_sbs_resume(struct acpi_device *device); - static const struct acpi_device_id sbs_device_ids[] = { {"ACPI0002", 0}, {"", 0}, }; MODULE_DEVICE_TABLE(acpi, sbs_device_ids); -static struct acpi_driver acpi_sbs_driver = { - .name = "sbs", - .class = ACPI_SBS_CLASS, - .ids = sbs_device_ids, - .ops = { - .add = acpi_sbs_add, - .remove = acpi_sbs_remove, - .resume = acpi_sbs_resume, - }, -}; - struct acpi_battery { + struct power_supply bat; struct acpi_sbs *sbs; struct proc_dir_entry *proc_entry; unsigned long update_time; @@ -105,7 +92,7 @@ struct acpi_battery { char manufacturer_name[ACPI_SBS_BLOCK_MAX]; char device_name[ACPI_SBS_BLOCK_MAX]; char device_chemistry[ACPI_SBS_BLOCK_MAX]; - u32 alarm_capacity; + u16 alarm_capacity; u16 full_charge_capacity; u16 design_capacity; u16 design_voltage; @@ -124,7 +111,10 @@ struct acpi_battery { u8 present:1; }; +#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat); + struct acpi_sbs { + struct power_supply charger; struct acpi_device *device; struct acpi_smb_hc *hc; struct mutex lock; @@ -135,6 +125,8 @@ struct acpi_sbs { u8 charger_present:1; }; +#define to_acpi_sbs(x) container_of(x, struct acpi_sbs, charger) + static inline int battery_scale(int log) { int scale = 1; @@ -164,6 +156,144 @@ static inline int acpi_battery_scale(struct acpi_battery *battery) acpi_battery_ipscale(battery); } +static int sbs_get_ac_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct acpi_sbs *sbs = to_acpi_sbs(psy); + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = sbs->charger_present; + break; + default: + return -EINVAL; + } + return 0; +} + +static int acpi_battery_technology(struct acpi_battery *battery) +{ + if (!strcasecmp("NiCd", battery->device_chemistry)) + return POWER_SUPPLY_TECHNOLOGY_NiCd; + if (!strcasecmp("NiMH", battery->device_chemistry)) + return POWER_SUPPLY_TECHNOLOGY_NiMH; + if (!strcasecmp("LION", battery->device_chemistry)) + return POWER_SUPPLY_TECHNOLOGY_LION; + if (!strcasecmp("LiP", battery->device_chemistry)) + return POWER_SUPPLY_TECHNOLOGY_LIPO; + return POWER_SUPPLY_TECHNOLOGY_UNKNOWN; +} + +static int acpi_sbs_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct acpi_battery *battery = to_acpi_battery(psy); + + if ((!battery->present) && psp != POWER_SUPPLY_PROP_PRESENT) + return -ENODEV; + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + if (battery->current_now < 0) + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + else if (battery->current_now > 0) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + else + val->intval = POWER_SUPPLY_STATUS_FULL; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = battery->present; + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = acpi_battery_technology(battery); + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = battery->design_voltage * + acpi_battery_vscale(battery) * 1000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = battery->voltage_now * + acpi_battery_vscale(battery) * 1000; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = abs(battery->current_now) * + acpi_battery_ipscale(battery) * 1000; + break; + case POWER_SUPPLY_PROP_CURRENT_AVG: + val->intval = abs(battery->current_avg) * + acpi_battery_ipscale(battery) * 1000; + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = battery->state_of_charge; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: + val->intval = battery->design_capacity * + acpi_battery_scale(battery) * 1000; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + case POWER_SUPPLY_PROP_ENERGY_FULL: + val->intval = battery->full_charge_capacity * + acpi_battery_scale(battery) * 1000; + break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + case POWER_SUPPLY_PROP_ENERGY_NOW: + val->intval = battery->capacity_now * + acpi_battery_scale(battery) * 1000; + break; + case POWER_SUPPLY_PROP_TEMP: + val->intval = battery->temp_now - 2730; // dK -> dC + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = battery->device_name; + break; + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = battery->manufacturer_name; + break; + default: + return -EINVAL; + } + return 0; +} + +static enum power_supply_property sbs_ac_props[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + +static enum power_supply_property sbs_charge_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CURRENT_AVG, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +static enum power_supply_property sbs_energy_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CURRENT_AVG, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, + POWER_SUPPLY_PROP_ENERGY_FULL, + POWER_SUPPLY_PROP_ENERGY_NOW, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + /* -------------------------------------------------------------------------- Smart Battery System Management -------------------------------------------------------------------------- */ @@ -204,7 +334,7 @@ static int acpi_manager_get_info(struct acpi_sbs *sbs) u16 battery_system_info; result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER, - 0x04, (u8 *) & battery_system_info); + 0x04, (u8 *)&battery_system_info); if (!result) sbs->batteries_supported = battery_system_info & 0x000f; return result; @@ -215,9 +345,12 @@ static int acpi_battery_get_info(struct acpi_battery *battery) int i, result = 0; for (i = 0; i < ARRAY_SIZE(info_readers); ++i) { - result = acpi_smbus_read(battery->sbs->hc, info_readers[i].mode, - ACPI_SBS_BATTERY, info_readers[i].command, - (u8 *) battery + info_readers[i].offset); + result = acpi_smbus_read(battery->sbs->hc, + info_readers[i].mode, + ACPI_SBS_BATTERY, + info_readers[i].command, + (u8 *) battery + + info_readers[i].offset); if (result) break; } @@ -228,7 +361,8 @@ static int acpi_battery_get_state(struct acpi_battery *battery) { int i, result = 0; - if (time_before(jiffies, battery->update_time + + if (battery->update_time && + time_before(jiffies, battery->update_time + msecs_to_jiffies(cache_time))) return 0; for (i = 0; i < ARRAY_SIZE(state_readers); ++i) { @@ -250,26 +384,36 @@ static int acpi_battery_get_alarm(struct acpi_battery *battery) { return acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SBS_BATTERY, 0x01, - (u8 *) & battery->alarm_capacity); + (u8 *)&battery->alarm_capacity); } static int acpi_battery_set_alarm(struct acpi_battery *battery) { struct acpi_sbs *sbs = battery->sbs; - u16 value; - return 0; + u16 value, sel = 1 << (battery->id + 12); + + int ret; + if (sbs->manager_present) { - acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER, + ret = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER, 0x01, (u8 *)&value); - value &= 0x0fff; - value |= 1 << (battery->id + 12); - acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, ACPI_SBS_MANAGER, - 0x01, (u8 *)&value, 2); + if (ret) + goto end; + if ((value & 0xf000) != sel) { + value &= 0x0fff; + value |= sel; + ret = acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, + ACPI_SBS_MANAGER, + 0x01, (u8 *)&value, 2); + if (ret) + goto end; + } } - value = battery->alarm_capacity / (acpi_battery_mode(battery) ? 10 : 1); - return acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, ACPI_SBS_BATTERY, - 0x01, (u8 *)&value, 2); + ret = acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, ACPI_SBS_BATTERY, + 0x01, (u8 *)&battery->alarm_capacity, 2); + end: + return ret; } static int acpi_ac_get_present(struct acpi_sbs *sbs) @@ -289,22 +433,19 @@ static int acpi_ac_get_present(struct acpi_sbs *sbs) -------------------------------------------------------------------------- */ /* Generic Routines */ - static int acpi_sbs_add_fs(struct proc_dir_entry **dir, - struct proc_dir_entry *parent_dir, - char *dir_name, - struct file_operations *info_fops, - struct file_operations *state_fops, - struct file_operations *alarm_fops, void *data) + struct proc_dir_entry *parent_dir, + char *dir_name, + struct file_operations *info_fops, + struct file_operations *state_fops, + struct file_operations *alarm_fops, void *data) { struct proc_dir_entry *entry = NULL; if (!*dir) { *dir = proc_mkdir(dir_name, parent_dir); if (!*dir) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "proc_mkdir() failed")); return -ENODEV; } (*dir)->owner = THIS_MODULE; @@ -313,10 +454,7 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir, /* 'info' [R] */ if (info_fops) { entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir); - if (!entry) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "create_proc_entry() failed")); - } else { + if (entry) { entry->proc_fops = info_fops; entry->data = data; entry->owner = THIS_MODULE; @@ -326,10 +464,7 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir, /* 'state' [R] */ if (state_fops) { entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir); - if (!entry) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "create_proc_entry() failed")); - } else { + if (entry) { entry->proc_fops = state_fops; entry->data = data; entry->owner = THIS_MODULE; @@ -339,16 +474,12 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir, /* 'alarm' [R/W] */ if (alarm_fops) { entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir); - if (!entry) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "create_proc_entry() failed")); - } else { + if (entry) { entry->proc_fops = alarm_fops; entry->data = data; entry->owner = THIS_MODULE; } } - return 0; } @@ -356,7 +487,6 @@ static void acpi_sbs_remove_fs(struct proc_dir_entry **dir, struct proc_dir_entry *parent_dir) { - if (*dir) { remove_proc_entry(ACPI_SBS_FILE_INFO, *dir); remove_proc_entry(ACPI_SBS_FILE_STATE, *dir); @@ -364,11 +494,9 @@ acpi_sbs_remove_fs(struct proc_dir_entry **dir, remove_proc_entry((*dir)->name, parent_dir); *dir = NULL; } - } /* Smart Battery Interface */ - static struct proc_dir_entry *acpi_battery_dir = NULL; static inline char *acpi_battery_units(struct acpi_battery *battery) @@ -506,7 +634,8 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer, goto end; } alarm_string[count] = 0; - battery->alarm_capacity = simple_strtoul(alarm_string, NULL, 0); + battery->alarm_capacity = simple_strtoul(alarm_string, NULL, 0) / + acpi_battery_scale(battery); acpi_battery_set_alarm(battery); end: mutex_unlock(&sbs->lock); @@ -579,9 +708,6 @@ static struct file_operations acpi_ac_state_fops = { /* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */ - -/* Smart Battery */ - static int acpi_battery_read(struct acpi_battery *battery) { int result = 0, saved_present = battery->present; @@ -611,13 +737,14 @@ static int acpi_battery_read(struct acpi_battery *battery) return result; } +/* Smart Battery */ static int acpi_battery_add(struct acpi_sbs *sbs, int id) { - int result; struct acpi_battery *battery = &sbs->battery[id]; + int result; + battery->id = id; battery->sbs = sbs; - battery->update_time = 0; result = acpi_battery_read(battery); if (result) return result; @@ -627,6 +754,19 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) battery->name, &acpi_battery_info_fops, &acpi_battery_state_fops, &acpi_battery_alarm_fops, battery); + battery->bat.name = battery->name; + battery->bat.type = POWER_SUPPLY_TYPE_BATTERY; + if (!acpi_battery_mode(battery)) { + battery->bat.properties = sbs_charge_battery_props; + battery->bat.num_properties = + ARRAY_SIZE(sbs_charge_battery_props); + } else { + battery->bat.properties = sbs_energy_battery_props; + battery->bat.num_properties = + ARRAY_SIZE(sbs_energy_battery_props); + } + battery->bat.get_property = acpi_sbs_battery_get_property; + result = power_supply_register(&sbs->device->dev, &battery->bat); printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n", ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), battery->name, sbs->battery->present ? "present" : "absent"); @@ -635,7 +775,8 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) static void acpi_battery_remove(struct acpi_sbs *sbs, int id) { - + if (sbs->battery[id].bat.dev) + power_supply_unregister(&sbs->battery[id].bat); if (sbs->battery[id].proc_entry) { acpi_sbs_remove_fs(&(sbs->battery[id].proc_entry), acpi_battery_dir); @@ -654,6 +795,12 @@ static int acpi_charger_add(struct acpi_sbs *sbs) &acpi_ac_state_fops, NULL, sbs); if (result) goto end; + sbs->charger.name = "sbs-charger"; + sbs->charger.type = POWER_SUPPLY_TYPE_MAINS; + sbs->charger.properties = sbs_ac_props; + sbs->charger.num_properties = ARRAY_SIZE(sbs_ac_props); + sbs->charger.get_property = sbs_get_ac_property; + power_supply_register(&sbs->device->dev, &sbs->charger); printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n", ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), ACPI_AC_DIR_NAME, sbs->charger_present ? "on-line" : "off-line"); @@ -663,7 +810,8 @@ static int acpi_charger_add(struct acpi_sbs *sbs) static void acpi_charger_remove(struct acpi_sbs *sbs) { - + if (sbs->charger.dev) + power_supply_unregister(&sbs->charger); if (sbs->charger_entry) acpi_sbs_remove_fs(&sbs->charger_entry, acpi_ac_dir); } @@ -677,9 +825,12 @@ void acpi_sbs_callback(void *context) u8 saved_battery_state; acpi_ac_get_present(sbs); if (sbs->charger_present != saved_charger_state) { +#ifdef CONFIG_ACPI_PROC_EVENT acpi_bus_generate_proc_event4(ACPI_AC_CLASS, ACPI_AC_DIR_NAME, ACPI_SBS_NOTIFY_STATUS, sbs->charger_present); +#endif + kobject_uevent(&sbs->charger.dev->kobj, KOBJ_CHANGE); } if (sbs->manager_present) { for (id = 0; id < MAX_SBS_BAT; ++id) { @@ -690,10 +841,13 @@ void acpi_sbs_callback(void *context) acpi_battery_read(bat); if (saved_battery_state == bat->present) continue; +#ifdef CONFIG_ACPI_PROC_EVENT acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS, bat->name, ACPI_SBS_NOTIFY_STATUS, bat->present); +#endif + kobject_uevent(&bat->bat.dev->kobj, KOBJ_CHANGE); } } } @@ -782,45 +936,43 @@ static int acpi_sbs_resume(struct acpi_device *device) return 0; } +static struct acpi_driver acpi_sbs_driver = { + .name = "sbs", + .class = ACPI_SBS_CLASS, + .ids = sbs_device_ids, + .ops = { + .add = acpi_sbs_add, + .remove = acpi_sbs_remove, + .resume = acpi_sbs_resume, + }, +}; + static int __init acpi_sbs_init(void) { int result = 0; if (acpi_disabled) return -ENODEV; - acpi_ac_dir = acpi_lock_ac_dir(); - if (!acpi_ac_dir) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_lock_ac_dir() failed")); + if (!acpi_ac_dir) return -ENODEV; - } - acpi_battery_dir = acpi_lock_battery_dir(); if (!acpi_battery_dir) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_lock_battery_dir() failed")); acpi_sbs_rmdirs(); return -ENODEV; } - result = acpi_bus_register_driver(&acpi_sbs_driver); if (result < 0) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_bus_register_driver() failed")); acpi_sbs_rmdirs(); return -ENODEV; } - return 0; } static void __exit acpi_sbs_exit(void) { acpi_bus_unregister_driver(&acpi_sbs_driver); - acpi_sbs_rmdirs(); - return; } -- cgit v1.1 From 66e4b72bfa7347fd1017b9b82dce77a410f2e4a1 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Wed, 26 Sep 2007 19:43:54 +0400 Subject: ACPI: SBS: Add ACPI_PROCFS around procfs handling code. Make procfs support optional under ACPI_PROCFS Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/sbs.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index c4f9641..aae65e8 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -29,9 +29,11 @@ #include #include +#ifdef CONFIG_ACPI_PROCFS #include #include #include +#endif #include #include @@ -86,7 +88,9 @@ MODULE_DEVICE_TABLE(acpi, sbs_device_ids); struct acpi_battery { struct power_supply bat; struct acpi_sbs *sbs; +#ifdef CONFIG_ACPI_PROCFS struct proc_dir_entry *proc_entry; +#endif unsigned long update_time; char name[8]; char manufacturer_name[ACPI_SBS_BLOCK_MAX]; @@ -118,7 +122,9 @@ struct acpi_sbs { struct acpi_device *device; struct acpi_smb_hc *hc; struct mutex lock; +#ifdef CONFIG_ACPI_PROCFS struct proc_dir_entry *charger_entry; +#endif struct acpi_battery battery[MAX_SBS_BAT]; u8 batteries_supported:4; u8 manager_present:1; @@ -380,6 +386,8 @@ static int acpi_battery_get_state(struct acpi_battery *battery) return result; } +#ifdef CONFIG_ACPI_PROCFS + static int acpi_battery_get_alarm(struct acpi_battery *battery) { return acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, @@ -416,6 +424,8 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery) return ret; } +#endif + static int acpi_ac_get_present(struct acpi_sbs *sbs) { int result; @@ -432,6 +442,7 @@ static int acpi_ac_get_present(struct acpi_sbs *sbs) FS Interface (/proc/acpi) -------------------------------------------------------------------------- */ +#ifdef CONFIG_ACPI_PROCFS /* Generic Routines */ static int acpi_sbs_add_fs(struct proc_dir_entry **dir, @@ -705,6 +716,8 @@ static struct file_operations acpi_ac_state_fops = { .owner = THIS_MODULE, }; +#endif + /* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */ @@ -750,10 +763,12 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) return result; sprintf(battery->name, ACPI_BATTERY_DIR_NAME, id); +#ifdef CONFIG_ACPI_PROCFS acpi_sbs_add_fs(&battery->proc_entry, acpi_battery_dir, battery->name, &acpi_battery_info_fops, &acpi_battery_state_fops, &acpi_battery_alarm_fops, battery); +#endif battery->bat.name = battery->name; battery->bat.type = POWER_SUPPLY_TYPE_BATTERY; if (!acpi_battery_mode(battery)) { @@ -777,10 +792,12 @@ static void acpi_battery_remove(struct acpi_sbs *sbs, int id) { if (sbs->battery[id].bat.dev) power_supply_unregister(&sbs->battery[id].bat); +#ifdef CONFIG_ACPI_PROCFS if (sbs->battery[id].proc_entry) { acpi_sbs_remove_fs(&(sbs->battery[id].proc_entry), acpi_battery_dir); } +#endif } static int acpi_charger_add(struct acpi_sbs *sbs) @@ -790,11 +807,13 @@ static int acpi_charger_add(struct acpi_sbs *sbs) result = acpi_ac_get_present(sbs); if (result) goto end; +#ifdef CONFIG_ACPI_PROCFS result = acpi_sbs_add_fs(&sbs->charger_entry, acpi_ac_dir, ACPI_AC_DIR_NAME, NULL, &acpi_ac_state_fops, NULL, sbs); if (result) goto end; +#endif sbs->charger.name = "sbs-charger"; sbs->charger.type = POWER_SUPPLY_TYPE_MAINS; sbs->charger.properties = sbs_ac_props; @@ -812,8 +831,10 @@ static void acpi_charger_remove(struct acpi_sbs *sbs) { if (sbs->charger.dev) power_supply_unregister(&sbs->charger); +#ifdef CONFIG_ACPI_PROCFS if (sbs->charger_entry) acpi_sbs_remove_fs(&sbs->charger_entry, acpi_ac_dir); +#endif } void acpi_sbs_callback(void *context) @@ -916,6 +937,7 @@ static int acpi_sbs_remove(struct acpi_device *device, int type) static void acpi_sbs_rmdirs(void) { +#ifdef CONFIG_ACPI_PROCFS if (acpi_ac_dir) { acpi_unlock_ac_dir(acpi_ac_dir); acpi_ac_dir = NULL; @@ -924,6 +946,7 @@ static void acpi_sbs_rmdirs(void) acpi_unlock_battery_dir(acpi_battery_dir); acpi_battery_dir = NULL; } +#endif } static int acpi_sbs_resume(struct acpi_device *device) @@ -953,6 +976,7 @@ static int __init acpi_sbs_init(void) if (acpi_disabled) return -ENODEV; +#ifdef CONFIG_ACPI_PROCFS acpi_ac_dir = acpi_lock_ac_dir(); if (!acpi_ac_dir) return -ENODEV; @@ -961,6 +985,7 @@ static int __init acpi_sbs_init(void) acpi_sbs_rmdirs(); return -ENODEV; } +#endif result = acpi_bus_register_driver(&acpi_sbs_driver); if (result < 0) { acpi_sbs_rmdirs(); -- cgit v1.1 From 8bd955320661cfd03ab8d5574d96aa684acd38f6 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Wed, 26 Sep 2007 19:44:00 +0400 Subject: ACPI: SBS: Add sysfs alarm Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/sbs.c | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index aae65e8..90fd09c 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -386,8 +386,6 @@ static int acpi_battery_get_state(struct acpi_battery *battery) return result; } -#ifdef CONFIG_ACPI_PROCFS - static int acpi_battery_get_alarm(struct acpi_battery *battery) { return acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, @@ -424,8 +422,6 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery) return ret; } -#endif - static int acpi_ac_get_present(struct acpi_sbs *sbs) { int result; @@ -438,6 +434,36 @@ static int acpi_ac_get_present(struct acpi_sbs *sbs) return result; } +static ssize_t acpi_battery_alarm_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); + acpi_battery_get_alarm(battery); + return sprintf(buf, "%d\n", battery->alarm_capacity * + acpi_battery_scale(battery) * 1000); +} + +static ssize_t acpi_battery_alarm_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long x; + struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); + if (sscanf(buf, "%ld\n", &x) == 1) + battery->alarm_capacity = x / + (1000 * acpi_battery_scale(battery)); + if (battery->present) + acpi_battery_set_alarm(battery); + return count; +} + +static struct device_attribute alarm_attr = { + .attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE}, + .show = acpi_battery_alarm_show, + .store = acpi_battery_alarm_store, +}; + /* -------------------------------------------------------------------------- FS Interface (/proc/acpi) -------------------------------------------------------------------------- */ @@ -782,6 +808,7 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) } battery->bat.get_property = acpi_sbs_battery_get_property; result = power_supply_register(&sbs->device->dev, &battery->bat); + device_create_file(battery->bat.dev, &alarm_attr); printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n", ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), battery->name, sbs->battery->present ? "present" : "absent"); @@ -791,6 +818,7 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) static void acpi_battery_remove(struct acpi_sbs *sbs, int id) { if (sbs->battery[id].bat.dev) + device_remove_file(sbs->battery[id].bat.dev, &alarm_attr); power_supply_unregister(&sbs->battery[id].bat); #ifdef CONFIG_ACPI_PROCFS if (sbs->battery[id].proc_entry) { -- cgit v1.1 From d5b4a3d0efa36de31b86d5677dad6c36cb8735d7 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Wed, 26 Sep 2007 19:44:06 +0400 Subject: ACPI: AC: Add sysfs interface Refer to Documentation/power_supply_class.txt for interface description. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 2 +- drivers/acpi/ac.c | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index ba6a61f..a858bc5 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -88,7 +88,7 @@ config ACPI_PROC_EVENT config ACPI_AC tristate "AC Adapter" - depends on X86 + depends on X86 && POWER_SUPPLY default y help This driver adds support for the AC Adapter object, which indicates diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 26d7070..e03de37 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -72,16 +73,37 @@ static struct acpi_driver acpi_ac_driver = { }; struct acpi_ac { + struct power_supply charger; struct acpi_device * device; unsigned long state; }; +#define to_acpi_ac(x) container_of(x, struct acpi_ac, charger); + static const struct file_operations acpi_ac_fops = { .open = acpi_ac_open_fs, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; +static int get_ac_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct acpi_ac *ac = to_acpi_ac(psy); + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = ac->state; + break; + default: + return -EINVAL; + } + return 0; +} + +static enum power_supply_property ac_props[] = { + POWER_SUPPLY_PROP_ONLINE, +}; /* -------------------------------------------------------------------------- AC Adapter Management @@ -208,6 +230,7 @@ static void acpi_ac_notify(acpi_handle handle, u32 event, void *data) acpi_bus_generate_netlink_event(device->pnp.device_class, device->dev.bus_id, event, (u32) ac->state); + kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE); break; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -244,7 +267,12 @@ static int acpi_ac_add(struct acpi_device *device) result = acpi_ac_add_fs(device); if (result) goto end; - + ac->charger.name = acpi_device_bid(device); + ac->charger.type = POWER_SUPPLY_TYPE_MAINS; + ac->charger.properties = ac_props; + ac->charger.num_properties = ARRAY_SIZE(ac_props); + ac->charger.get_property = get_ac_property; + power_supply_register(&ac->device->dev, &ac->charger); status = acpi_install_notify_handler(device->handle, ACPI_ALL_NOTIFY, acpi_ac_notify, ac); @@ -279,7 +307,8 @@ static int acpi_ac_remove(struct acpi_device *device, int type) status = acpi_remove_notify_handler(device->handle, ACPI_ALL_NOTIFY, acpi_ac_notify); - + if (ac->charger.dev) + power_supply_unregister(&ac->charger); acpi_ac_remove_fs(device); kfree(ac); -- cgit v1.1 From 4f86d3a8e297205780cca027e974fd5f81064780 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 3 Oct 2007 18:58:00 -0400 Subject: cpuidle: consolidate 2.6.22 cpuidle branch into one patch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e5a16b1f9eec0af7cfa0830304b41c1c0833cf9f Author: Len Brown Date: Tue Oct 2 23:44:44 2007 -0400 cpuidle: shrink diff processor_idle.c | 440 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 429 insertions(+), 11 deletions(-) Signed-off-by: Len Brown commit dfbb9d5aedfb18848a3e0d6f6e3e4969febb209c Author: Len Brown Date: Wed Sep 26 02:17:55 2007 -0400 cpuidle: reduce diff size Reduces the cpuidle processor_idle.c diff vs 2.6.22 from this processor_idle.c | 2006 ++++++++++++++++++++++++++----------------- 1 file changed, 1219 insertions(+), 787 deletions(-) to this: processor_idle.c | 502 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 458 insertions(+), 44 deletions(-) ...for the purpose of making the cpuilde patch less invasive and easier to review. no functional changes. build tested only. Signed-off-by: Len Brown commit 889172fc915f5a7fe20f35b133cbd205ce69bf6c Author: Venki Pallipadi Date: Thu Sep 13 13:40:05 2007 -0700 cpuidle: Retain old ACPI policy for !CONFIG_CPU_IDLE Retain the old policy in processor_idle, so that when CPU_IDLE is not configured, old C-state policy will still be used. This provides a clean gradual migration path from old ACPI policy to new cpuidle based policy. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Len Brown commit 9544a8181edc7ecc33b3bfd69271571f98ed08bc Author: Venki Pallipadi Date: Thu Sep 13 13:39:17 2007 -0700 cpuidle: Configure governors by default Quoting Len "Do not give an option to users to shoot themselves in the foot". Remove the configurability of ladder and menu governors as they are needed for default policy of cpuidle. That way users will not be able to have cpuidle without any policy loosing all C-state power savings. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Len Brown commit 8975059a2c1e56cfe83d1bcf031bcf4cb39be743 Author: Adam Belay Date: Tue Aug 21 18:27:07 2007 -0400 CPUIDLE: load ACPI properly when CPUIDLE is disabled Change the registration return codes for when CPUIDLE support is not compiled into the kernel. As a result, the ACPI processor driver will load properly even if CPUIDLE is unavailable. However, it may be possible to cleanup the ACPI processor driver further and eliminate some dead code paths. Signed-off-by: Adam Belay Acked-by: Venkatesh Pallipadi Signed-off-by: Len Brown commit e0322e2b58dd1b12ec669bf84693efe0dc2414a8 Author: Adam Belay Date: Tue Aug 21 18:26:06 2007 -0400 CPUIDLE: remove cpuidle_get_bm_activity() Remove cpuidle_get_bm_activity() and updates governors accordingly. Signed-off-by: Adam Belay Acked-by: Venkatesh Pallipadi Signed-off-by: Len Brown commit 18a6e770d5c82ba26653e53d240caa617e09e9ab Author: Adam Belay Date: Tue Aug 21 18:25:58 2007 -0400 CPUIDLE: max_cstate fix Currently max_cstate is limited to 0, resulting in no idle processor power management on ACPI platforms. This patch restores the value to the array size. Signed-off-by: Adam Belay Acked-by: Venkatesh Pallipadi Signed-off-by: Len Brown commit 1fdc0887286179b40ce24bcdbde663172e205ef0 Author: Adam Belay Date: Tue Aug 21 18:25:40 2007 -0400 CPUIDLE: handle BM detection inside the ACPI Processor driver Update the ACPI processor driver to detect BM activity and limit state entry depth internally, rather than exposing such requirements to CPUIDLE. As a result, CPUIDLE can drop this ACPI-specific interface and become more platform independent. BM activity is now handled much more aggressively than it was in the original implementation, so some testing coverage may be needed to verify that this doesn't introduce any DMA buffer under-run issues. Signed-off-by: Adam Belay Acked-by: Venkatesh Pallipadi Signed-off-by: Len Brown commit 0ef38840db666f48e3cdd2b769da676c57228dd9 Author: Adam Belay Date: Tue Aug 21 18:25:14 2007 -0400 CPUIDLE: menu governor updates Tweak the menu governor to more effectively handle non-timer break events. Non-timer break events are detected by comparing the actual sleep time to the expected sleep time. In future revisions, it may be more reliable to use the timer data structures directly. Signed-off-by: Adam Belay Acked-by: Venkatesh Pallipadi Signed-off-by: Len Brown commit bb4d74fca63fa96cf3ace644b15ae0f12b7df5a1 Author: Adam Belay Date: Tue Aug 21 18:24:40 2007 -0400 CPUIDLE: fix 'current_governor' sysfs entry Allow the "current_governor" sysfs entry to properly handle input terminated with '\n'. Signed-off-by: Adam Belay Acked-by: Venkatesh Pallipadi Signed-off-by: Len Brown commit df3c71559bb69b125f1a48971bf0d17f78bbdf47 Author: Len Brown Date: Sun Aug 12 02:00:45 2007 -0400 cpuidle: fix IA64 build (again) Signed-off-by: Len Brown commit a02064579e3f9530fd31baae16b1fc46b5a7bca8 Author: Venkatesh Pallipadi Date: Sun Aug 12 01:39:27 2007 -0400 cpuidle: Remove support for runtime changing of max_cstate Remove support for runtime changeability of max_cstate. Drivers can use use latency APIs. max_cstate can still be used as a boot time option and dmi override. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Len Brown commit 0912a44b13adf22f5e3f607d263aed23b4910d7e Author: Venkatesh Pallipadi Date: Sun Aug 12 01:39:16 2007 -0400 cpuidle: Remove ACPI cstate_limit calls from ipw2100 ipw2100 already has code to use accetable_latency interfaces to limit the C-state. Remove the calls to acpi_set_cstate_limit and acpi_get_cstate_limit as they are redundant. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Len Brown commit c649a76e76be6bff1fd770d0a775798813a3f6e0 Author: Venkatesh Pallipadi Date: Sun Aug 12 01:35:39 2007 -0400 cpuidle: compile fix for pause and resume functions Fix the compilation failure when cpuidle is not compiled in. Signed-off-by: Venkatesh Pallipadi Acked-by: Adam Belay Signed-off-by: Len Brown commit 2305a5920fb8ee6ccec1c62ade05aa8351091d71 Author: Adam Belay Date: Thu Jul 19 00:49:00 2007 -0400 cpuidle: re-write Some portions have been rewritten to make the code cleaner and lighter weight. The following is a list of changes: 1.) the state name is now included in the sysfs interface 2.) detection, hotplug, and available state modifications are handled by CPUIDLE drivers directly 3.) the CPUIDLE idle handler is only ever installed when at least one cpuidle_device is enabled and ready 4.) the menu governor BM code no longer overflows 5.) the sysfs attributes are now printed as unsigned integers, avoiding negative values 6.) a variety of other small cleanups Also, Idle drivers are no longer swappable during runtime through the CPUIDLE sysfs inteface. On i386 and x86_64 most idle handlers (e.g. poll, mwait, halt, etc.) don't benefit from an infrastructure that supports multiple states, so I think using a more general case idle handler selection mechanism would be cleaner. Signed-off-by: Adam Belay Acked-by: Venkatesh Pallipadi Acked-by: Shaohua Li Signed-off-by: Len Brown commit df25b6b56955714e6e24b574d88d1fd11f0c3ee5 Author: Len Brown Date: Tue Jul 24 17:08:21 2007 -0400 cpuidle: fix IA64 buid Signed-off-by: Len Brown commit fd6ada4c14488755ff7068860078c437431fbccd Author: Adrian Bunk Date: Mon Jul 9 11:33:13 2007 -0700 cpuidle: static make cpuidle_replace_governor() static Signed-off-by: Adrian Bunk Cc: Venkatesh Pallipadi Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit c1d4a2cebcadf2429c0c72e1d29aa2a9684c32e0 Author: Adrian Bunk Date: Tue Jul 3 00:54:40 2007 -0400 cpuidle: static This patch makes the needlessly global struct menu_governor static. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit dbf8780c6e8d572c2c273da97ed1cca7608fd999 Author: Andrew Morton Date: Tue Jul 3 00:49:14 2007 -0400 export symbol tick_nohz_get_sleep_length ERROR: "tick_nohz_get_sleep_length" [drivers/cpuidle/governors/menu.ko] undefined! ERROR: "tick_nohz_get_idle_jiffies" [drivers/cpuidle/governors/menu.ko] undefined! And please be sure to get your changes to core kernel suitably reviewed. Cc: Adam Belay Cc: Venki Pallipadi Cc: Ingo Molnar Cc: Thomas Gleixner Cc: john stultz Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 29f0e248e7017be15f99febf9143a2cef00b2961 Author: Andrew Morton Date: Tue Jul 3 00:43:04 2007 -0400 tick.h needs hrtimer.h It uses hrtimers. Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit e40cede7d63a029e92712a3fe02faee60cc38fb4 Author: Venki Pallipadi Date: Tue Jul 3 00:40:34 2007 -0400 cpuidle: first round of documentation updates Documentation changes based on Pavel's feedback. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 83b42be2efece386976507555c29e7773a0dfcd1 Author: Venki Pallipadi Date: Tue Jul 3 00:39:25 2007 -0400 cpuidle: add rating to the governors and pick the one with highest rating by default Introduce a governor rating scheme to pick the right governor by default. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit d2a74b8c5e8f22def4709330d4bfc4a29209b71c Author: Venki Pallipadi Date: Tue Jul 3 00:38:08 2007 -0400 cpuidle: make cpuidle sysfs driver governor switch off by default Make default cpuidle sysfs to show current_governor and current_driver in read-only mode. More elaborate available_governors and available_drivers with writeable current_governor and current_driver interface only appear with "cpuidle_sysfs_switch" boot parameter. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 1f60a0e80bf83cf6b55c8845bbe5596ed8f6307b Author: Venki Pallipadi Date: Tue Jul 3 00:37:00 2007 -0400 cpuidle: menu governor: change the early break condition Change the C-state early break out algorithm in menu governor. We only look at early breakouts that result in wakeups shorter than idle state's target_residency. If such a breakout is frequent enough, eliminate the particular idle state upto a timeout period. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 45a42095cf64b003b4a69be3ce7f434f97d7af51 Author: Venki Pallipadi Date: Tue Jul 3 00:35:38 2007 -0400 cpuidle: fix uninitialized variable in sysfs routine Fix the uninitialized usage of ret. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 80dca7cdba3e6ee13eae277660873ab9584eb3be Author: Venki Pallipadi Date: Tue Jul 3 00:34:16 2007 -0400 cpuidle: reenable /proc/acpi//power interface for the time being Keep /proc/acpi/processor/CPU*/power around for a while as powertop depends on it. It will be marked deprecated and removed in future. powertop can use cpuidle interfaces instead. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 589c37c2646c5e3813a51255a5ee1159cb4c33fc Author: Venki Pallipadi Date: Tue Jul 3 00:32:37 2007 -0400 cpuidle: menu governor and hrtimer compile fix Compile fix for menu governor. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 0ba80bd9ab3ed304cb4f19b722e4cc6740588b5e Author: Len Brown Date: Thu May 31 22:51:43 2007 -0400 cpuidle: build fix - cpuidle vs ipw2100 module ERROR: "acpi_set_cstate_limit" [drivers/net/wireless/ipw2100.ko] undefined! Signed-off-by: Len Brown commit d7d8fa7f96a7f7682be7c6cc0cc53fa7a18c3b58 Author: Adam Belay Date: Sat Mar 24 03:47:07 2007 -0400 cpuidle: add the 'menu' governor Here is my first take at implementing an idle PM governor that takes full advantage of NO_HZ. I call it the 'menu' governor because it considers the full list of idle states before each entry. I've kept the implementation fairly simple. It attempts to guess the next residency time and then chooses a state that would meet at least the break-even point between power savings and entry cost. To this end, it selects the deepest idle state that satisfies the following constraints: 1. If the idle time elapsed since bus master activity was detected is below a threshold (currently 20 ms), then limit the selection to C2-type or above. 2. Do not choose a state with a break-even residency that exceeds the expected time remaining until the next timer interrupt. 3. Do not choose a state with a break-even residency that exceeds the elapsed time between the last pair of break events, excluding timer interrupts. This governor has an advantage over "ladder" governor because it proactively checks how much time remains until the next timer interrupt using the tick infrastructure. Also, it handles device interrupt activity more intelligently by not including timer interrupts in break event calculations. Finally, it doesn't make policy decisions using the number of state entries, which can have variable residency times (NO_HZ makes these potentially very large), and instead only considers sleep time deltas. The menu governor can be selected during runtime using the cpuidle sysfs interface like so: "echo "menu" > /sys/devices/system/cpu/cpuidle/current_governor" Signed-off-by: Adam Belay Signed-off-by: Len Brown commit a4bec7e65aa3b7488b879d971651cc99a6c410fe Author: Adam Belay Date: Sat Mar 24 03:47:03 2007 -0400 cpuidle: export time until next timer interrupt using NO_HZ Expose information about the time remaining until the next timer interrupt expires by utilizing the dynticks infrastructure. Also modify the main idle loop to allow dynticks to handle non-interrupt break events (e.g. DMA). Finally, expose sleep ticks information to external code. Thomas Gleixner is responsible for much of the code in this patch. However, I've made some additional changes, so I'm probably responsible if there are any bugs or oversights :) Signed-off-by: Adam Belay Signed-off-by: Len Brown commit 2929d8996fbc77f41a5ff86bb67cdde3ca7d2d72 Author: Adam Belay Date: Sat Mar 24 03:46:58 2007 -0400 cpuidle: governor API changes This patch prepares cpuidle for the menu governor. It adds an optional stage after idle state entry to give the governor an opportunity to check why the state was exited. Also it makes sure the idle loop returns after each state entry, allowing the appropriate dynticks code to run. Signed-off-by: Adam Belay Signed-off-by: Len Brown commit 3a7fd42f9825c3b03e364ca59baa751bb350775f Author: Venki Pallipadi Date: Thu Apr 26 00:03:59 2007 -0700 cpuidle: hang fix Prevent hang on x86-64, when ACPI processor driver is added as a module on a system that does not support C-states. x86-64 expects all idle handlers to enable interrupts before returning from idle handler. This is due to enter_idle(), exit_idle() races. Make cpuidle_idle_call() confirm to this when there is no pm_idle_old. Also, cpuidle look at the return values of attch_driver() and set current_driver to NULL if attach fails on all CPUs. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 4893339a142afbd5b7c01ffadfd53d14746e858e Author: Shaohua Li Date: Thu Apr 26 10:40:09 2007 +0800 cpuidle: add support for max_cstate limit With CPUIDLE framework, the max_cstate (to limit max cpu c-state) parameter is ingored. Some systems require it to ignore C2/C3 and some drivers like ipw require it too. Signed-off-by: Shaohua Li Signed-off-by: Len Brown commit 43bbbbe1cb998cbd2df656f55bb3bfe30f30e7d1 Author: Shaohua Li Date: Thu Apr 26 10:40:13 2007 +0800 cpuidle: add cpuidle_fore_redetect_devices API add cpuidle_force_redetect_devices API, which forces all CPU redetect idle states. Next patch will use it. Signed-off-by: Shaohua Li Signed-off-by: Len Brown commit d1edadd608f24836def5ec483d2edccfb37b1d19 Author: Shaohua Li Date: Thu Apr 26 10:40:01 2007 +0800 cpuidle: fix sysfs related issue Fix the cpuidle sysfs issue. a. make kobject dynamicaly allocated b. fixed sysfs init issue to avoid suspend/resume issue Signed-off-by: Shaohua Li Signed-off-by: Len Brown commit 7169a5cc0d67b263978859672e86c13c23a5570d Author: Randy Dunlap Date: Wed Mar 28 22:52:53 2007 -0400 cpuidle: 1-bit field must be unsigned A 1-bit bitfield has no room for a sign bit. drivers/cpuidle/governors/ladder.c:54:16: error: dubious bitfield without explicit `signed' or `unsigned' Signed-off-by: Randy Dunlap Cc: Venkatesh Pallipadi Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 4658620158dc2fbd9e4bcb213c5b6fb5d05ba7d4 Author: Venkatesh Pallipadi Date: Wed Mar 28 22:52:41 2007 -0400 cpuidle: fix boot hang Patch for cpuidle boot hang reported by Larry Finger here. http://www.ussg.iu.edu/hypermail/linux/kernel/0703.2/2025.html Signed-off-by: Venkatesh Pallipadi Cc: Larry Finger Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit c17e168aa6e5fe3851baaae8df2fbc1cf11443a9 Author: Len Brown Date: Wed Mar 7 04:37:53 2007 -0500 cpuidle: ladder does not depend on ACPI build fix for CONFIG_ACPI=n In file included from drivers/cpuidle/governors/ladder.c:21: include/acpi/processor.h:88: error: expected specifier-qualifier-list before ‘acpi_integer’ include/acpi/processor.h:106: error: expected specifier-qualifier-list before ‘acpi_integer’ include/acpi/processor.h:168: error: expected specifier-qualifier-list before ‘acpi_handle’ Signed-off-by: Len Brown commit 8c91d958246bde68db0c3f0c57b535962ce861cb Author: Adrian Bunk Date: Tue Mar 6 02:29:40 2007 -0800 cpuidle: make code static This patch makes the following needlessly global code static: - driver.c: __cpuidle_find_driver() - governor.c: __cpuidle_find_governor() - ladder.c: struct ladder_governor Signed-off-by: Adrian Bunk Cc: Venkatesh Pallipadi Cc: Adam Belay Cc: Shaohua Li Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 0c39dc3187094c72c33ab65a64d2017b21f372d2 Author: Venkatesh Pallipadi Date: Wed Mar 7 02:38:22 2007 -0500 cpu_idle: fix build break This patch fixes a build breakage with !CONFIG_HOTPLUG_CPU and CONFIG_CPU_IDLE. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 8112e3b115659b07df340ef170515799c0105f82 Author: Venkatesh Pallipadi Date: Tue Mar 6 02:29:39 2007 -0800 cpuidle: build fix for !CPU_IDLE Fix the compile issues when CPU_IDLE is not configured. Signed-off-by: Venkatesh Pallipadi Cc: Adam Belay Cc: Shaohua Li Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 1eb4431e9599cd25e0d9872f3c2c8986821839dd Author: Venkatesh Pallipadi Date: Thu Feb 22 13:54:57 2007 -0800 cpuidle take2: Basic documentation for cpuidle Documentation for cpuidle infrastructure Signed-off-by: Venkatesh Pallipadi Signed-off-by: Adam Belay Signed-off-by: Shaohua Li Signed-off-by: Len Brown commit ef5f15a8b79123a047285ec2e3899108661df779 Author: Venkatesh Pallipadi Date: Thu Feb 22 13:54:03 2007 -0800 cpuidle take2: Hookup ACPI C-states driver with cpuidle Hookup ACPI C-states onto generic cpuidle infrastructure. drivers/acpi/procesor_idle.c is now a ACPI C-states driver that registers as a driver in cpuidle infrastructure and the policy part is removed from drivers/acpi/processor_idle.c. We use governor in cpuidle instead. Signed-off-by: Shaohua Li Signed-off-by: Venkatesh Pallipadi Signed-off-by: Adam Belay Signed-off-by: Len Brown commit 987196fa82d4db52c407e8c9d5dec884ba602183 Author: Venkatesh Pallipadi Date: Thu Feb 22 13:52:57 2007 -0800 cpuidle take2: Core cpuidle infrastructure Announcing 'cpuidle', a new CPU power management infrastructure to manage idle CPUs in a clean and efficient manner. cpuidle separates out the drivers that can provide support for multiple types of idle states and policy governors that decide on what idle state to use at run time. A cpuidle driver can support multiple idle states based on parameters like varying power consumption, wakeup latency, etc (ACPI C-states for example). A cpuidle governor can be usage model specific (laptop, server, laptop on battery etc). Main advantage of the infrastructure being, it allows independent development of drivers and governors and allows for better CPU power management. A huge thanks to Adam Belay and Shaohua Li who were part of this mini-project since its beginning and are greatly responsible for this patchset. This patch: Core cpuidle infrastructure. Introduces a new abstraction layer for cpuidle: * which manages drivers that can support multiple idles states. Drivers can be generic or particular to specific hardware/platform * allows pluging in multiple policy governors that can take idle state policy decision * The core also has a set of sysfs interfaces with which administrato can know about supported drivers and governors and switch them at run time. Signed-off-by: Adam Belay Signed-off-by: Shaohua Li Signed-off-by: Venkatesh Pallipadi Signed-off-by: Len Brown Signed-off-by: Len Brown --- drivers/acpi/osl.c | 8 - drivers/acpi/processor_core.c | 22 +- drivers/acpi/processor_idle.c | 482 ++++++++++++++++++++++++++++++++++++++---- 3 files changed, 460 insertions(+), 52 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 12c09fa..5d14d4f 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1043,14 +1043,6 @@ static int __init acpi_wake_gpes_always_on_setup(char *str) __setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup); /* - * max_cstate is defined in the base kernel so modules can - * change it w/o depending on the state of the processor module. - */ -unsigned int max_cstate = ACPI_PROCESSOR_MAX_POWER; - -EXPORT_SYMBOL(max_cstate); - -/* * Acquire a spinlock. * * handle is a pointer to the spinlock_t. diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 9f11dc2..a735108 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -1049,11 +1050,13 @@ static int __init acpi_processor_init(void) return -ENOMEM; acpi_processor_dir->owner = THIS_MODULE; + result = cpuidle_register_driver(&acpi_idle_driver); + if (result < 0) + goto out_proc; + result = acpi_bus_register_driver(&acpi_processor_driver); - if (result < 0) { - remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); - return result; - } + if (result < 0) + goto out_cpuidle; acpi_processor_install_hotplug_notify(); @@ -1062,11 +1065,18 @@ static int __init acpi_processor_init(void) acpi_processor_ppc_init(); return 0; + +out_cpuidle: + cpuidle_unregister_driver(&acpi_idle_driver); + +out_proc: + remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); + + return result; } static void __exit acpi_processor_exit(void) { - acpi_processor_ppc_exit(); acpi_thermal_cpufreq_exit(); @@ -1075,6 +1085,8 @@ static void __exit acpi_processor_exit(void) acpi_bus_unregister_driver(&acpi_processor_driver); + cpuidle_unregister_driver(&acpi_idle_driver); + remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); return; diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index f182613..99da6a7 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -40,6 +40,7 @@ #include /* need_resched() */ #include #include +#include /* * Include the apic definitions for x86 to have the APIC timer related defines @@ -64,14 +65,22 @@ ACPI_MODULE_NAME("processor_idle"); #define ACPI_PROCESSOR_FILE_POWER "power" #define US_TO_PM_TIMER_TICKS(t) ((t * (PM_TIMER_FREQUENCY/1000)) / 1000) #define PM_TIMER_TICK_NS (1000000000ULL/PM_TIMER_FREQUENCY) +#ifndef CONFIG_CPU_IDLE #define C2_OVERHEAD 4 /* 1us (3.579 ticks per us) */ #define C3_OVERHEAD 4 /* 1us (3.579 ticks per us) */ static void (*pm_idle_save) (void) __read_mostly; -module_param(max_cstate, uint, 0644); +#else +#define C2_OVERHEAD 1 /* 1us */ +#define C3_OVERHEAD 1 /* 1us */ +#endif +#define PM_TIMER_TICKS_TO_US(p) (((p) * 1000)/(PM_TIMER_FREQUENCY/1000)) +static unsigned int max_cstate __read_mostly = ACPI_PROCESSOR_MAX_POWER; +module_param(max_cstate, uint, 0000); static unsigned int nocst __read_mostly; module_param(nocst, uint, 0000); +#ifndef CONFIG_CPU_IDLE /* * bm_history -- bit-mask with a bit per jiffy of bus-master activity * 1000 HZ: 0xFFFFFFFF: 32 jiffies = 32ms @@ -82,9 +91,10 @@ module_param(nocst, uint, 0000); static unsigned int bm_history __read_mostly = (HZ >= 800 ? 0xFFFFFFFF : ((1U << (HZ / 25)) - 1)); module_param(bm_history, uint, 0644); -/* -------------------------------------------------------------------------- - Power Management - -------------------------------------------------------------------------- */ + +static int acpi_processor_set_power_policy(struct acpi_processor *pr); + +#endif /* * IBM ThinkPad R40e crashes mysteriously when going into C2 or C3. @@ -177,6 +187,18 @@ static inline u32 ticks_elapsed(u32 t1, u32 t2) return ((0xFFFFFFFF - t1) + t2); } +static inline u32 ticks_elapsed_in_us(u32 t1, u32 t2) +{ + if (t2 >= t1) + return PM_TIMER_TICKS_TO_US(t2 - t1); + else if (!(acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER)) + return PM_TIMER_TICKS_TO_US(((0x00FFFFFF - t1) + t2) & 0x00FFFFFF); + else + return PM_TIMER_TICKS_TO_US((0xFFFFFFFF - t1) + t2); +} + +#ifndef CONFIG_CPU_IDLE + static void acpi_processor_power_activate(struct acpi_processor *pr, struct acpi_processor_cx *new) @@ -248,6 +270,7 @@ static void acpi_cstate_enter(struct acpi_processor_cx *cstate) unused = inl(acpi_gbl_FADT.xpm_timer_block.address); } } +#endif /* !CONFIG_CPU_IDLE */ #ifdef ARCH_APICTIMER_STOPS_ON_C3 @@ -342,6 +365,7 @@ int acpi_processor_resume(struct acpi_device * device) return 0; } +#ifndef CONFIG_CPU_IDLE static void acpi_processor_idle(void) { struct acpi_processor *pr = NULL; @@ -439,7 +463,7 @@ static void acpi_processor_idle(void) * an SMP system. We do it here instead of doing it at _CST/P_LVL * detection phase, to work cleanly with logical CPU hotplug. */ - if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && + if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) cx = &pr->power.states[ACPI_STATE_C1]; #endif @@ -739,6 +763,7 @@ static int acpi_processor_set_power_policy(struct acpi_processor *pr) return 0; } +#endif /* !CONFIG_CPU_IDLE */ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) { @@ -756,7 +781,7 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) #ifndef CONFIG_HOTPLUG_CPU /* * Check for P_LVL2_UP flag before entering C2 and above on - * an SMP system. + * an SMP system. */ if ((num_online_cpus() > 1) && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) @@ -957,7 +982,12 @@ static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx) * Normalize the C2 latency to expidite policy */ cx->valid = 1; + +#ifndef CONFIG_CPU_IDLE cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency); +#else + cx->latency_ticks = cx->latency; +#endif return; } @@ -1037,7 +1067,12 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr, * use this in our C3 policy */ cx->valid = 1; + +#ifndef CONFIG_CPU_IDLE cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency); +#else + cx->latency_ticks = cx->latency; +#endif return; } @@ -1102,6 +1137,7 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) pr->power.count = acpi_processor_power_verify(pr); +#ifndef CONFIG_CPU_IDLE /* * Set Default Policy * ------------------ @@ -1113,6 +1149,7 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) result = acpi_processor_set_power_policy(pr); if (result) return result; +#endif /* * if one state of type C2 or C3 is available, mark this @@ -1129,35 +1166,6 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) return 0; } -int acpi_processor_cst_has_changed(struct acpi_processor *pr) -{ - int result = 0; - - - if (!pr) - return -EINVAL; - - if (nocst) { - return -ENODEV; - } - - if (!pr->flags.power_setup_done) - return -ENODEV; - - /* Fall back to the default idle loop */ - pm_idle = pm_idle_save; - synchronize_sched(); /* Relies on interrupts forcing exit from idle. */ - - pr->flags.power = 0; - result = acpi_processor_get_power_info(pr); - if ((pr->flags.power == 1) && (pr->flags.power_setup_done)) - pm_idle = acpi_processor_idle; - - return result; -} - -/* proc interface */ - static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset) { struct acpi_processor *pr = seq->private; @@ -1239,6 +1247,35 @@ static const struct file_operations acpi_processor_power_fops = { .release = single_release, }; +#ifndef CONFIG_CPU_IDLE + +int acpi_processor_cst_has_changed(struct acpi_processor *pr) +{ + int result = 0; + + + if (!pr) + return -EINVAL; + + if (nocst) { + return -ENODEV; + } + + if (!pr->flags.power_setup_done) + return -ENODEV; + + /* Fall back to the default idle loop */ + pm_idle = pm_idle_save; + synchronize_sched(); /* Relies on interrupts forcing exit from idle. */ + + pr->flags.power = 0; + result = acpi_processor_get_power_info(pr); + if ((pr->flags.power == 1) && (pr->flags.power_setup_done)) + pm_idle = acpi_processor_idle; + + return result; +} + #ifdef CONFIG_SMP static void smp_callback(void *v) { @@ -1261,7 +1298,360 @@ static int acpi_processor_latency_notify(struct notifier_block *b, static struct notifier_block acpi_processor_latency_notifier = { .notifier_call = acpi_processor_latency_notify, }; + +#endif + +#else /* CONFIG_CPU_IDLE */ + +/** + * acpi_idle_bm_check - checks if bus master activity was detected + */ +static int acpi_idle_bm_check(void) +{ + u32 bm_status = 0; + + acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status); + if (bm_status) + acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, 1); + /* + * PIIX4 Erratum #18: Note that BM_STS doesn't always reflect + * the true state of bus mastering activity; forcing us to + * manually check the BMIDEA bit of each IDE channel. + */ + else if (errata.piix4.bmisx) { + if ((inb_p(errata.piix4.bmisx + 0x02) & 0x01) + || (inb_p(errata.piix4.bmisx + 0x0A) & 0x01)) + bm_status = 1; + } + return bm_status; +} + +/** + * acpi_idle_update_bm_rld - updates the BM_RLD bit depending on target state + * @pr: the processor + * @target: the new target state + */ +static inline void acpi_idle_update_bm_rld(struct acpi_processor *pr, + struct acpi_processor_cx *target) +{ + if (pr->flags.bm_rld_set && target->type != ACPI_STATE_C3) { + acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0); + pr->flags.bm_rld_set = 0; + } + + if (!pr->flags.bm_rld_set && target->type == ACPI_STATE_C3) { + acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1); + pr->flags.bm_rld_set = 1; + } +} + +/** + * acpi_idle_do_entry - a helper function that does C2 and C3 type entry + * @cx: cstate data + */ +static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) +{ + if (cx->space_id == ACPI_CSTATE_FFH) { + /* Call into architectural FFH based C-state */ + acpi_processor_ffh_cstate_enter(cx); + } else { + int unused; + /* IO port based C-state */ + inb(cx->address); + /* Dummy wait op - must do something useless after P_LVL2 read + because chipsets cannot guarantee that STPCLK# signal + gets asserted in time to freeze execution properly. */ + unused = inl(acpi_gbl_FADT.xpm_timer_block.address); + } +} + +/** + * acpi_idle_enter_c1 - enters an ACPI C1 state-type + * @dev: the target CPU + * @state: the state data + * + * This is equivalent to the HALT instruction. + */ +static int acpi_idle_enter_c1(struct cpuidle_device *dev, + struct cpuidle_state *state) +{ + struct acpi_processor *pr; + struct acpi_processor_cx *cx = cpuidle_get_statedata(state); + pr = processors[smp_processor_id()]; + + if (unlikely(!pr)) + return 0; + + if (pr->flags.bm_check) + acpi_idle_update_bm_rld(pr, cx); + + current_thread_info()->status &= ~TS_POLLING; + /* + * TS_POLLING-cleared state must be visible before we test + * NEED_RESCHED: + */ + smp_mb(); + if (!need_resched()) + safe_halt(); + current_thread_info()->status |= TS_POLLING; + + cx->usage++; + + return 0; +} + +/** + * acpi_idle_enter_simple - enters an ACPI state without BM handling + * @dev: the target CPU + * @state: the state data + */ +static int acpi_idle_enter_simple(struct cpuidle_device *dev, + struct cpuidle_state *state) +{ + struct acpi_processor *pr; + struct acpi_processor_cx *cx = cpuidle_get_statedata(state); + u32 t1, t2; + pr = processors[smp_processor_id()]; + + if (unlikely(!pr)) + return 0; + + if (pr->flags.bm_check) + acpi_idle_update_bm_rld(pr, cx); + + local_irq_disable(); + current_thread_info()->status &= ~TS_POLLING; + /* + * TS_POLLING-cleared state must be visible before we test + * NEED_RESCHED: + */ + smp_mb(); + + if (unlikely(need_resched())) { + current_thread_info()->status |= TS_POLLING; + local_irq_enable(); + return 0; + } + + if (cx->type == ACPI_STATE_C3) + ACPI_FLUSH_CPU_CACHE(); + + t1 = inl(acpi_gbl_FADT.xpm_timer_block.address); + acpi_state_timer_broadcast(pr, cx, 1); + acpi_idle_do_entry(cx); + t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); + +#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC) + /* TSC could halt in idle, so notify users */ + mark_tsc_unstable("TSC halts in idle");; +#endif + + local_irq_enable(); + current_thread_info()->status |= TS_POLLING; + + cx->usage++; + + acpi_state_timer_broadcast(pr, cx, 0); + cx->time += ticks_elapsed(t1, t2); + return ticks_elapsed_in_us(t1, t2); +} + +static int c3_cpu_count; +static DEFINE_SPINLOCK(c3_lock); + +/** + * acpi_idle_enter_bm - enters C3 with proper BM handling + * @dev: the target CPU + * @state: the state data + * + * If BM is detected, the deepest non-C3 idle state is entered instead. + */ +static int acpi_idle_enter_bm(struct cpuidle_device *dev, + struct cpuidle_state *state) +{ + struct acpi_processor *pr; + struct acpi_processor_cx *cx = cpuidle_get_statedata(state); + u32 t1, t2; + pr = processors[smp_processor_id()]; + + if (unlikely(!pr)) + return 0; + + local_irq_disable(); + current_thread_info()->status &= ~TS_POLLING; + /* + * TS_POLLING-cleared state must be visible before we test + * NEED_RESCHED: + */ + smp_mb(); + + if (unlikely(need_resched())) { + current_thread_info()->status |= TS_POLLING; + local_irq_enable(); + return 0; + } + + /* + * Must be done before busmaster disable as we might need to + * access HPET ! + */ + acpi_state_timer_broadcast(pr, cx, 1); + + if (acpi_idle_bm_check()) { + cx = pr->power.bm_state; + + acpi_idle_update_bm_rld(pr, cx); + + t1 = inl(acpi_gbl_FADT.xpm_timer_block.address); + acpi_idle_do_entry(cx); + t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); + } else { + acpi_idle_update_bm_rld(pr, cx); + + spin_lock(&c3_lock); + c3_cpu_count++; + /* Disable bus master arbitration when all CPUs are in C3 */ + if (c3_cpu_count == num_online_cpus()) + acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1); + spin_unlock(&c3_lock); + + t1 = inl(acpi_gbl_FADT.xpm_timer_block.address); + acpi_idle_do_entry(cx); + t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); + + spin_lock(&c3_lock); + /* Re-enable bus master arbitration */ + if (c3_cpu_count == num_online_cpus()) + acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0); + c3_cpu_count--; + spin_unlock(&c3_lock); + } + +#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC) + /* TSC could halt in idle, so notify users */ + mark_tsc_unstable("TSC halts in idle"); +#endif + + local_irq_enable(); + current_thread_info()->status |= TS_POLLING; + + cx->usage++; + + acpi_state_timer_broadcast(pr, cx, 0); + cx->time += ticks_elapsed(t1, t2); + return ticks_elapsed_in_us(t1, t2); +} + +struct cpuidle_driver acpi_idle_driver = { + .name = "acpi_idle", + .owner = THIS_MODULE, +}; + +/** + * acpi_processor_setup_cpuidle - prepares and configures CPUIDLE + * @pr: the ACPI processor + */ +static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) +{ + int i, count = 0; + struct acpi_processor_cx *cx; + struct cpuidle_state *state; + struct cpuidle_device *dev = &pr->power.dev; + + if (!pr->flags.power_setup_done) + return -EINVAL; + + if (pr->flags.power == 0) { + return -EINVAL; + } + + for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) { + cx = &pr->power.states[i]; + state = &dev->states[count]; + + if (!cx->valid) + continue; + +#ifdef CONFIG_HOTPLUG_CPU + if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && + !pr->flags.has_cst && + !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) + continue; #endif + cpuidle_set_statedata(state, cx); + + snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i); + state->exit_latency = cx->latency; + state->target_residency = cx->latency * 6; + state->power_usage = cx->power; + + state->flags = 0; + switch (cx->type) { + case ACPI_STATE_C1: + state->flags |= CPUIDLE_FLAG_SHALLOW; + state->enter = acpi_idle_enter_c1; + break; + + case ACPI_STATE_C2: + state->flags |= CPUIDLE_FLAG_BALANCED; + state->flags |= CPUIDLE_FLAG_TIME_VALID; + state->enter = acpi_idle_enter_simple; + break; + + case ACPI_STATE_C3: + state->flags |= CPUIDLE_FLAG_DEEP; + state->flags |= CPUIDLE_FLAG_TIME_VALID; + state->flags |= CPUIDLE_FLAG_CHECK_BM; + state->enter = pr->flags.bm_check ? + acpi_idle_enter_bm : + acpi_idle_enter_simple; + break; + } + + count++; + } + + dev->state_count = count; + + if (!count) + return -EINVAL; + + /* find the deepest state that can handle active BM */ + if (pr->flags.bm_check) { + for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) + if (pr->power.states[i].type == ACPI_STATE_C3) + break; + pr->power.bm_state = &pr->power.states[i-1]; + } + + return 0; +} + +int acpi_processor_cst_has_changed(struct acpi_processor *pr) +{ + int ret; + + if (!pr) + return -EINVAL; + + if (nocst) { + return -ENODEV; + } + + if (!pr->flags.power_setup_done) + return -ENODEV; + + cpuidle_pause_and_lock(); + cpuidle_disable_device(&pr->power.dev); + acpi_processor_get_power_info(pr); + acpi_processor_setup_cpuidle(pr); + ret = cpuidle_enable_device(&pr->power.dev); + cpuidle_resume_and_unlock(); + + return ret; +} + +#endif /* CONFIG_CPU_IDLE */ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *device) @@ -1279,7 +1669,7 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, "ACPI: processor limited to max C-state %d\n", max_cstate); first_run++; -#ifdef CONFIG_SMP +#if !defined (CONFIG_CPU_IDLE) && defined (CONFIG_SMP) register_latency_notifier(&acpi_processor_latency_notifier); #endif } @@ -1297,6 +1687,7 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, } acpi_processor_get_power_info(pr); + pr->flags.power_setup_done = 1; /* * Install the idle handler if processor power management is supported. @@ -1304,6 +1695,13 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, * platforms that only support C1. */ if ((pr->flags.power) && (!boot_option_idle_override)) { +#ifdef CONFIG_CPU_IDLE + acpi_processor_setup_cpuidle(pr); + pr->power.dev.cpu = pr->id; + if (cpuidle_register_device(&pr->power.dev)) + return -EIO; +#endif + printk(KERN_INFO PREFIX "CPU%d (power states:", pr->id); for (i = 1; i <= pr->power.count; i++) if (pr->power.states[i].valid) @@ -1311,10 +1709,12 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, pr->power.states[i].type); printk(")\n"); +#ifndef CONFIG_CPU_IDLE if (pr->id == 0) { pm_idle_save = pm_idle; pm_idle = acpi_processor_idle; } +#endif } /* 'power' [R] */ @@ -1328,21 +1728,24 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, entry->owner = THIS_MODULE; } - pr->flags.power_setup_done = 1; - return 0; } int acpi_processor_power_exit(struct acpi_processor *pr, struct acpi_device *device) { - +#ifdef CONFIG_CPU_IDLE + if ((pr->flags.power) && (!boot_option_idle_override)) + cpuidle_unregister_device(&pr->power.dev); +#endif pr->flags.power_setup_done = 0; if (acpi_device_dir(device)) remove_proc_entry(ACPI_PROCESSOR_FILE_POWER, acpi_device_dir(device)); +#ifndef CONFIG_CPU_IDLE + /* Unregister the idle handler when processor #0 is removed. */ if (pr->id == 0) { pm_idle = pm_idle_save; @@ -1357,6 +1760,7 @@ int acpi_processor_power_exit(struct acpi_processor *pr, unregister_latency_notifier(&acpi_processor_latency_notifier); #endif } +#endif return 0; } -- cgit v1.1 From 8ab7367f483d1d676d61fca58498a73b194dda82 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 2 Oct 2007 13:24:10 -0700 Subject: ACPI: suppress uninitialized var warning drivers/acpi/tables/tbutils.c: In function `acpi_tb_parse_root_table': drivers/acpi/tables/tbutils.c:403: warning: `rsdt_address' may be used uninitialized in this function Reported-by: Uwe Bugla Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/tables/tbutils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c index 8cc9492..5f1d85f 100644 --- a/drivers/acpi/tables/tbutils.c +++ b/drivers/acpi/tables/tbutils.c @@ -400,7 +400,7 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags) u32 table_count; struct acpi_table_header *table; acpi_physical_address address; - acpi_physical_address rsdt_address; + acpi_physical_address uninitialized_var(rsdt_address); u32 length; u8 *table_entry; acpi_status status; -- cgit v1.1 From 8a0bb7362587807fec985f72fb0317aa8ed24835 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 2 Oct 2007 13:24:08 -0700 Subject: Hibernation: Make sure that ACPI is enabled in acpi_hibernation_finish If the BIOS does not enable ACPI and the "acpi=off" command line parameter is passed to the boot kernel, ACPI may be disabled when the (restored) image kernel attempts to execute acpi_hibernation_finish(). To prevent this from happening we can call acpi_enable() from acpi_hibernation_finish() (if ACPI is already enabled, this will have no effect). Signed-off-by: Rafael J. Wysocki Acked-by: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/sleep/main.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 2cbb9aa..caf8721 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -256,6 +256,11 @@ static int acpi_hibernation_enter(void) static void acpi_hibernation_finish(void) { + /* + * If ACPI is not enabled by the BIOS and the boot kernel, we need to + * enable it here. + */ + acpi_enable(); acpi_leave_sleep_state(ACPI_STATE_S4); acpi_disable_wakeup_device(ACPI_STATE_S4); -- cgit v1.1 From 6cffd46651b881a11791a7ef4d99f2f20853fcd9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 2 Oct 2007 13:24:09 -0700 Subject: ACPI: clean up acpi_enter_sleep_state_prep Remove some redundant code from acpi_enter_sleep_state_prep() and clean up a comment in there. Signed-off-by: Rafael J. Wysocki Acked-by: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/hardware/hwsleep.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index cf69c00..8181afb 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -234,15 +234,11 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) "While executing method _SST")); } - /* - * 1) Disable/Clear all GPEs - */ + /* Disable/Clear all GPEs */ + status = acpi_hw_disable_all_gpes(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - return_ACPI_STATUS(AE_OK); + return_ACPI_STATUS(status); } ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep) -- cgit v1.1 From e196441bdf2dbf0526b28a6829c39557c236d611 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Thu, 4 Oct 2007 01:23:47 -0400 Subject: ACPI: cpuidle: port idle timer suspend/resume workaround to cpuidle Some timers stop during C2 and C3, and so there are various generations of timer broadcast workarounds to deal with that. But that (already complex) code gets confused during suspend. As it is unlikely that deep C-states would save much power during the actual suspend/resume process anyway, deep C-states were disabled via the addition of .suspend/.resume hooks in to the ACPI processor driver. Here that workaround is ported to the cpuidle version of the ACPI idle loop. Technically, ACPI could un-register itself from cpuidle on .suspend, but that code path is currently quite cumbersome. So instead, we simply invoke C1 from the C2 and C3 handlers for the duration of .suspend/.resume. Signed-off-by: Len Brown --- drivers/acpi/processor_idle.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 99da6a7..0cad56c 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1416,6 +1416,9 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, if (unlikely(!pr)) return 0; + if (acpi_idle_suspend) + return(acpi_idle_enter_c1(dev, state)); + if (pr->flags.bm_check) acpi_idle_update_bm_rld(pr, cx); @@ -1477,6 +1480,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, if (unlikely(!pr)) return 0; + if (acpi_idle_suspend) + return(acpi_idle_enter_c1(dev, state)); + local_irq_disable(); current_thread_info()->status &= ~TS_POLLING; /* -- cgit v1.1 From d30dc9abb4aacfd4df3f486f22bcbc0531b73283 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Sun, 30 Sep 2007 22:39:36 +0400 Subject: ACPICA: hw: remove use_lock flag from acpi_hw_register_{read, write} use_lock flag is used once for acpi_hw_register_read, and never for acpi_hw_register_write. It will greatly simplify understanding of locking if we just drop this use_lock altogether, and wrap the only call to ..._read in lock/unlock. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/events/evevent.c | 6 +-- drivers/acpi/hardware/hwregs.c | 89 ++++++++++++++++------------------------- drivers/acpi/hardware/hwsleep.c | 27 +++++-------- 3 files changed, 46 insertions(+), 76 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c index a1f87b5..e412878 100644 --- a/drivers/acpi/events/evevent.c +++ b/drivers/acpi/events/evevent.c @@ -239,10 +239,8 @@ u32 acpi_ev_fixed_event_detect(void) * Read the fixed feature status and enable registers, as all the cases * depend on their values. Ignore errors here. */ - (void)acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1_STATUS, &fixed_status); - (void)acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1_ENABLE, &fixed_enable); + (void)acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &fixed_status); + (void)acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &fixed_enable); ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, "Fixed Event Block: Enable %08X Status %08X\n", diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c index 1d371fa..73f9c5f 100644 --- a/drivers/acpi/hardware/hwregs.c +++ b/drivers/acpi/hardware/hwregs.c @@ -75,8 +75,7 @@ acpi_status acpi_hw_clear_acpi_status(void) lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); - status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1_STATUS, + status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, ACPI_BITMASK_ALL_FIXED_STATUS); if (ACPI_FAILURE(status)) { goto unlock_and_exit; @@ -259,7 +258,7 @@ struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id) * ******************************************************************************/ -acpi_status acpi_get_register(u32 register_id, u32 * return_value) +acpi_status acpi_get_register_unlocked(u32 register_id, u32 * return_value) { u32 register_value = 0; struct acpi_bit_register_info *bit_reg_info; @@ -276,8 +275,7 @@ acpi_status acpi_get_register(u32 register_id, u32 * return_value) /* Read from the register */ - status = acpi_hw_register_read(ACPI_MTX_LOCK, - bit_reg_info->parent_register, + status = acpi_hw_register_read(bit_reg_info->parent_register, ®ister_value); if (ACPI_SUCCESS(status)) { @@ -298,6 +296,16 @@ acpi_status acpi_get_register(u32 register_id, u32 * return_value) return_ACPI_STATUS(status); } +acpi_status acpi_get_register(u32 register_id, u32 * return_value) +{ + acpi_status status; + acpi_cpu_flags flags; + flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); + status = acpi_get_register_unlocked(register_id, return_value); + acpi_os_release_lock(acpi_gbl_hardware_lock, flags); + return status; +} + ACPI_EXPORT_SYMBOL(acpi_get_register) /******************************************************************************* @@ -335,8 +343,7 @@ acpi_status acpi_set_register(u32 register_id, u32 value) /* Always do a register read first so we can insert the new bits */ - status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK, - bit_reg_info->parent_register, + status = acpi_hw_register_read(bit_reg_info->parent_register, ®ister_value); if (ACPI_FAILURE(status)) { goto unlock_and_exit; @@ -363,8 +370,7 @@ acpi_status acpi_set_register(u32 register_id, u32 value) bit_reg_info-> access_bit_mask); if (value) { - status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1_STATUS, + status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, (u16) value); register_value = 0; } @@ -377,8 +383,7 @@ acpi_status acpi_set_register(u32 register_id, u32 value) bit_reg_info->access_bit_mask, value); - status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1_ENABLE, + status = acpi_hw_register_write(ACPI_REGISTER_PM1_ENABLE, (u16) register_value); break; @@ -397,15 +402,13 @@ acpi_status acpi_set_register(u32 register_id, u32 value) bit_reg_info->access_bit_mask, value); - status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1_CONTROL, + status = acpi_hw_register_write(ACPI_REGISTER_PM1_CONTROL, (u16) register_value); break; case ACPI_REGISTER_PM2_CONTROL: - status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM2_CONTROL, + status = acpi_hw_register_read(ACPI_REGISTER_PM2_CONTROL, ®ister_value); if (ACPI_FAILURE(status)) { goto unlock_and_exit; @@ -430,8 +433,7 @@ acpi_status acpi_set_register(u32 register_id, u32 value) xpm2_control_block. address))); - status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM2_CONTROL, + status = acpi_hw_register_write(ACPI_REGISTER_PM2_CONTROL, (u8) (register_value)); break; @@ -461,8 +463,7 @@ ACPI_EXPORT_SYMBOL(acpi_set_register) * * FUNCTION: acpi_hw_register_read * - * PARAMETERS: use_lock - Lock hardware? True/False - * register_id - ACPI Register ID + * PARAMETERS: register_id - ACPI Register ID * return_value - Where the register value is returned * * RETURN: Status and the value read. @@ -471,19 +472,14 @@ ACPI_EXPORT_SYMBOL(acpi_set_register) * ******************************************************************************/ acpi_status -acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value) +acpi_hw_register_read(u32 register_id, u32 * return_value) { u32 value1 = 0; u32 value2 = 0; acpi_status status; - acpi_cpu_flags lock_flags = 0; ACPI_FUNCTION_TRACE(hw_register_read); - if (ACPI_MTX_LOCK == use_lock) { - lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); - } - switch (register_id) { case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */ @@ -491,7 +487,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value) acpi_hw_low_level_read(16, &value1, &acpi_gbl_FADT.xpm1a_event_block); if (ACPI_FAILURE(status)) { - goto unlock_and_exit; + goto exit; } /* PM1B is optional */ @@ -507,7 +503,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value) status = acpi_hw_low_level_read(16, &value1, &acpi_gbl_xpm1a_enable); if (ACPI_FAILURE(status)) { - goto unlock_and_exit; + goto exit; } /* PM1B is optional */ @@ -523,7 +519,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value) acpi_hw_low_level_read(16, &value1, &acpi_gbl_FADT.xpm1a_control_block); if (ACPI_FAILURE(status)) { - goto unlock_and_exit; + goto exit; } status = @@ -558,10 +554,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value) break; } - unlock_and_exit: - if (ACPI_MTX_LOCK == use_lock) { - acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); - } + exit: if (ACPI_SUCCESS(status)) { *return_value = value1; @@ -574,8 +567,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value) * * FUNCTION: acpi_hw_register_write * - * PARAMETERS: use_lock - Lock hardware? True/False - * register_id - ACPI Register ID + * PARAMETERS: register_id - ACPI Register ID * Value - The value to write * * RETURN: Status @@ -597,28 +589,22 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value) * ******************************************************************************/ -acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value) +acpi_status acpi_hw_register_write(u32 register_id, u32 value) { acpi_status status; - acpi_cpu_flags lock_flags = 0; u32 read_value; ACPI_FUNCTION_TRACE(hw_register_write); - if (ACPI_MTX_LOCK == use_lock) { - lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); - } - switch (register_id) { case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */ /* Perform a read first to preserve certain bits (per ACPI spec) */ - status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1_STATUS, + status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &read_value); if (ACPI_FAILURE(status)) { - goto unlock_and_exit; + goto exit; } /* Insert the bits to be preserved */ @@ -632,7 +618,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value) acpi_hw_low_level_write(16, value, &acpi_gbl_FADT.xpm1a_event_block); if (ACPI_FAILURE(status)) { - goto unlock_and_exit; + goto exit; } /* PM1B is optional */ @@ -647,7 +633,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value) status = acpi_hw_low_level_write(16, value, &acpi_gbl_xpm1a_enable); if (ACPI_FAILURE(status)) { - goto unlock_and_exit; + goto exit; } /* PM1B is optional */ @@ -661,11 +647,10 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value) /* * Perform a read first to preserve certain bits (per ACPI spec) */ - status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1_CONTROL, + status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, &read_value); if (ACPI_FAILURE(status)) { - goto unlock_and_exit; + goto exit; } /* Insert the bits to be preserved */ @@ -679,7 +664,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value) acpi_hw_low_level_write(16, value, &acpi_gbl_FADT.xpm1a_control_block); if (ACPI_FAILURE(status)) { - goto unlock_and_exit; + goto exit; } status = @@ -728,11 +713,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value) break; } - unlock_and_exit: - if (ACPI_MTX_LOCK == use_lock) { - acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); - } - + exit: return_ACPI_STATUS(status); } diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index cf69c00..4d0c677 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -313,8 +313,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) /* Get current value of PM1A control */ - status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol); + status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -341,15 +340,13 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) /* Write #1: fill in SLP_TYP data */ - status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1A_CONTROL, + status = acpi_hw_register_write(ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } - status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1B_CONTROL, + status = acpi_hw_register_write(ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); @@ -364,15 +361,13 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) ACPI_FLUSH_CPU_CACHE(); - status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1A_CONTROL, + status = acpi_hw_register_write(ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } - status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1B_CONTROL, + status = acpi_hw_register_write(ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); @@ -392,8 +387,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) */ acpi_os_stall(10000000); - status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1_CONTROL, + status = acpi_hw_register_write(ACPI_REGISTER_PM1_CONTROL, sleep_enable_reg_info-> access_bit_mask); if (ACPI_FAILURE(status)) { @@ -520,8 +514,7 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state) /* Get current value of PM1A control */ - status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1_CONTROL, + status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol); if (ACPI_SUCCESS(status)) { @@ -543,11 +536,9 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state) /* Just ignore any errors */ - (void)acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1A_CONTROL, + (void)acpi_hw_register_write(ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol); - (void)acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1B_CONTROL, + (void)acpi_hw_register_write(ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol); } } -- cgit v1.1 From 2d571b33cf7efd6a894e765e3cb45587ec5b834a Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Sun, 30 Sep 2007 22:39:42 +0400 Subject: ACPICA: hw: Don't carry spinlock over suspend ACPI uses acpi_get_register() in order to get into suspend. This function is guarded by acpi_gbl_hardware_lock, which will be carried into resume phase. At resume interrupts are enabled and first ACPI interrupt deadlocks on this lock. Solution seems to be to not lock register read, as there are no concurrent activity at this point. Reference: http://bugzilla.kernel.org/show_bug.cgi?id=7499 Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/hardware/hwsleep.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index 4d0c677..c0577ca 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -398,7 +398,8 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) /* Wait until we enter sleep state */ do { - status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value); + status = acpi_get_register_unlocked(ACPI_BITREG_WAKE_STATUS, + &in_value); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } -- cgit v1.1