linux-acpi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Alex Hung <alex.hung@canonical.com>
To: alex.hung@canonical.com, lenb@kernel.org, rjw@sisk.pl,
	linux-acpi@vger.kernel.org, robert.moore@intel.com,
	lv.zheng@intel.com
Subject: [PATCH] ACPI: add a dummy ACPI RTC driver to handle BIOS AML's  accesses  to registers delcared in CMOS OperationRegion v2.
Date: Mon, 28 Jan 2013 09:56:42 +0800	[thread overview]
Message-ID: <1359338202-4942-1-git-send-email-alex.hung@canonical.com> (raw)

This is to fix acpica returns an error and terminate when BIOS ASL
tries to access ACPI's RTC CMOS registers as the below example:

Device (RTC)
{
	Name (_HID, EisaId ("PNP0B00"))
	...
	OperationRegion (CMS0, SystemCMOS, Zero, 0x40)
	Field (CMS0, ByteAcc, NoLock, Preserve)
	{
		RTSE,   8,
			Offset (0x02),
		RTMN,   8,
			Offset (0x04),
		RTHR,   8,
			Offset (0x06),
		RTDY,   8,
		RTDE,   8
	}
}

Method (_Q33, 0, NotSerialized)
{
	Store (^^RTC.RTMN, Local0)
	FromBCD (Local0, Local0)
	Store (^^RTC.RTHR, Local1)
	FromBCD (Local1, Local1)
	Store (^^RTC.RTDY, Local2)
	Store (^^RTC.RTSE, Local3)
	...
}

Signed-off-by: Alex Hung <alex.hung@canonical.com>
---
 drivers/acpi/Kconfig    |    9 +++
 drivers/acpi/Makefile   |    1 +
 drivers/acpi/acpi_rtc.c |  149 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 159 insertions(+)
 create mode 100644 drivers/acpi/acpi_rtc.c

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 38c5078..fb90397 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -181,6 +181,15 @@ config ACPI_DOCK
 	  This driver supports ACPI-controlled docking stations and removable
 	  drive bays such as the IBM Ultrabay and the Dell Module Bay.
 
+config ACPI_RTC
+	tristate "RTC"
+	default m
+	help
+	  This driver supports an ACPI RTC device. It enables BIOS to read and
+	  to write ACPI RTC registers declared in an OperationRegion with
+	  RegionSpace as SYSTEMCMOS. This is required if BIOS needs to access
+	  RTC registers during run-time such as a number of HP laptops.
+
 config ACPI_I2C
 	def_tristate I2C
 	depends on I2C
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 2a4502b..383c62b 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS)	+= ec_sys.o
 obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
 obj-$(CONFIG_ACPI_BGRT)		+= bgrt.o
 obj-$(CONFIG_ACPI_I2C)		+= acpi_i2c.o
+obj-$(CONFIG_ACPI_RTC)          += acpi_rtc.o
 
 # processor has its own "processor." module_param namespace
 processor-y			:= processor_driver.o processor_throttling.o
