0001
0002
0003
0004
0005
0006
0007
0008
0009 #define pr_fmt(fmt) "ACPI: " fmt
0010
0011 #include <linux/acpi.h>
0012 #include <linux/device.h>
0013 #include <linux/err.h>
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/mc146818rtc.h>
0017
0018 #include "internal.h"
0019
0020 static const struct acpi_device_id acpi_cmos_rtc_ids[] = {
0021 { "PNP0B00" },
0022 { "PNP0B01" },
0023 { "PNP0B02" },
0024 {}
0025 };
0026
0027 static acpi_status
0028 acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address,
0029 u32 bits, u64 *value64,
0030 void *handler_context, void *region_context)
0031 {
0032 int i;
0033 u8 *value = (u8 *)value64;
0034
0035 if (address > 0xff || !value64)
0036 return AE_BAD_PARAMETER;
0037
0038 if (function != ACPI_WRITE && function != ACPI_READ)
0039 return AE_BAD_PARAMETER;
0040
0041 spin_lock_irq(&rtc_lock);
0042
0043 for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value)
0044 if (function == ACPI_READ)
0045 *value = CMOS_READ(address);
0046 else
0047 CMOS_WRITE(*value, address);
0048
0049 spin_unlock_irq(&rtc_lock);
0050
0051 return AE_OK;
0052 }
0053
0054 static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev,
0055 const struct acpi_device_id *id)
0056 {
0057 acpi_status status;
0058
0059 status = acpi_install_address_space_handler(adev->handle,
0060 ACPI_ADR_SPACE_CMOS,
0061 &acpi_cmos_rtc_space_handler,
0062 NULL, NULL);
0063 if (ACPI_FAILURE(status)) {
0064 pr_err("Error installing CMOS-RTC region handler\n");
0065 return -ENODEV;
0066 }
0067
0068 return 1;
0069 }
0070
0071 static void acpi_remove_cmos_rtc_space_handler(struct acpi_device *adev)
0072 {
0073 if (ACPI_FAILURE(acpi_remove_address_space_handler(adev->handle,
0074 ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler)))
0075 pr_err("Error removing CMOS-RTC region handler\n");
0076 }
0077
0078 static struct acpi_scan_handler cmos_rtc_handler = {
0079 .ids = acpi_cmos_rtc_ids,
0080 .attach = acpi_install_cmos_rtc_space_handler,
0081 .detach = acpi_remove_cmos_rtc_space_handler,
0082 };
0083
0084 void __init acpi_cmos_rtc_init(void)
0085 {
0086 acpi_scan_add_handler(&cmos_rtc_handler);
0087 }