9389f46e97
The value64 parameter is an u64 point that used to transfer the value for write to CMOS, or used to return the value that's read from CMOS. The value64 is an u64 point, so don't need get address again. It causes acpi_cmos_rtc_space_handler always return 0 to reader and didn't write expected value to CMOS. Signed-off-by: Lee, Chun-Yi <jlee@suse.com> Cc: 3.11+ <stable@vger.kernel.org> # 3.11+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
91 lines
2.1 KiB
C
91 lines
2.1 KiB
C
/*
|
|
* ACPI support for CMOS RTC Address Space access
|
|
*
|
|
* Copyright (C) 2013, Intel Corporation
|
|
* Authors: Lan Tianyu <tianyu.lan@intel.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
#include <linux/acpi.h>
|
|
#include <linux/device.h>
|
|
#include <linux/err.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <asm-generic/rtc.h>
|
|
|
|
#include "internal.h"
|
|
|
|
ACPI_MODULE_NAME("cmos rtc");
|
|
|
|
static const struct acpi_device_id acpi_cmos_rtc_ids[] = {
|
|
{ "PNP0B00" },
|
|
{ "PNP0B01" },
|
|
{ "PNP0B02" },
|
|
{}
|
|
};
|
|
|
|
static acpi_status
|
|
acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address,
|
|
u32 bits, u64 *value64,
|
|
void *handler_context, void *region_context)
|
|
{
|
|
int i;
|
|
u8 *value = (u8 *)value64;
|
|
|
|
if (address > 0xff || !value64)
|
|
return AE_BAD_PARAMETER;
|
|
|
|
if (function != ACPI_WRITE && function != ACPI_READ)
|
|
return AE_BAD_PARAMETER;
|
|
|
|
spin_lock_irq(&rtc_lock);
|
|
|
|
for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value)
|
|
if (function == ACPI_READ)
|
|
*value = CMOS_READ(address);
|
|
else
|
|
CMOS_WRITE(*value, address);
|
|
|
|
spin_unlock_irq(&rtc_lock);
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev,
|
|
const struct acpi_device_id *id)
|
|
{
|
|
acpi_status status;
|
|
|
|
status = acpi_install_address_space_handler(adev->handle,
|
|
ACPI_ADR_SPACE_CMOS,
|
|
&acpi_cmos_rtc_space_handler,
|
|
NULL, NULL);
|
|
if (ACPI_FAILURE(status)) {
|
|
pr_err(PREFIX "Error installing CMOS-RTC region handler\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void acpi_remove_cmos_rtc_space_handler(struct acpi_device *adev)
|
|
{
|
|
if (ACPI_FAILURE(acpi_remove_address_space_handler(adev->handle,
|
|
ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler)))
|
|
pr_err(PREFIX "Error removing CMOS-RTC region handler\n");
|
|
}
|
|
|
|
static struct acpi_scan_handler cmos_rtc_handler = {
|
|
.ids = acpi_cmos_rtc_ids,
|
|
.attach = acpi_install_cmos_rtc_space_handler,
|
|
.detach = acpi_remove_cmos_rtc_space_handler,
|
|
};
|
|
|
|
void __init acpi_cmos_rtc_init(void)
|
|
{
|
|
acpi_scan_add_handler(&cmos_rtc_handler);
|
|
}
|