diff options
-rw-r--r-- | sys/dev/usb/udcf.c | 146 |
1 files changed, 134 insertions, 12 deletions
diff --git a/sys/dev/usb/udcf.c b/sys/dev/usb/udcf.c index 20ac0296f2a..5d8ea25df5f 100644 --- a/sys/dev/usb/udcf.c +++ b/sys/dev/usb/udcf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: udcf.c,v 1.12 2006/06/12 09:51:09 mbalmer Exp $ */ +/* $OpenBSD: udcf.c,v 1.13 2006/06/17 12:26:55 mbalmer Exp $ */ /* * Copyright (c) 2006 Marc Balmer <mbalmer@openbsd.org> @@ -29,7 +29,6 @@ #include <sys/time.h> #include <sys/sensors.h> -#include <dev/clock_subr.h> #include <dev/usb/usb.h> #include <dev/usb/usbdi.h> #include <dev/usb/usbdi_util.h> @@ -43,6 +42,18 @@ int udcfdebug = 0; #endif #define DPRINTF(x) DPRINTFN(0, x) +/* Traditional POSIX base year */ +#define POSIX_BASE_YEAR 1970 + +static inline int leapyear(int year); +#define FEBRUARY 2 +#define days_in_year(a) (leapyear(a) ? 366 : 365) +#define days_in_month(a) (month_days[(a) - 1]) + +static const int month_days[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + #define UDCF_READ_REQ 0xc0 #define UDCF_READ_IDX 0x1f @@ -113,6 +124,11 @@ void udcf_sl_probe(void *); void udcf_it_probe(void *); void udcf_ct_probe(void *); +#define FROMBCD(x) (((x) >> 4) * 10 + ((x) & 0xf)) +static inline int leapyear(int year); +int udcf_ymdhm_to_secs(int y, int mon, int d, int h, int m, time_t *secs); + + USB_DECLARE_DRIVER(udcf); USB_MATCH(udcf) @@ -460,7 +476,7 @@ udcf_mg_probe(void *xsc) { struct udcf_softc *sc = xsc; - struct clock_ymdhms ymdhm; + int year, month, day, hour, minute; int minute_bits, hour_bits, day_bits; int month_bits, year_bits, wday; int p1, p2, p3; @@ -529,18 +545,23 @@ udcf_mg_probe(void *xsc) /* Decode valid time */ - ymdhm.dt_min = FROMBCD(minute_bits); - ymdhm.dt_hour = FROMBCD(hour_bits); - ymdhm.dt_day = FROMBCD(day_bits); - ymdhm.dt_mon = FROMBCD(month_bits); - ymdhm.dt_year = 2000 + FROMBCD(year_bits); - ymdhm.dt_sec = 0; + minute = FROMBCD(minute_bits); + hour = FROMBCD(hour_bits); + day = FROMBCD(day_bits); + month = FROMBCD(month_bits); + year = 2000 + FROMBCD(year_bits); - sc->sc_next = clock_ymdhms_to_secs(&ymdhm); + if (!udcf_ymdhm_to_secs(year, month, day, + hour, minute, &sc->sc_next)) { - /* convert to coordinated universal time */ + /* convert to UTC */ - sc->sc_next -= z1_bit ? 7200 : 3600; + sc->sc_next -= z1_bit ? 7200 : 3600; + } else { + sc->sc_sensor.status = SENSOR_S_WARN; + timeout_add(&sc->sc_it_to, t8); + sc->sc_sync = 1; + } DPRINTF(("\n%02d.%02d.%04d %02d:%02d:00 %s", ymdhm.dt_day, ymdhm.dt_mon + 1, @@ -637,3 +658,104 @@ udcf_activate(device_ptr_t self, enum devact act) } return (0); } + +/* + * the leapyear() and udcf_ymdhms_to_secs() functions to calculate the number + * of seconds since the epoch for a certain date are from sys/dev/clock_subr.c, + * the following copyright applies to these functions: + */ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1982, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department. + * + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +/* + * This inline avoids some unnecessary modulo operations + * as compared with the usual macro: + * ( ((year % 4) == 0 && + * (year % 100) != 0) || + * ((year % 400) == 0) ) + * It is otherwise equivalent. + */ +static inline int +leapyear(int year) +{ + int rv = 0; + + if ((year & 3) == 0) { + rv = 1; + if ((year % 100) == 0) { + rv = 0; + if ((year % 400) == 0) + rv = 1; + } + } + return (rv); +} + +/* convert year, month, day, hour, minute to seconds since the epoch */ +int +udcf_ymdhm_to_secs(int year, int month, int day, int hour, int minute, + time_t *secs) +{ + int i, days; + int leap; + + if (month < 1 || month > 12) + return (-1); + + days = days_in_month(month); + leap = leapyear(year); + if (month == FEBRUARY && leap) + days++; + if (day < 1 || day > days) + return (-1); + + /* + * Compute days since start of time + * First from years, then from months. + */ + days = 0; + for (i = POSIX_BASE_YEAR; i < year; i++) + days += days_in_year(i); + if (leap && month > FEBRUARY) + days++; + + /* Months */ + for (i = 1; i < month; i++) + days += days_in_month(i); + days += (day - 1); + + /* convert to seconds. */ + *secs = days * 86400L + hour * 3600L + minute * 60L; + return (0); +} |