| 1 | /*- |
| 2 | * SPDX-License-Identifier: BSD-2-Clause |
| 3 | * |
| 4 | * Copyright (c) 1996 The NetBSD Foundation, Inc. |
| 5 | * All rights reserved. |
| 6 | * |
| 7 | * This code is derived from software contributed to The NetBSD Foundation |
| 8 | * by Gordon W. Ross |
| 9 | * |
| 10 | * Redistribution and use in source and binary forms, with or without |
| 11 | * modification, are permitted provided that the following conditions |
| 12 | * are met: |
| 13 | * 1. Redistributions of source code must retain the above copyright |
| 14 | * notice, this list of conditions and the following disclaimer. |
| 15 | * 2. Redistributions in binary form must reproduce the above copyright |
| 16 | * notice, this list of conditions and the following disclaimer in the |
| 17 | * documentation and/or other materials provided with the distribution. |
| 18 | * |
| 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
| 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
| 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
| 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 29 | * POSSIBILITY OF SUCH DAMAGE. |
| 30 | * |
| 31 | *	$NetBSD: clock_subr.h,v 1.7 2000/10/03 13:41:07 tsutsui Exp $ |
| 32 | * |
| 33 | * |
| 34 | * This file is the central clearing-house for calendrical issues. |
| 35 | * |
| 36 | * In general the kernel does not know about minutes, hours, days, timezones, |
| 37 | * daylight savings time, leap-years and such. All that is theoretically a |
| 38 | * matter for userland only. |
| 39 | * |
| 40 | * Parts of kernel code does however care: badly designed filesystems store |
| 41 | * timestamps in local time and RTC chips sometimes track time in a local |
| 42 | * timezone instead of UTC and so on. |
| 43 | * |
| 44 | * All that code should go here for service. |
| 45 | */ |
| 46 | |
| 47 | #ifndef _SYS_CLOCK_H_ |
| 48 | #define _SYS_CLOCK_H_ |
| 49 | |
| 50 | #ifdef _KERNEL		/* No user serviceable parts */ |
| 51 | |
| 52 | int utc_offset(void); |
| 53 | |
| 54 | /* |
| 55 | * Structure to hold the values typically reported by time-of-day clocks, |
| 56 | * expressed as binary integers (see below for a BCD version). This can be |
| 57 | * passed to the conversion functions to be converted to/from a struct timespec. |
| 58 | * |
| 59 | * On input, the year is interpreted as follows: |
| 60 | * 0 - 69 = 2000 - 2069 |
| 61 | * 70 - 99 = 1970 - 1999 |
| 62 | * 100 - 199 = 2000 - 2099 (Supports hardware "century bit".) |
| 63 | * 200 - 1969 = Invalid. |
| 64 | * 1970 - 9999 = Full 4-digit century+year. |
| 65 | * |
| 66 | * The dow field is ignored (not even validated) on input, but is always |
| 67 | * populated with day-of-week on output. |
| 68 | * |
| 69 | * clock_ct_to_ts() returns EINVAL if any values are out of range. The year |
| 70 | * field will always be 4-digit on output. |
| 71 | */ |
| 72 | struct clocktime { |
| 73 | 	int	year;			/* year (4 digit year) */ |
| 74 | 	int	mon;			/* month (1 - 12) */ |
| 75 | 	int	day;			/* day (1 - 31) */ |
| 76 | 	int	hour;			/* hour (0 - 23) */ |
| 77 | 	int	min;			/* minute (0 - 59) */ |
| 78 | 	int	sec;			/* second (0 - 59) */ |
| 79 | 	int	dow;			/* day of week (0 - 6; 0 = Sunday) */ |
| 80 | 	long	nsec;			/* nano seconds */ |
| 81 | }; |
| 82 | |
| 83 | int clock_ct_to_ts(const struct clocktime *, struct timespec *); |
| 84 | void clock_ts_to_ct(const struct timespec *, struct clocktime *); |
| 85 | |
| 86 | /* |
| 87 | * Structure to hold the values typically reported by time-of-day clocks, |
| 88 | * expressed as BCD. This can be passed to the conversion functions to be |
| 89 | * converted to/from a struct timespec. |
| 90 | * |
| 91 | * The clock_bcd_to_ts() function interprets the values in the year through sec |
| 92 | * fields as BCD numbers, and returns EINVAL if any BCD values are out of range. |
| 93 | * After conversion to binary, the values are passed to clock_ct_to_ts() and |
| 94 | * undergo further validation as described above. Year may be 2 or 4-digit BCD, |
| 95 | * interpreted as described above. The nsec field is binary. If the ampm arg |
| 96 | * is true, the incoming hour and ispm values are interpreted as 12-hour am/pm |
| 97 | * representation of the hour, otherwise hour is interpreted as 24-hour and ispm |
| 98 | * is ignored. |
| 99 | * |
| 100 | * The clock_ts_to_bcd() function converts the timespec to BCD values stored |
| 101 | * into year through sec. The value in year will be 4-digit BCD (e.g., |
| 102 | * 0x2017). The mon through sec values will be 2-digit BCD. The nsec field will |
| 103 | * be binary, and the range of dow makes its binary and BCD values identical. |
| 104 | * If the ampm arg is true, the hour and ispm fields are set to the 12-hour |
| 105 | * time plus a pm flag, otherwise the hour is set to 24-hour time and ispm is |
| 106 | * set to false. |
| 107 | */ |
| 108 | struct bcd_clocktime { |
| 109 | 	uint16_t year;			/* year (2 or 4 digit year) */ |
| 110 | 	uint8_t mon;			/* month (1 - 12) */ |
| 111 | 	uint8_t day;			/* day (1 - 31) */ |
| 112 | 	uint8_t hour;			/* hour (0 - 23 or 1 - 12) */ |
| 113 | 	uint8_t min;			/* minute (0 - 59) */ |
| 114 | 	uint8_t sec;			/* second (0 - 59) */ |
| 115 | 	uint8_t dow;			/* day of week (0 - 6; 0 = Sunday) */ |
| 116 | 	long nsec;			/* nanoseconds */ |
| 117 | 	bool ispm;			/* true if hour represents pm time */ |
| 118 | }; |
| 119 | |
| 120 | int clock_bcd_to_ts(const struct bcd_clocktime *, struct timespec *, bool ampm); |
| 121 | void clock_ts_to_bcd(const struct timespec *, struct bcd_clocktime *, bool ampm); |
| 122 | |
| 123 | /* |
| 124 | * Time-of-day clock functions and flags. These functions might sleep. |
| 125 | * |
| 126 | * clock_register and clock_unregister() do what they say. Upon return from |
| 127 | * unregister, the clock's methods are not running and will not be called again. |
| 128 | * |
| 129 | * clock_schedule() requests that a registered clock's clock_settime() calls |
| 130 | * happen at the given offset into the second. The default is 0, meaning no |
| 131 | * specific scheduling. To schedule the call as soon after top-of-second as |
| 132 | * possible, specify 1. Each clock has its own schedule, but taskqueue_thread |
| 133 | * is shared by many tasks; the timing of the call is not guaranteed. |
| 134 | * |
| 135 | * Flags: |
| 136 | * |
| 137 | * CLOCKF_SETTIME_NO_TS |
| 138 | * Do not pass a timespec to clock_settime(), the driver obtains its own time |
| 139 | * and applies its own adjustments (this flag implies CLOCKF_SETTIME_NO_ADJ). |
| 140 | * |
| 141 | * CLOCKF_SETTIME_NO_ADJ |
| 142 | * Do not apply utc offset and resolution/accuracy adjustments to the value |
| 143 | * passed to clock_settime(), the driver applies them itself. |
| 144 | * |
| 145 | * CLOCKF_GETTIME_NO_ADJ |
| 146 | * Do not apply utc offset and resolution/accuracy adjustments to the value |
| 147 | * returned from clock_gettime(), the driver has already applied them. |
| 148 | */ |
| 149 | |
| 150 | #define	CLOCKF_SETTIME_NO_TS	0x00000001 |
| 151 | #define	CLOCKF_SETTIME_NO_ADJ	0x00000002 |
| 152 | #define	CLOCKF_GETTIME_NO_ADJ	0x00000004 |
| 153 | |
| 154 | void clock_register(device_t _clockdev, long _resolution_us); |
| 155 | void clock_register_flags(device_t _clockdev, long _resolution_us, int _flags); |
| 156 | void clock_schedule(device_t clockdev, u_int _offsetns); |
| 157 | void clock_unregister(device_t _clockdev); |
| 158 | |
| 159 | /* |
| 160 | * BCD to decimal and decimal to BCD. |
| 161 | */ |
| 162 | #define	FROMBCD(x)	bcd2bin(x) |
| 163 | #define	TOBCD(x)	bin2bcd(x) |
| 164 | |
| 165 | /* Some handy constants. */ |
| 166 | #define SECDAY		(24 * 60 * 60) |
| 167 | #define SECYR		(SECDAY * 365) |
| 168 | |
| 169 | /* Traditional POSIX base year */ |
| 170 | #define	POSIX_BASE_YEAR	1970 |
| 171 | |
| 172 | void timespec2fattime(const struct timespec *tsp, int utc, u_int16_t *ddp, |
| 173 | u_int16_t *dtp, u_int8_t *dhp); |
| 174 | void fattime2timespec(unsigned dd, unsigned dt, unsigned dh, int utc, |
| 175 | struct timespec *tsp); |
| 176 | |
| 177 | /* |
| 178 | * Print a [bcd_]clocktime or timespec, optionally with fractional seconds. The |
| 179 | * nsdig argument can range from 0-9, and specifies how many decimal digits to |
| 180 | * display for fractional seconds. |
| 181 | */ |
| 182 | void clock_print_bcd(const struct bcd_clocktime *bct, int nsdig); |
| 183 | void clock_print_ct(const struct clocktime *ct, int nsdig); |
| 184 | void clock_print_ts(const struct timespec *ts, int nsdig); |
| 185 | |
| 186 | /* |
| 187 | * Debugging helpers for RTC clock drivers. Print a [bcd_]clocktime or |
| 188 | * timespec, only if rtc clock debugging has been enabled. The rw argument is |
| 189 | * one of CLOCK_DBG_READ or CLOCK_DBG_WRITE. |
| 190 | */ |
| 191 | #define	CLOCK_DBG_READ	0x01 |
| 192 | #define	CLOCK_DBG_WRITE	0x02 |
| 193 | void clock_dbgprint_bcd(device_t dev, int rw, const struct bcd_clocktime *bct); |
| 194 | void clock_dbgprint_ct(device_t dev, int rw, const struct clocktime *ct); |
| 195 | void clock_dbgprint_err(device_t dev, int rw, int err); |
| 196 | void clock_dbgprint_ts(device_t dev, int rw, const struct timespec *ts); |
| 197 | |
| 198 | #endif /* _KERNEL */ |
| 199 | |
| 200 | #endif /* !_SYS_CLOCK_H_ */ |