diff --git a/drivers/acpi/acpi_rtc.c b/drivers/acpi/acpi_rtc.c
new file mode 100644
index 0000000..8d6b76b
--- /dev/null
+++ b/drivers/acpi/acpi_rtc.c
@@ -0,0 +1,149 @@
+/*
+ *  acpi_rtc - ACPI RTC Driver
+ *
+ *  Copyright (C) 2013 Alex Hung <alex.hung@canonical.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  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; either version 2 of the License, or (at
+ *  your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("acpi*:PNP0B00:*");
+MODULE_ALIAS("acpi*:PNP0B01:*");
+MODULE_ALIAS("acpi*:PNP0B02:*");
+
+static const struct acpi_device_id rtc_device_ids[] = {
+	{"PNP0B00", 0},
+	{"PNP0B01", 0},
+	{"PNP0B02", 0},
+	{"", 0},
+};
+
+static acpi_status acpi_acpi_handle_locate_callback(acpi_handle handle,
+			u32 level, void *context, void **return_value)
+{
+	struct acpi_device *dev = context;
+
+	dev->handle = handle;
+	*(acpi_handle *)return_value = handle;
+
+	return AE_CTRL_TERMINATE;
+}
+
+static acpi_status
+acpi_rtc_space_handler(u32 function, acpi_physical_address address,
+		      u32 bits, u64 *value64,
+		      void *handler_context, void *region_context)
+{
+	pr_warn("Accessing CMOS offset 0x%02llx is skipped.\n", address);
+
+	return AE_OK;
+}
+
+static int rtc_install_handlers(struct acpi_device *rtc_dev)
+{
+	acpi_status status;
+	status = acpi_install_address_space_handler(rtc_dev->handle,
+						    ACPI_ADR_SPACE_CMOS,
+						    &acpi_rtc_space_handler,
+						    NULL, rtc_dev);
+	if (ACPI_FAILURE(status)) {
+		pr_info("Fail to install ACPI RTC handler\n");
+		return AE_ERROR;
+	}
+
+	return 0;
+}
+
+static int acpi_rtc_add(struct acpi_device *device)
+{
+	int ret;
+	int i;
+	acpi_status status;
+	acpi_handle rtc_dev = NULL;
+
+	for (i = 0; i < sizeof(rtc_device_ids) /
+			sizeof(struct acpi_device_id) - 1; i++) {
+		status = acpi_get_devices(rtc_device_ids[i].id,
+				  acpi_acpi_handle_locate_callback,
+				  &rtc_dev, &rtc_dev);
+		if (ACPI_SUCCESS(status) && rtc_dev)
+				break;
+	}
+
+	if (!ACPI_SUCCESS(status) || !rtc_dev)
+		return AE_NOT_FOUND;
+
+	ret = rtc_install_handlers((struct acpi_device *) &rtc_dev);
+
+	return ret;
+}
+
+static int acpi_rtc_remove(struct acpi_device *device, int type)
+{
+	acpi_status status;
+	status = acpi_remove_address_space_handler(device->handle,
+						   ACPI_ADR_SPACE_CMOS,
+						   &acpi_rtc_space_handler);
+	if (!ACPI_SUCCESS(status))
+		return AE_ERROR;
+
+	return AE_OK;
+}
+
+static struct acpi_driver acpi_rtc_driver = {
+	.name = "rtc",
+	.class = "ACPI_RTC_CLASS",
+	.ids = rtc_device_ids,
+	.ops = {
+		.add = acpi_rtc_add,
+		.remove = acpi_rtc_remove,
+		},
+};
+
+static int __init rtc_init(void)
+{
+	int err;
+
+	pr_info("Initializing ACPI RTC module\n");
+	err = acpi_bus_register_driver(&acpi_rtc_driver);
+	if (err) {
+		pr_err("Unable to register acpi driver.\n");
+		goto error_acpi_register;
+	}
+
+	return 0;
+
+error_acpi_register:
+
+	return err;
+}
+
+static void __exit rtc_exit(void)
+{
+	pr_info("Exiting ACPI RTC module\n");
+	acpi_bus_unregister_driver(&acpi_rtc_driver);
+}
+
+module_init(rtc_init);
+module_exit(rtc_exit);
-- 
1.7.9.5


             reply	other threads:[~2013-01-28  1:56 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-01-28  1:56 Alex Hung [this message]
2013-04-22  9:28 ` [PATCH] ACPI: add a dummy ACPI RTC driver to handle BIOS AML's accesses to registers delcared in CMOS OperationRegion v2 Alex Hung
2013-04-22 11:53   ` Rafael J. Wysocki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1359338202-4942-1-git-send-email-alex.hung@canonical.com \
    --to=alex.hung@canonical.com \
    --cc=lenb@kernel.org \
    --cc=linux-acpi@vger.kernel.org \
    --cc=lv.zheng@intel.com \
    --cc=rjw@sisk.pl \
    --cc=robert.moore@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).