Return to BSD News archive
Received: by minnie.vk1xwt.ampr.org with NNTP id AA7082 ; Mon, 18 Jan 93 10:47:11 EST Path: sserve!manuel.anu.edu.au!munnari.oz.au!uunet!zaphod.mps.ohio-state.edu!howland.reston.ans.net!paladin.american.edu!news.univie.ac.at!fstgds15.tu-graz.ac.at!fstgds01!chmr From: chmr@fstgds01 (Christoph Robitschko) Newsgroups: comp.unix.bsd Subject: Re: 386BSD/clock.c/CMOS-Time Date: 18 Jan 1993 11:39:02 GMT Organization: Technical University of Graz, Austria Lines: 526 Message-ID: <1je4smINNjro@fstgds15.tu-graz.ac.at> References: <1993Jan15.143725.153556@eratu.rz.uni-konstanz.de> NNTP-Posting-Host: fstgds01.tu-graz.ac.at X-Newsreader: TIN [version 1.1 PL7] [ This is a second attempt. The patch in my first post had two mistakes: in machdep.c.diff, "settodr" should have been "resettodr", and in clock.c, the LEAPYEAR macro was wrong. ] [ Third attempt. I should learn to really include the fixes in the post. 8-( ] In article <1993Jan15.143725.153556@eratu.rz.uni-konstanz.de> Z. Horvat (zh@nike.rz.uni-konstanz.de) wrote: :> In article 1j6aanINNll@fstgds15.tu-graz.ac.at, chmr@fstgds01 (Christoph Robitschko) writes: :> >In article <1993Jan13.090434.141136@eratu.rz.uni-konstanz.de> Z. Horvat (zh@nike.rz.uni-konstanz.de) wrote: :> >:> I noticed that 386BSD will not update the CMOS Time/Date after :> >:> setting it in the running system. :> >:> Maybe someone out there has already patches available ? :> >:> Thanks in advance ... :> >:> :> >I have put my modified clock driver on ref.tfs.com in ~chmr/time . :> >This can write the time back to the CMOS. :> > :> > Christoph :> :> Christoph, :> :> first, thank you very much. :> I have already tried some time ago to contact ref.tfs.com for anon ftp, :> but the link here from germany is very poor. Would you mind posting :> your driver ? :> Hmm, maybe there is a mirror site of this host somwhere here in europe ? So, here goes. This is also available from ftp.tu-graz.ac.at:/pub/386BSD/0.1/unofficial/time . Christoph P.S.: Headers are probably incorrect; Please respond to chmr@edvz.tu-graz.ac.at --- CUT HERE --- # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # README # README.localtz # clock.c # cpu.h.diff # kern_time.c.diff # machdep.c.diff # rtc.h.diff # echo x - README sed 's/^X//' >README << 'END-of-README' XThis is a modified version of the realtime clock support functions. X Xadvantages over the original version: X fixed many bugs X is able to write the time back to the CMOS X (explicitly when you set it via date, and automagically X on shutdown). X has a settable option RTC_LOCALTZ which allows it to satisfy the X needs of 386BSD and DOS (386bsd wants GMT; DOS wants X localtime in the CMOS). X WARNING: This option is not recommended unless you know X exactly what you are doing ! (see README.localtz for details) X XIt does not have code to support daylight savings time, because this does Xnot belong in the kernel, and different countries have different requirements Xfor DST. X X XThis dorectory is intentionally writable: You are welcome to put your Xenhancements here, if you also write a README.enhancement with your name Xand e-mail address in it. X X X Christoph Robitschko X chmr@edvz.tu-graz.ac.at END-of-README echo x - README.localtz sed 's/^X//' >README.localtz << 'END-of-README.localtz' XThe option RTC_LOCALTZ does the following: X X disable the use of the "timezone" config line X On startup, read the time (local time) from the CMOS, X read and validate timezone information (from the CMOS ALARM X registers), and correct the X time to get GMT. X On shutdown or when the time has been changed, correct the time X to local time and write it to the CMOS. X When the timezone is being set (via the settimeofday system call, X and tz.tz_dsttime == -2, use the offset in tz_minuteswest X to save the timezone information in the ALARM registers. X X XThe idea behind the thing is that somewhere in /etc/rc, you should have Xsomething like "date -Z" (the option -Z would have to be added to date), Xwhich calculates the local timezone offset from /usr/share/zoneinfo, and Xpass it along to the kernel. The kernel writes this information to the XCMOS ALARM registers and uses it on the next boot. X X X Christoph Robitschko X chmr@edvz.tu-graz.ac.at END-of-README.localtz echo x - clock.c sed 's/^X//' >clock.c << 'END-of-clock.c' X/*- X * Copyright (c) 1990 The Regents of the University of California. X * All rights reserved. X * X * This code is derived from software contributed to Berkeley by X * William Jolitz and Don Ahn. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * 3. All advertising materials mentioning features or use of this software X * must display the following acknowledgement: X * This product includes software developed by the University of X * California, Berkeley and its contributors. X * 4. Neither the name of the University nor the names of its contributors X * may be used to endorse or promote products derived from this software X * without specific prior written permission. X * X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF X * SUCH DAMAGE. X * X * @(#)clock.c 7.2 (Berkeley) 5/12/91 X */ X X/* X * inittodr, resettodr, setrtc_tz and support routines written X * by Christoph Robitschko <chmr@edvz.tu-graz.ac.at> X * X * You can put an 'options RTC_LOCALTZ' in your config file to make X * both DOS and 386bsd happy about the time in the CMOS clock. X * The system then holds localtime (according to your time zone and DST) X * in the CMOS time registers. So that 386bsd can calculate GMT from this, X * it also holds the current offset from GMT (in hours and minutes) X * in the ALARM registers. X * it is a good idea to run 'date -C' from your /etc/rc file. That updates X * the offset information in the CMOS. (it can change if you have DST). X * X * WARNING: This does not work if you have any applications X * that modify the ALARM registers in the CMOS. X */ X X#include "param.h" X#include "time.h" X#include "kernel.h" X#include "machine/segments.h" X#include "i386/isa/icu.h" X#include "i386/isa/isa.h" X#include "i386/isa/rtc.h" X X#define XTALSPEED 1193182 X X#define LEAPYEAR(_YR) (((!(_YR%4) && (_YR%100)) || !((_YR)%400)) ? 1: 0) X#define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31) Xstatic const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31}; X X X/* X * Support routines X */ Xstatic int Xbcd2int(bcd) X{ X return(bcd/16 * 10 + bcd%16); X} X X Xstatic int Xint2bcd(dez) X{ X return(dez/10 * 16 + dez%10); X} X X Xstatic void Xwritertc(port, val) X{ X outb(IO_RTC, port); X outb(IO_RTC+1, val); X} X X Xstatic int Xreadrtc(port) X{ X return(bcd2int(rtcin(port))); X} X X X/* X * Initialize the real time clock X */ Xstartrtclock() X{ X int s; X X /* initialize 8253 timer */ X outb (IO_TIMER1+3, 0x36); X outb (IO_TIMER1, XTALSPEED/hz); X outb (IO_TIMER1, (XTALSPEED/hz)/256); X X /* initialize brain-dead battery powered clock */ X writertc(RTC_STATUSA, 0x26); X writertc(RTC_STATUSB, RTCSB_24HR); X X if (s = rtcin(RTC_DIAG)) X printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); X writertc(RTC_DIAG, 0); X} X X X/* X * Read the system time from the RTC. X */ Xinittodr(base) Xtime_t base; X{ X unsigned long sec, days; X int yd; X int year, month; X int y, m; X X X time.tv_sec = base; X time.tv_usec = 0; X X /* Look if we have a RTC present and the time is valid */ X if (rtcin(RTC_STATUSD) != RTCSD_PWR) X goto wrong_time; X X /* wait for time update to complete */ X /* If RTCSA_TUP is zero, we have at least 244us before next update */ X while (rtcin(RTC_STATUSA) & RTCSA_TUP); X X days = 0; X year = readrtc(RTC_YEAR) + readrtc(RTC_CENTURY) * 100; X if (year < 1970) X goto wrong_time; X month = readrtc(RTC_MONTH); X for (m = 1; m < month; m++) X days += daysinmonth[m-1]; X if ((month > 2) && LEAPYEAR(year)) X days ++; X days += readrtc(RTC_DAY) - 1; X yd = days; X for (y = 1970; y < year; y++) X days += DAYSPERYEAR + LEAPYEAR(y); X sec = ((( days * 24 + X readrtc(RTC_HRS)) * 60 + X readrtc(RTC_MIN)) * 60 + X readrtc(RTC_SEC)); X /* sec now contains the number of seconds, since Jan 1 1970, X in the local time zone */ X X#ifdef RTC_LOCALTZ X { X unsigned char reg1 = rtcin(RTCLZ_REG1); X unsigned char reg2 = rtcin(RTCLZ_REG2); X unsigned char reg3 = rtcin(RTCLZ_REG3); X if (((reg1 & RTCLZ_M1MASK) == RTCLZ_MAGIC1) && X ((reg2 & RTCLZ_M2MASK) == RTCLZ_MAGIC2) && X ((reg3 & RTCLZ_M3MASK) == RTCLZ_MAGIC3)) { X int offset = 60 * (reg3 & RTCLZ_HRSOFF); X offset += reg2 & RTCLZ_MINOFF; X if (reg3 & RTCLZ_NEG) X sec += 60 * offset; X else X sec -= 60 * offset; X } X else X printf("Warning: No timezone info in CMOS\n"); X } X#else X sec += tz.tz_minuteswest * 60; X#endif X X time.tv_sec = sec; X return; X Xwrong_time: X printf("invalid time in real time clock.\n"); X printf("check and reset the date immediately !\n"); X} X X X/* X * Write system time back to RTC X */ Xresettodr() X{ X unsigned long tm; X int y, m; X X X tm = time.tv_sec; X X /* First, disable clock updates */ X writertc(RTC_STATUSB, RTCSB_SET | RTCSB_24HR); X X /* Calculate local time to put in CMOS */ X#ifdef RTC_LOCALTZ X { X unsigned char reg1 = rtcin(RTCLZ_REG1); X unsigned char reg2 = rtcin(RTCLZ_REG2); X unsigned char reg3 = rtcin(RTCLZ_REG3); X if (((reg1 & RTCLZ_M1MASK) == RTCLZ_MAGIC1) && X ((reg2 & RTCLZ_M2MASK) == RTCLZ_MAGIC2) && X ((reg3 & RTCLZ_M3MASK) == RTCLZ_MAGIC3)) { X int offset = 60 * (reg3 & RTCLZ_HRSOFF); X offset += reg2 & RTCLZ_MINOFF; X if (reg3 & RTCLZ_NEG) X tm -= 60 * offset; X else X tm += 60 * offset; X } X } X#else X tm -= tz.tz_minuteswest * 60; X#endif X X writertc(RTC_SEC, int2bcd(tm%60)); tm /= 60; /* Write back Seconds */ X writertc(RTC_MIN, int2bcd(tm%60)); tm /= 60; /* Write back Minutes */ X writertc(RTC_HRS, int2bcd(tm%24)); tm /= 24; /* Write back Hours */ X X /* We have now the days since 01-01-1970 in tm */ X writertc(RTC_WDAY, (tm+4)%7); /* Write back Weekday */ X for (y=1970;; y++) X if ((tm - DAYSPERYEAR - LEAPYEAR(y)) > tm) X break; X else X tm -= DAYSPERYEAR + LEAPYEAR(y); X X /* Now we have the years in y and the day-of-the-year in tm */ X writertc(RTC_YEAR, int2bcd(y%100)); /* Write back Year */ X writertc(RTC_CENTURY, int2bcd(y/100)); /* ... and Century */ X if (LEAPYEAR(y) && (tm >= 31+29)) X tm--; /* Subtract Feb-29 */ X for (m=1;; m++) X if (tm - daysinmonth[m-1] > tm) X break; X else X tm -= daysinmonth[m-1]; X X writertc(RTC_MONTH, int2bcd(m)); /* Write back Month */ X writertc(RTC_DAY, int2bcd(tm+1)); /* Write back Day */ X X /* enable time updates */ X writertc(RTC_STATUSB, RTCSB_24HR); X} X X X#ifdef RTC_LOCALTZ X/* X * Write timezone offset to CMOS (abuse ALARM registers) X */ Xsetrtc_tz(offset) Xint offset; X{ X unsigned char reg1, reg2, reg3; X X X reg1 = RTCLZ_MAGIC1 & RTCLZ_M1MASK; X reg2 = RTCLZ_MAGIC2 & RTCLZ_M2MASK; X reg3 = RTCLZ_MAGIC3 & RTCLZ_M3MASK; X X if (offset < 0) X reg3 |= RTCLZ_NEG, offset = -offset; X reg2 |= (offset % 60) & RTCLZ_MINOFF; X reg3 |= (offset / 60) & RTCLZ_HRSOFF; X X writertc(RTCLZ_REG1, reg1); X writertc(RTCLZ_REG2, reg2); X writertc(RTCLZ_REG3, reg3); X X /* update the RTC registers */ X resettodr(); X} X#endif X X X/* X * Wire clock interrupt in. X */ X#define V(s) __CONCAT(V, s) Xextern V(clk)(); Xenablertclock() { X INTREN(IRQ0); X setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL); X splnone(); X} END-of-clock.c echo x - cpu.h.diff sed 's/^X//' >cpu.h.diff << 'END-of-cpu.h.diff' X*** /sys/i386/include/cpu.h.ori Tue Dec 24 23:23:38 1991 X--- /sys/i386/include/cpu.h Wed Sep 9 18:47:09 1992 X*************** X*** 71,78 **** X #define CLKF_BASEPRI(framep) ((framep)->if_ppl == 0) X #define CLKF_PC(framep) ((framep)->if_eip) X X- #define resettodr() /* no todr to set */ X- X /* X * Preempt the current process if in interrupt from user mode, X * or after the current trap/syscall if in system mode. X--- 71,76 ---- END-of-cpu.h.diff echo x - kern_time.c.diff sed 's/^X//' >kern_time.c.diff << 'END-of-kern_time.c.diff' X*** /sys/kern/kern_time.c.ori Fri Oct 2 23:12:20 1992 X--- /sys/kern/kern_time.c Fri Oct 2 23:16:40 1992 X*************** X*** 100,105 **** X--- 100,110 ---- X } X if (uap->tzp && (error = copyin((caddr_t)uap->tzp, (caddr_t)&atz, X sizeof (atz))) == 0) X+ #ifdef RTC_LOCALTZ X+ if (atz.tz_dsttime == -2) X+ setrtc_tz(atz.tz_minuteswest); X+ else X+ #endif X tz = atz; X return (error); X } END-of-kern_time.c.diff echo x - machdep.c.diff sed 's/^X//' >machdep.c.diff << 'END-of-machdep.c.diff' X*** /sys/i386/i386/machdep.c.old Sun Aug 9 08:43:08 1992 X--- /sys/i386/i386/machdep.c Tue Jan 5 18:26:06 1993 X*************** X*** 442,447 **** X--- 442,449 ---- X printf("hit reset please"); X for(;;); X } X+ X+ resettodr(); /* Update CMOS clock */ X howto = arghowto; X if ((howto&RB_NOSYNC) == 0 && waittime < 0 && bfreelist[0].b_forw) { X register struct buf *bp; END-of-machdep.c.diff echo x - rtc.h.diff sed 's/^X//' >rtc.h.diff << 'END-of-rtc.h.diff' X*** /sys/i386/isa/rtc.h.ori Mon May 25 23:30:57 1992 X--- /sys/i386/isa/rtc.h Sun Oct 4 08:56:21 1992 X*************** X*** 54,61 **** X #define RTCSA_TUP 0x80 /* time update, don't look now */ X X #define RTC_STATUSB 0x0b /* status register B */ X X! #define RTC_INTR 0x0c /* status register C (R) interrupt source */ X #define RTCIR_UPDATE 0x10 /* update intr */ X #define RTCIR_ALARM 0x20 /* alarm intr */ X #define RTCIR_PERIOD 0x40 /* periodic intr */ X--- 54,69 ---- X #define RTCSA_TUP 0x80 /* time update, don't look now */ X X #define RTC_STATUSB 0x0b /* status register B */ X+ #define RTCSB_DST 0x01 /* Daylight Savings Time enable */ X+ #define RTCSB_24HR 0x02 /* 0 = 12 hours, 1 = 24 hours */ X+ #define RTCSB_BCD 0x04 /* 0 = BCD, 1 = Binary coded time */ X+ #define RTCSB_SQWE 0x08 /* 1 = output sqare wave at SQW pin */ X+ #define RTCSB_UIE 0x10 /* 1 = enable update-ended interrupt */ X+ #define RTCSB_AIE 0x20 /* 1 = enable alarm interrupt */ X+ #define RTCSB_PIE 0x40 /* 1 = enable periodic interrupt */ X+ #define RTCSB_SET 0x80 /* 1 = disable clock update */ X X! #define RTC_INTR 0x0c /* status register C (R/O) interrupt source */ X #define RTCIR_UPDATE 0x10 /* update intr */ X #define RTCIR_ALARM 0x20 /* alarm intr */ X #define RTCIR_PERIOD 0x40 /* periodic intr */ X*************** X*** 82,85 **** X #define RTC_EXTLO 0x17 /* low byte of extended mem size */ X #define RTC_EXTHI 0x18 /* low byte of extended mem size */ X X! #define RTC_CENTURY 0x32 /* current century - please increment in Dec99*/ X--- 90,109 ---- X #define RTC_EXTLO 0x17 /* low byte of extended mem size */ X #define RTC_EXTHI 0x18 /* low byte of extended mem size */ X X! #define RTC_CENTURY 0x32 /* current century */ X! X! X! #ifdef RTC_LOCALTZ /* see clock.c for explanation */ X! # define RTCLZ_REG1 RTC_SECALRM /* abused for our purposes */ X! # define RTCLZ_REG2 RTC_MINALRM X! # define RTCLZ_REG3 RTC_HRSALRM X! # define RTCLZ_MAGIC1 'j' /* cannot be confused with time value */ X! # define RTCLZ_M1MASK 0xff /* whole register is magic */ X! # define RTCLZ_MAGIC2 0x40 /* binary 01000000 */ X! # define RTCLZ_M2MASK 0xc0 /* mask 11000000 */ X! # define RTCLZ_MINOFF 0x3f /* 00111111 */ X! # define RTCLZ_MAGIC3 0x20 /* binary 001xxxxx */ X! # define RTCLZ_M3MASK 0xe0 /* mask 11100000 */ X! # define RTCLZ_NEG 0x10 /* 00010000 */ X! # define RTCLZ_HRSOFF 0x0f /* 00001111 */ X! #endif END-of-rtc.h.diff exit