Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F109425680
D33897.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D33897.diff
View Options
Index: sys/dev/acpica/acpi_rtc.c
===================================================================
--- /dev/null
+++ sys/dev/acpica/acpi_rtc.c
@@ -0,0 +1,414 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Takanori Watanabe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/clock.h>
+
+#include <contrib/dev/acpica/include/acpi.h>
+
+#include "acpi_if.h"
+#include "clock_if.h"
+#include <sys/module.h>
+#include <dev/acpica/acpivar.h>
+#include <sys/sysctl.h>
+
+#define ACPI_RTC_AC_WAKE 1
+#define ACPI_RTC_DC_WAKE 2
+#define ACPI_RTC_RTC 4
+#define ACPI_RTC_RTC_MSEC 8
+#define ACPI_RTC_GWS 0x10
+#define ACPI_RTC_S4AC 0x20
+#define ACPI_RTC_S5AC 0x40
+#define ACPI_RTC_S4DC 0x80
+#define ACPI_RTC_S5DC 0x100
+#define ACPI_RTC_TZ_UNSPEC 0x7ff
+
+struct acpi_rtc_ct{
+ uint16_t year;
+ uint8_t month;
+ uint8_t day;
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
+ uint8_t valid;
+ uint16_t milisecond;
+ int16_t TimeZone;
+ uint8_t Daylight;
+ uint8_t pad[3];
+}__attribute((__packed__));
+
+static char *acpi_rtc_id[] = {"ACPI000E", NULL};
+struct acpi_rtc_softc {
+ int device_cap;
+ int tzmin;
+};
+static ACPI_STATUS acpi_rtc_grt(device_t dev, struct acpi_rtc_ct *act)
+{
+ ACPI_BUFFER buf;
+ ACPI_STATUS status ;
+ ACPI_OBJECT *ao;
+
+ buf.Length = ACPI_ALLOCATE_BUFFER;
+ buf.Pointer = NULL;
+ status = AcpiEvaluateObject(acpi_get_handle(dev), "_GRT", NULL, &buf);
+ if(ACPI_FAILURE(status)){
+ goto error;
+ }
+
+ ao = buf.Pointer;
+
+ if(ao->Type != ACPI_TYPE_BUFFER){
+ status = AE_ERROR;
+ }else{
+ memcpy(act, ao->Buffer.Pointer, sizeof(*act));
+ }
+
+ AcpiOsFree(buf.Pointer);
+error:
+ return status;
+}
+
+static ACPI_STATUS acpi_rtc_arg1_call(device_t dev, char *name, int arg,
+ int *rv)
+{
+ ACPI_OBJECT ao, reto;
+ ACPI_STATUS status;
+ ACPI_OBJECT_LIST aol;
+ ACPI_BUFFER buf;
+
+ ao.Type = ACPI_TYPE_INTEGER;
+ ao.Integer.Value = arg;
+ aol.Count = 1;
+ aol.Pointer = &ao;
+ buf.Length = sizeof(reto);
+ buf.Pointer = &reto;
+ status = AcpiEvaluateObjectTyped(acpi_get_handle(dev), name,
+ &aol, &buf, ACPI_TYPE_INTEGER);
+
+ *rv = reto.Integer.Value;
+
+ return status;
+}
+
+static ACPI_STATUS acpi_rtc_arg2_call(device_t dev, char *name, int arg1,
+ int arg2, int *rv)
+{
+ ACPI_OBJECT ao[2], reto;
+ ACPI_STATUS status;
+ ACPI_OBJECT_LIST aol;
+ ACPI_BUFFER buf;
+
+ ao[0].Type = ACPI_TYPE_INTEGER;
+ ao[0].Integer.Value = arg1;
+ ao[1].Type = ACPI_TYPE_INTEGER;
+ ao[1].Integer.Value = arg2;
+ aol.Count = 2;
+ aol.Pointer = ao;
+ buf.Length = sizeof(reto);
+ buf.Pointer = &reto;
+ status = AcpiEvaluateObjectTyped(acpi_get_handle(dev), name,
+ &aol, &buf, ACPI_TYPE_INTEGER);
+
+ *rv = reto.Integer.Value;
+
+ return status;
+}
+
+static int acpi_rtc_gettime(device_t dev, struct timespec *ts)
+{
+ struct clocktime ct;
+ struct acpi_rtc_ct grt;
+ int rv;
+ if (ACPI_FAILURE(acpi_rtc_grt(dev, &grt)))
+ return EINVAL;
+
+ if (grt.valid == 0) {
+ return EINVAL;
+ }
+
+ ct.year = grt.year;
+ ct.mon = grt.month;
+ ct.day = grt.day;
+ ct.hour = grt.hour;
+ ct.min = grt.minute;
+ ct.sec = grt.second;
+ ct.dow = 0; /* ignored.*/
+ ct.nsec = grt.milisecond * 1000 * 1000;
+
+ rv = clock_ct_to_ts(&ct, ts);
+ if (rv != 0)
+ return rv;
+
+ /* Return UTC time when TZ is set.*/
+ if (grt.TimeZone != ACPI_RTC_TZ_UNSPEC)
+ ts->tv_sec += grt.TimeZone * 60;
+
+ return 0;
+}
+
+static int acpi_rtc_settime(device_t dev, struct timespec *ts)
+{
+ struct acpi_rtc_ct srt;
+ struct clocktime ct;
+ ACPI_OBJECT ao, reto;
+ ACPI_STATUS status;
+ ACPI_OBJECT_LIST aol;
+ ACPI_BUFFER buf;
+
+ struct acpi_rtc_softc *sc = device_get_softc(dev);
+
+ memset(&srt, 0, sizeof(srt));
+
+ /* Set Local time when TZ is set.*/
+ if ( sc->tzmin != ACPI_RTC_TZ_UNSPEC )
+ ts->tv_sec -= sc->tzmin * 60;
+
+ clock_ts_to_ct(ts, &ct);
+ srt.year = ct.year;
+ srt.month = ct.mon;
+ srt.day = ct.day;
+ srt.hour = ct.hour;
+ srt.minute = ct.min;
+ srt.second = ct.sec;
+ srt.milisecond = ct.nsec / 1000 / 1000 ;
+ srt.TimeZone = 0x7ff;
+ srt.Daylight = 0;
+
+ ao.Type = ACPI_TYPE_BUFFER;
+ ao.Buffer.Length = sizeof(srt);
+ ao.Buffer.Pointer = (void*)&srt;
+ aol.Count = 1;
+ aol.Pointer = &ao;
+ buf.Length = sizeof(reto);
+ buf.Pointer = &reto;
+ status = AcpiEvaluateObjectTyped(acpi_get_handle(dev), "_SRT",
+ &aol, &buf, ACPI_TYPE_INTEGER);
+
+ if (ACPI_FAILURE(status)){
+ return (EINVAL);
+ }
+
+ if(reto.Integer.Value != 0){
+ return (EINVAL);
+ }
+
+ return (0);
+}
+static void acpi_rtc_notify_handler(ACPI_HANDLE h, UINT32 notify, void *ctx)
+{
+#if 0
+ device_t dev = (device_t) ctx;
+ device_printf(dev, "Notify %d\n");
+#endif
+ acpi_UserNotify("RTCWAKE", h, notify);
+}
+
+static int acpi_rtc_probe(device_t dev)
+{
+ int ret;
+
+ ret = ACPI_ID_PROBE(device_get_parent(dev), dev, acpi_rtc_id, NULL);
+ if (ret <= 0) {
+ device_set_desc(dev, "Date and Alarm Device");
+ }
+
+ return (ret);
+}
+static int acpi_rtc_wakestate(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev ;
+ int arg, val;
+ ACPI_STATUS status;
+ int error;
+
+ dev = (device_t) oidp->oid_arg1;
+ arg = oidp->oid_arg2;
+
+ if (ACPI_FAILURE(acpi_rtc_arg1_call(dev, "_GWS", arg, &val)))
+ return EINVAL;
+ error = sysctl_handle_int(oidp, &val, 0,req);
+ if ( error || ! req->newptr)
+ return error;
+
+ status = acpi_rtc_arg1_call(dev, "_CWS", arg, &val);
+ if(ACPI_FAILURE(status) || (val != 0))
+ return EINVAL;
+
+ return 0;
+}
+static int acpi_rtc_timer(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev ;
+ int arg, val;
+ ACPI_STATUS status;
+ int error;
+
+ dev = (device_t) oidp->oid_arg1;
+ arg = oidp->oid_arg2;
+
+ if (ACPI_FAILURE(acpi_rtc_arg1_call(dev, "_TIV", arg, &val)))
+ return EINVAL;
+ error = sysctl_handle_int(oidp, &val, 0,req);
+ if ( error || ! req->newptr)
+ return error;
+
+ status = acpi_rtc_arg2_call(dev, "_STV", arg, val, &val);
+
+ if(ACPI_FAILURE(status) || (val != 0))
+ return EINVAL;
+
+ return 0;
+}
+static int acpi_rtc_policy(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev ;
+ int arg, val;
+ ACPI_STATUS status;
+ int error;
+
+ dev = (device_t) oidp->oid_arg1;
+ arg = oidp->oid_arg2;
+
+ if (ACPI_FAILURE(acpi_rtc_arg1_call(dev, "_TIP", arg, &val)))
+ return EINVAL;
+ error = sysctl_handle_int(oidp, &val, 0,req);
+ if ( error || ! req->newptr)
+ return error;
+
+ status = acpi_rtc_arg2_call(dev, "_STP", arg, val, &val);
+
+ if(ACPI_FAILURE(status) || (val != 0))
+ return EINVAL;
+
+ return 0;
+}
+static int acpi_rtc_attach(device_t dev)
+{
+ struct acpi_rtc_softc *sc = device_get_softc(dev);
+ struct acpi_rtc_ct act;
+ struct sysctl_ctx_list *sysctl_ctx = device_get_sysctl_ctx(dev);
+ struct sysctl_oid *sysctl_tree = device_get_sysctl_tree(dev);
+
+ if(ACPI_FAILURE(acpi_GetInteger(acpi_get_handle(dev), "_GCP", &sc->device_cap))){
+ return ENXIO;
+ }
+
+ device_printf(dev, "Capacity %b\n", sc->device_cap, "\020\1AC\2DC\3RTC\4mS\5GWSS45\6S4AC\7S5AC\010S4DC\011S5DC");
+ if(sc->device_cap & ACPI_RTC_RTC){
+ acpi_rtc_grt(dev, &act);
+
+ sc->tzmin = act.TimeZone;
+ if(act.Daylight)
+ device_printf (dev, "Warning: Daylight time affect the value\n");
+
+ clock_register_flags(dev,
+ (sc->device_cap & ACPI_RTC_RTC_MSEC) ? 1000 : 1000000,
+ (sc->tzmin == ACPI_RTC_TZ_UNSPEC) ? 0 :
+ (CLOCKF_GETTIME_NO_ADJ | CLOCKF_SETTIME_NO_ADJ));
+
+ }
+ AcpiInstallNotifyHandler(acpi_get_handle(dev),
+ ACPI_ALL_NOTIFY,
+ acpi_rtc_notify_handler, dev);
+
+ acpi_wake_set_enable(dev, 1);
+ SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "ac_wake_status",
+ CTLTYPE_INT | CTLFLAG_RW |CTLFLAG_MPSAFE,
+ dev, 0, acpi_rtc_wakestate, "I",
+ "AC Wake status. write any value to clear");
+
+ SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "dc_wake_status",
+ CTLTYPE_INT | CTLFLAG_RW |CTLFLAG_MPSAFE,
+ dev, 1, acpi_rtc_wakestate, "I",
+ "DC Wake status. write any value to clear");
+
+ SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "ac_wake_timer",
+ CTLTYPE_INT | CTLFLAG_RW |CTLFLAG_MPSAFE,
+ dev, 0, acpi_rtc_timer, "I",
+ "AC Wake count down timer in second. -1 means timer expired");
+
+ SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "dc_wake_timer",
+ CTLTYPE_INT | CTLFLAG_RW |CTLFLAG_MPSAFE,
+ dev, 1, acpi_rtc_timer, "I",
+ "DC Wake count down timer in second. -1 means timer expired.");
+
+ SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "ac_wake_policy",
+ CTLTYPE_INT | CTLFLAG_RW |CTLFLAG_MPSAFE,
+ dev, 0, acpi_rtc_policy, "I",
+ "AC Wake policy");
+
+ SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "dc_wake_policy",
+ CTLTYPE_INT | CTLFLAG_RW |CTLFLAG_MPSAFE,
+ dev, 1, acpi_rtc_policy, "I",
+ "DC Wake policy");
+
+ return 0;
+}
+
+static int acpi_rtc_detach(device_t dev)
+{
+ AcpiRemoveNotifyHandler(acpi_get_handle(dev),
+ ACPI_ALL_NOTIFY,
+ acpi_rtc_notify_handler);
+ return 0;
+}
+
+static device_method_t acpi_rtc_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, acpi_rtc_probe),
+ DEVMETHOD(device_attach, acpi_rtc_attach),
+ DEVMETHOD(device_detach, acpi_rtc_detach),
+
+ DEVMETHOD(clock_gettime, acpi_rtc_gettime),
+ DEVMETHOD(clock_settime, acpi_rtc_settime),
+
+ DEVMETHOD_END
+};
+
+static driver_t acpi_rtc_driver = {
+ "acpi_rtc",
+ acpi_rtc_methods,
+ sizeof(struct acpi_rtc_softc),
+};
+devclass_t acpi_rtc_devclass;
+
+DRIVER_MODULE(acpi_rtc, acpi, acpi_rtc_driver, acpi_rtc_devclass, 0, 0);
+MODULE_DEPEND(acpi_rtc, acpi, 1, 1, 1);
Index: sys/modules/acpi/acpi_rtc/Makefile
===================================================================
--- /dev/null
+++ sys/modules/acpi/acpi_rtc/Makefile
@@ -0,0 +1,6 @@
+.PATH: ${SRCTOP}/sys/dev/acpica
+
+KMOD= acpi_rtc
+SRCS= acpi_rtc.c opt_acpi.h acpi_if.h acpi_wmi_if.h device_if.h bus_if.h clock_if.h
+
+.include <bsd.kmod.mk>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Feb 5, 9:58 PM (20 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16481559
Default Alt Text
D33897.diff (11 KB)
Attached To
Mode
D33897: Add ACPI Alarm and Day Time Driver.
Attached
Detach File
Event Timeline
Log In to Comment