Page MenuHomeFreeBSD

D33897.diff
No OneTemporary

D33897.diff

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

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)

Event Timeline