subr_rtc.c (99ab8292c750e68a8b8f72229067a718d56b9a5a) subr_rtc.c (b69f71eb29797c1a8175e6db41d45e6b2b08b2b5)
1/*-
2 * Copyright (c) 1988 University of Utah.
3 * Copyright (c) 1982, 1990, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * the Systems Programming Group of the University of Utah Computer
8 * Science Department.

--- 33 unchanged lines hidden (view full) ---

42 * Helpers for time-of-day clocks. This is useful for architectures that need
43 * support multiple models of such clocks, and generally serves to make the
44 * code more machine-independent.
45 * If the clock in question can also be used as a time counter, the driver
46 * needs to initiate this.
47 * This code is not yet used by all architectures.
48 */
49
1/*-
2 * Copyright (c) 1988 University of Utah.
3 * Copyright (c) 1982, 1990, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * the Systems Programming Group of the University of Utah Computer
8 * Science Department.

--- 33 unchanged lines hidden (view full) ---

42 * Helpers for time-of-day clocks. This is useful for architectures that need
43 * support multiple models of such clocks, and generally serves to make the
44 * code more machine-independent.
45 * If the clock in question can also be used as a time counter, the driver
46 * needs to initiate this.
47 * This code is not yet used by all architectures.
48 */
49
50/*
51 * Generic routines to convert between a POSIX date
52 * (seconds since 1/1/1970) and yr/mo/day/hr/min/sec
53 * Derived from NetBSD arch/hp300/hp300/clock.c
54 */
55
56#include <sys/cdefs.h>
57__FBSDID("$FreeBSD$");
58
59#include <sys/param.h>
60#include <sys/systm.h>
61#include <sys/kernel.h>
62#include <sys/bus.h>
63#include <sys/clock.h>
64#include <sys/sysctl.h>
65#include <sys/timetc.h>
66
67/* XXX: for the CPU_* sysctl OID constants. */
68#include <machine/cpu.h>
69
70#include "clock_if.h"
71
50#include <sys/cdefs.h>
51__FBSDID("$FreeBSD$");
52
53#include <sys/param.h>
54#include <sys/systm.h>
55#include <sys/kernel.h>
56#include <sys/bus.h>
57#include <sys/clock.h>
58#include <sys/sysctl.h>
59#include <sys/timetc.h>
60
61/* XXX: for the CPU_* sysctl OID constants. */
62#include <machine/cpu.h>
63
64#include "clock_if.h"
65
72static __inline int leapyear(int year);
73static int sysctl_machdep_adjkerntz(SYSCTL_HANDLER_ARGS);
74
75#define FEBRUARY 2
76#define days_in_year(y) (leapyear(y) ? 366 : 365)
77#define days_in_month(y, m) \
78 (month_days[(m) - 1] + (m == FEBRUARY ? leapyear(y) : 0))
79/* Day of week. Days are counted from 1/1/1970, which was a Thursday */
80#define day_of_week(days) (((days) + 4) % 7)
81
82static const int month_days[12] = {
83 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
84};
85
86static device_t clock_dev = NULL;
87static long clock_res;
88
66static device_t clock_dev = NULL;
67static long clock_res;
68
89int adjkerntz; /* local offset from GMT in seconds */
90int disable_rtc_set; /* disable resettodr() if != 0 */
91int wall_cmos_clock; /* wall CMOS clock assumed if != 0 */
92
93/*
94 * These have traditionally been in machdep, but should probably be moved to
95 * kern.
96 */
97SYSCTL_PROC(_machdep, OID_AUTO, adjkerntz, CTLTYPE_INT|CTLFLAG_RW,
98 &adjkerntz, 0, sysctl_machdep_adjkerntz, "I", "");
99
100SYSCTL_INT(_machdep, OID_AUTO, disable_rtc_set,
101 CTLFLAG_RW, &disable_rtc_set, 0, "");
102
103SYSCTL_INT(_machdep, OID_AUTO, wall_cmos_clock,
104 CTLFLAG_RW, &wall_cmos_clock, 0, "");
105
106static int
107sysctl_machdep_adjkerntz(SYSCTL_HANDLER_ARGS)
108{
109 int error;
110 error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2,
111 req);
112 if (!error && req->newptr)
113 resettodr();
114 return (error);
115}
116
117/*
118 * This inline avoids some unnecessary modulo operations
119 * as compared with the usual macro:
120 * ( ((year % 4) == 0 &&
121 * (year % 100) != 0) ||
122 * ((year % 400) == 0) )
123 * It is otherwise equivalent.
124 */
125static __inline int
126leapyear(int year)
127{
128 int rv = 0;
129
130 if ((year & 3) == 0) {
131 rv = 1;
132 if ((year % 100) == 0) {
133 rv = 0;
134 if ((year % 400) == 0)
135 rv = 1;
136 }
137 }
138 return (rv);
139}
140
141int
142clock_ct_to_ts(struct clocktime *ct, struct timespec *ts)
143{
144 time_t secs;
145 int i, year, days;
146
147 year = ct->year;
148
149 /* Sanity checks. */
150 if (ct->mon < 1 || ct->mon > 12 || ct->day < 1 ||
151 ct->day > days_in_month(year, ct->mon) ||
152 ct->hour > 23 || ct->min > 59 || ct->sec > 59 ||
153 ct->year > 2037) /* time_t overflow */
154 return (EINVAL);
155
156 /*
157 * Compute days since start of time
158 * First from years, then from months.
159 */
160 days = 0;
161 for (i = POSIX_BASE_YEAR; i < year; i++)
162 days += days_in_year(i);
163
164 /* Months */
165 for (i = 1; i < ct->mon; i++)
166 days += days_in_month(year, i);
167 days += (ct->day - 1);
168
169 /* Another sanity check. */
170 if (ct->dow != -1 && ct->dow != day_of_week(days))
171 return (EINVAL);
172
173 /* Add hours, minutes, seconds. */
174 secs = ((days * 24 + ct->hour) * 60 + ct->min) * 60 + ct->sec;
175
176 ts->tv_sec = secs;
177 ts->tv_nsec = ct->nsec;
178 return (0);
179}
180
181void
69void
182clock_ts_to_ct(struct timespec *ts, struct clocktime *ct)
183{
184 int i, year, days;
185 time_t rsec; /* remainder seconds */
186 time_t secs;
187
188 secs = ts->tv_sec;
189 days = secs / SECDAY;
190 rsec = secs % SECDAY;
191
192 ct->dow = day_of_week(days);
193
194 /* Subtract out whole years, counting them in i. */
195 for (year = POSIX_BASE_YEAR; days >= days_in_year(year); year++)
196 days -= days_in_year(year);
197 ct->year = year;
198
199 /* Subtract out whole months, counting them in i. */
200 for (i = 1; days >= days_in_month(year, i); i++)
201 days -= days_in_month(year, i);
202 ct->mon = i;
203
204 /* Days are what is left over (+1) from all that. */
205 ct->day = days + 1;
206
207 /* Hours, minutes, seconds are easy */
208 ct->hour = rsec / 3600;
209 rsec = rsec % 3600;
210 ct->min = rsec / 60;
211 rsec = rsec % 60;
212 ct->sec = rsec;
213 ct->nsec = ts->tv_nsec;
214}
215
216void
217clock_register(device_t dev, long res) /* res has units of microseconds */
218{
219
220 if (clock_dev != NULL) {
221 if (clock_res > res) {
222 if (bootverbose) {
223 device_printf(dev, "not installed as "
224 "time-of-day clock: clock %s has higher "

--- 93 unchanged lines hidden ---
70clock_register(device_t dev, long res) /* res has units of microseconds */
71{
72
73 if (clock_dev != NULL) {
74 if (clock_res > res) {
75 if (bootverbose) {
76 device_printf(dev, "not installed as "
77 "time-of-day clock: clock %s has higher "

--- 93 unchanged lines hidden ---