summaryrefslogtreecommitdiff
path: root/sys/dev/clockctl.c
diff options
context:
space:
mode:
authorpgoyette <pgoyette@NetBSD.org>2015-12-07 03:25:57 +0000
committerpgoyette <pgoyette@NetBSD.org>2015-12-07 03:25:57 +0000
commitedf0b3446a599a7c13dc35601a62ee2e6de22996 (patch)
tree9b55af70cdb2215e4c18b77c41795cff585ebbfd /sys/dev/clockctl.c
parenta30736a20f4afa2515329a601f5bbf2924497c11 (diff)
Modularize the clockctl pseudo-device and link to the build.
Diffstat (limited to 'sys/dev/clockctl.c')
-rw-r--r--sys/dev/clockctl.c181
1 files changed, 177 insertions, 4 deletions
diff --git a/sys/dev/clockctl.c b/sys/dev/clockctl.c
index 169bd335f24..09417fcb190 100644
--- a/sys/dev/clockctl.c
+++ b/sys/dev/clockctl.c
@@ -1,4 +1,4 @@
-/* $NetBSD: clockctl.c,v 1.32 2014/07/25 08:10:35 dholland Exp $ */
+/* $NetBSD: clockctl.c,v 1.33 2015/12/07 03:25:57 pgoyette Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -31,10 +31,12 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: clockctl.c,v 1.32 2014/07/25 08:10:35 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: clockctl.c,v 1.33 2015/12/07 03:25:57 pgoyette Exp $");
+#ifdef _KERNEL_OPT
#include "opt_ntp.h"
#include "opt_compat_netbsd.h"
+#endif
#include <sys/param.h>
#include <sys/systm.h>
@@ -48,17 +50,28 @@ __KERNEL_RCSID(0, "$NetBSD: clockctl.c,v 1.32 2014/07/25 08:10:35 dholland Exp $
#include <sys/timex.h>
#endif /* NTP */
#include <sys/kauth.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/once.h>
#include <sys/clockctl.h>
#ifdef COMPAT_50
#include <compat/sys/clockctl.h>
+#include <compat/sys/time_types.h>
#endif
+kmutex_t clockctl_mtx;
+int clockctl_refcnt;
+
+ONCE_DECL(clockctl_once);
+
+#include "ioconf.h"
+
dev_type_ioctl(clockctlioctl);
const struct cdevsw clockctl_cdevsw = {
- .d_open = nullopen,
- .d_close = nullclose,
+ .d_open = clockctlopen,
+ .d_close = clockctlclose,
.d_read = noread,
.d_write = nowrite,
.d_ioctl = clockctlioctl,
@@ -102,8 +115,102 @@ void
clockctlattach(int num)
{
+/*
+ * Don't initialize the listener here - it will get handled as part
+ * of module initialization.
+ */
+#if 0
clockctl_listener = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
clockctl_listener_cb, NULL);
+#endif
+}
+
+/*
+ * Maintain a refcount for each open/close, so we know when it is
+ * safe to call devsw_detach()
+ */
+int
+clockctlopen(dev_t dev, int flag, int mode, struct lwp *l)
+{
+
+ mutex_enter(&clockctl_mtx);
+ clockctl_refcnt++;
+ mutex_exit(&clockctl_mtx);
+
+ return 0;
+}
+
+int
+clockctlclose(dev_t dev, int flag, int mode, struct lwp *l)
+{
+
+ mutex_enter(&clockctl_mtx);
+ clockctl_refcnt--;
+ mutex_exit(&clockctl_mtx);
+
+ return 0;
+}
+
+int
+clockctl_init(void)
+{
+
+ mutex_init(&clockctl_mtx, MUTEX_DEFAULT, IPL_NONE);
+ clockctl_refcnt = 0;
+ return 0;
+}
+
+MODULE(MODULE_CLASS_DRIVER, clockctl, NULL);
+
+int
+clockctl_modcmd(modcmd_t cmd, void *data)
+{
+ int error;
+#ifdef _MODULE
+ int bmajor, cmajor;
+#endif
+
+ error = 0;
+
+ switch (cmd) {
+ case MODULE_CMD_INIT:
+ RUN_ONCE(&clockctl_once, clockctl_init);
+
+ clockctl_listener = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
+ clockctl_listener_cb, NULL);
+
+#ifdef _MODULE
+ bmajor = cmajor = -1;
+ error = devsw_attach("clockctl", NULL, &bmajor,
+ &clockctl_cdevsw, &cmajor);
+ if (error != 0)
+ kauth_unlisten_scope(clockctl_listener);
+#endif
+
+ break;
+
+ case MODULE_CMD_FINI:
+ mutex_enter(&clockctl_mtx);
+ if (clockctl_refcnt != 0) {
+ mutex_exit(&clockctl_mtx);
+ return EBUSY;
+ }
+#ifdef _MODULE
+ error = devsw_detach(NULL, &clockctl_cdevsw);
+#endif
+ mutex_exit(&clockctl_mtx);
+
+ if (error == 0)
+ kauth_unlisten_scope(clockctl_listener);
+
+ break;
+
+ default:
+ error = ENOTTY;
+ break;
+ }
+
+ return error;
}
int
@@ -177,4 +284,70 @@ clockctlioctl(
return (error);
}
+#ifdef COMPAT_50
+int
+compat50_clockctlioctl(dev_t dev, u_long cmd, void *data, int flags,
+ struct lwp *l)
+{
+ int error = 0;
+ const struct cdevsw *cd = cdevsw_lookup(dev);
+
+ if (cd == NULL || cd->d_ioctl == NULL)
+ return ENXIO;
+
+ switch (cmd) {
+ case CLOCKCTL_OSETTIMEOFDAY: {
+ struct timeval50 tv50;
+ struct timeval tv;
+ struct clockctl50_settimeofday *args = data;
+ error = copyin(args->tv, &tv50, sizeof(tv50));
+ if (error)
+ return (error);
+ timeval50_to_timeval(&tv50, &tv);
+ error = settimeofday1(&tv, false, args->tzp, l, false);
+ break;
+ }
+ case CLOCKCTL_OADJTIME: {
+ struct timeval atv, oldatv;
+ struct timeval50 atv50;
+ struct clockctl50_adjtime *args = data;
+
+ if (args->delta) {
+ error = copyin(args->delta, &atv50, sizeof(atv50));
+ if (error)
+ return (error);
+ timeval50_to_timeval(&atv50, &atv);
+ }
+ adjtime1(args->delta ? &atv : NULL,
+ args->olddelta ? &oldatv : NULL, l->l_proc);
+ if (args->olddelta) {
+ timeval_to_timeval50(&oldatv, &atv50);
+ error = copyout(&atv50, args->olddelta, sizeof(atv50));
+ }
+ break;
+ }
+ case CLOCKCTL_OCLOCK_SETTIME: {
+ struct timespec50 tp50;
+ struct timespec tp;
+ struct clockctl50_clock_settime *args = data;
+
+ error = copyin(args->tp, &tp50, sizeof(tp50));
+ if (error)
+ return (error);
+ timespec50_to_timespec(&tp50, &tp);
+ error = clock_settime1(l->l_proc, args->clock_id, &tp, true);
+ break;
+ }
+ case CLOCKCTL_ONTP_ADJTIME:
+ /* The ioctl number changed but the data did not change. */
+ error = (cd->d_ioctl)(dev, CLOCKCTL_NTP_ADJTIME,
+ data, flags, l);
+ break;
+ default:
+ error = EINVAL;
+ }
+
+ return (error);
+}
+#endif