Home | History | Annotate | Line # | Download | only in dev
clock.c revision 1.13
      1  1.13  christos /*	$NetBSD: clock.c,v 1.13 1996/10/13 04:10:51 christos Exp $	*/
      2   1.1       leo 
      3   1.1       leo /*
      4   1.1       leo  * Copyright (c) 1988 University of Utah.
      5   1.1       leo  * Copyright (c) 1982, 1990 The Regents of the University of California.
      6   1.1       leo  * All rights reserved.
      7   1.1       leo  *
      8   1.1       leo  * This code is derived from software contributed to Berkeley by
      9   1.1       leo  * the Systems Programming Group of the University of Utah Computer
     10   1.1       leo  * Science Department.
     11   1.1       leo  *
     12   1.1       leo  * Redistribution and use in source and binary forms, with or without
     13   1.1       leo  * modification, are permitted provided that the following conditions
     14   1.1       leo  * are met:
     15   1.1       leo  * 1. Redistributions of source code must retain the above copyright
     16   1.1       leo  *    notice, this list of conditions and the following disclaimer.
     17   1.1       leo  * 2. Redistributions in binary form must reproduce the above copyright
     18   1.1       leo  *    notice, this list of conditions and the following disclaimer in the
     19   1.1       leo  *    documentation and/or other materials provided with the distribution.
     20   1.1       leo  * 3. All advertising materials mentioning features or use of this software
     21   1.1       leo  *    must display the following acknowledgement:
     22   1.1       leo  *	This product includes software developed by the University of
     23   1.1       leo  *	California, Berkeley and its contributors.
     24   1.1       leo  * 4. Neither the name of the University nor the names of its contributors
     25   1.1       leo  *    may be used to endorse or promote products derived from this software
     26   1.1       leo  *    without specific prior written permission.
     27   1.1       leo  *
     28   1.1       leo  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     29   1.1       leo  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     30   1.1       leo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     31   1.1       leo  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     32   1.1       leo  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     33   1.1       leo  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     34   1.1       leo  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     35   1.1       leo  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     36   1.1       leo  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     37   1.1       leo  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     38   1.1       leo  * SUCH DAMAGE.
     39   1.1       leo  *
     40   1.1       leo  * from: Utah $Hdr: clock.c 1.18 91/01/21$
     41   1.1       leo  *
     42   1.1       leo  *	@(#)clock.c	7.6 (Berkeley) 5/7/91
     43   1.1       leo  */
     44   1.1       leo 
     45   1.1       leo #include <sys/param.h>
     46   1.1       leo #include <sys/kernel.h>
     47   1.9       leo #include <sys/systm.h>
     48   1.1       leo #include <sys/device.h>
     49   1.1       leo #include <machine/psl.h>
     50   1.1       leo #include <machine/cpu.h>
     51   1.1       leo #include <machine/iomap.h>
     52   1.1       leo #include <machine/mfp.h>
     53   1.1       leo #include <atari/dev/clockreg.h>
     54   1.1       leo 
     55   1.4       leo #if defined(GPROF) && defined(PROFTIMER)
     56   1.4       leo #include <machine/profile.h>
     57   1.1       leo #endif
     58   1.1       leo 
     59   1.1       leo /*
     60   1.5       leo  * The MFP clock runs at 2457600Hz. We use a {system,stat,prof}clock divider
     61   1.5       leo  * of 200. Therefore the timer runs at an effective rate of:
     62   1.5       leo  * 2457600/200 = 12288Hz.
     63   1.5       leo  */
     64   1.5       leo #define CLOCK_HZ	12288
     65   1.5       leo 
     66   1.5       leo /*
     67   1.1       leo  * Machine-dependent clock routines.
     68   1.1       leo  *
     69   1.1       leo  * Inittodr initializes the time of day hardware which provides
     70   1.1       leo  * date functions.
     71   1.1       leo  *
     72   1.1       leo  * Resettodr restores the time of day hardware after a time change.
     73   1.1       leo  */
     74   1.1       leo 
     75  1.10   thorpej int	clockmatch __P((struct device *, void *, void *));
     76   1.1       leo void	clockattach __P((struct device *, struct device *, void *));
     77   1.1       leo 
     78  1.10   thorpej struct cfattach clock_ca = {
     79  1.10   thorpej 	sizeof(struct device), clockmatch, clockattach
     80  1.10   thorpej };
     81  1.10   thorpej 
     82  1.10   thorpej struct cfdriver clock_cd = {
     83  1.10   thorpej 	NULL, "clock", DV_DULL, NULL, 0
     84   1.1       leo };
     85   1.1       leo 
     86   1.9       leo void statintr __P((struct clockframe *));
     87   1.9       leo 
     88   1.1       leo static u_long	gettod __P((void));
     89   1.1       leo static int	settod __P((u_long));
     90   1.1       leo 
     91   1.5       leo static int	divisor;	/* Systemclock divisor	*/
     92   1.5       leo 
     93   1.5       leo /*
     94   1.5       leo  * Statistics and profile clock intervals and variances. Variance must
     95   1.5       leo  * be a power of 2. Since this gives us an even number, not an odd number,
     96   1.5       leo  * we discard one case and compensate. That is, a variance of 64 would
     97   1.5       leo  * give us offsets in [0..63]. Instead, we take offsets in [1..63].
     98   1.5       leo  * This is symetric around the point 32, or statvar/2, and thus averages
     99   1.5       leo  * to that value (assuming uniform random numbers).
    100   1.5       leo  */
    101   1.5       leo #ifdef STATCLOCK
    102   1.5       leo static int	statvar = 32;	/* {stat,prof}clock variance		*/
    103   1.5       leo static int	statmin;	/* statclock divisor - variance/2	*/
    104   1.5       leo static int	profmin;	/* profclock divisor - variance/2	*/
    105   1.5       leo static int	clk2min;	/* current, from above choises		*/
    106   1.5       leo #endif
    107   1.1       leo 
    108   1.1       leo int
    109  1.10   thorpej clockmatch(pdp, match, auxp)
    110   1.1       leo struct device *pdp;
    111  1.10   thorpej void *match, *auxp;
    112   1.1       leo {
    113   1.1       leo 	if(!strcmp("clock", auxp))
    114   1.1       leo 		return(1);
    115   1.1       leo 	return(0);
    116   1.1       leo }
    117   1.1       leo 
    118   1.1       leo /*
    119   1.1       leo  * Start the real-time clock.
    120   1.1       leo  */
    121   1.1       leo void clockattach(pdp, dp, auxp)
    122   1.1       leo struct device	*pdp, *dp;
    123   1.1       leo void			*auxp;
    124   1.1       leo {
    125   1.1       leo 	/*
    126   1.3       leo 	 * Initialize Timer-A in the ST-MFP. We use a divisor of 200.
    127   1.3       leo 	 * The MFP clock runs at 2457600Hz. Therefore the timer runs
    128   1.3       leo 	 * at an effective rate of: 2457600/200 = 12288Hz. The
    129   1.3       leo 	 * following expression works for 48, 64 or 96 hz.
    130   1.1       leo 	 */
    131   1.5       leo 	divisor       = CLOCK_HZ/hz;
    132   1.2       leo 	MFP->mf_tacr  = 0;		/* Stop timer			*/
    133   1.2       leo 	MFP->mf_iera &= ~IA_TIMA;	/* Disable timer interrupts	*/
    134   1.2       leo 	MFP->mf_tadr  = divisor;	/* Set divisor			*/
    135   1.1       leo 
    136   1.5       leo 	if (hz != 48 && hz != 64 && hz != 96) { /* XXX */
    137  1.13  christos 		printf (": illegal value %d for systemclock, reset to %d\n\t",
    138   1.5       leo 								hz, 64);
    139   1.5       leo 		hz = 64;
    140   1.5       leo 	}
    141  1.13  christos 	printf(": system hz %d timer-A divisor 200/%d\n", hz, divisor);
    142   1.1       leo 
    143   1.5       leo #ifdef STATCLOCK
    144   1.5       leo 	if ((stathz == 0) || (stathz > hz) || (CLOCK_HZ % stathz))
    145   1.5       leo 		stathz = hz;
    146   1.5       leo 	if ((profhz == 0) || (profhz > (hz << 1)) || (CLOCK_HZ % profhz))
    147   1.5       leo 		profhz = hz << 1;
    148   1.5       leo 
    149   1.5       leo 	MFP->mf_tcdcr &= 0x7;			/* Stop timer		*/
    150   1.5       leo 	MFP->mf_ierb  &= ~IB_TIMC;		/* Disable timer inter.	*/
    151   1.5       leo 	MFP->mf_tcdr   = CLOCK_HZ/stathz;	/* Set divisor		*/
    152   1.5       leo 
    153   1.5       leo 	statmin  = (CLOCK_HZ/stathz) - (statvar >> 1);
    154   1.5       leo 	profmin  = (CLOCK_HZ/profhz) - (statvar >> 1);
    155   1.5       leo 	clk2min  = statmin;
    156   1.5       leo #endif /* STATCLOCK */
    157   1.5       leo 
    158   1.1       leo 	/*
    159   1.2       leo 	 * Initialize Timer-B in the ST-MFP. This timer is used by the 'delay'
    160   1.1       leo 	 * function below. This time is setup to be continueously counting from
    161   1.1       leo 	 * 255 back to zero at a frequency of 614400Hz.
    162   1.1       leo 	 */
    163   1.2       leo 	MFP->mf_tbcr  = 0;		/* Stop timer			*/
    164   1.2       leo 	MFP->mf_iera &= ~IA_TIMB;	/* Disable timer interrupts	*/
    165   1.2       leo 	MFP->mf_tbdr  = 0;
    166   1.2       leo 	MFP->mf_tbcr  = T_Q004;	/* Start timer			*/
    167   1.1       leo 
    168   1.1       leo }
    169   1.1       leo 
    170   1.1       leo void cpu_initclocks()
    171   1.1       leo {
    172   1.3       leo 	MFP->mf_tacr  = T_Q200;		/* Start timer			*/
    173   1.2       leo 	MFP->mf_ipra &= ~IA_TIMA;	/* Clear pending interrupts	*/
    174   1.2       leo 	MFP->mf_iera |= IA_TIMA;	/* Enable timer interrupts	*/
    175   1.2       leo 	MFP->mf_imra |= IA_TIMA;	/*    .....			*/
    176   1.5       leo 
    177   1.5       leo #ifdef STATCLOCK
    178   1.5       leo 	MFP->mf_tcdcr = (MFP->mf_tcdcr & 0x7) | (T_Q200<<4); /* Start	*/
    179   1.5       leo 	MFP->mf_iprb &= ~IB_TIMC;	/* Clear pending interrupts	*/
    180   1.5       leo 	MFP->mf_ierb |= IB_TIMC;	/* Enable timer interrupts	*/
    181   1.5       leo 	MFP->mf_imrb |= IB_TIMC;	/*    .....			*/
    182   1.5       leo #endif /* STATCLOCK */
    183   1.1       leo }
    184   1.1       leo 
    185   1.9       leo void
    186   1.5       leo setstatclockrate(newhz)
    187   1.5       leo 	int newhz;
    188   1.1       leo {
    189   1.5       leo #ifdef STATCLOCK
    190   1.5       leo 	if (newhz == stathz)
    191   1.5       leo 		clk2min = statmin;
    192   1.5       leo 	else clk2min = profmin;
    193   1.5       leo #endif /* STATCLOCK */
    194   1.1       leo }
    195   1.1       leo 
    196   1.5       leo #ifdef STATCLOCK
    197   1.5       leo void
    198   1.5       leo statintr(frame)
    199   1.5       leo 	register struct clockframe *frame;
    200   1.5       leo {
    201   1.5       leo 	register int	var, r;
    202   1.5       leo 
    203   1.5       leo 	var = statvar - 1;
    204   1.5       leo 	do {
    205   1.5       leo 		r = random() & var;
    206   1.5       leo 	} while(r == 0);
    207   1.5       leo 
    208   1.5       leo 	/*
    209   1.5       leo 	 * Note that we are always lagging behind as the new divisor
    210   1.5       leo 	 * value will not be loaded until the next interrupt. This
    211   1.5       leo 	 * shouldn't disturb the median frequency (I think ;-) ) as
    212   1.5       leo 	 * only the value used when switching frequencies is used
    213   1.5       leo 	 * twice. This shouldn't happen very often.
    214   1.5       leo 	 */
    215   1.5       leo 	MFP->mf_tcdr = clk2min + r;
    216   1.5       leo 
    217   1.5       leo 	statclock(frame);
    218   1.5       leo }
    219   1.5       leo #endif /* STATCLOCK */
    220   1.5       leo 
    221   1.1       leo /*
    222   1.1       leo  * Returns number of usec since last recorded clock "tick"
    223   1.1       leo  * (i.e. clock interrupt).
    224   1.1       leo  */
    225   1.9       leo long
    226   1.1       leo clkread()
    227   1.1       leo {
    228   1.3       leo 	u_int	delta;
    229   1.3       leo 
    230   1.3       leo 	delta = ((divisor - MFP->mf_tadr) * tick) / divisor;
    231   1.1       leo 	/*
    232   1.1       leo 	 * Account for pending clock interrupts
    233   1.1       leo 	 */
    234   1.2       leo 	if(MFP->mf_iera & IA_TIMA)
    235   1.1       leo 		return(delta + tick);
    236   1.1       leo 	return(delta);
    237   1.1       leo }
    238   1.1       leo 
    239   1.2       leo #define TIMB_FREQ	614400
    240   1.2       leo #define TIMB_LIMIT	256
    241   1.1       leo 
    242   1.1       leo /*
    243   1.1       leo  * Wait "n" microseconds.
    244   1.2       leo  * Relies on MFP-Timer B counting down from TIMB_LIMIT at TIMB_FREQ Hz.
    245   1.1       leo  * Note: timer had better have been programmed before this is first used!
    246   1.1       leo  */
    247   1.1       leo void delay(n)
    248   1.1       leo int	n;
    249   1.1       leo {
    250   1.1       leo 	int	tick, otick;
    251   1.1       leo 
    252   1.1       leo 	/*
    253   1.1       leo 	 * Read the counter first, so that the rest of the setup overhead is
    254   1.1       leo 	 * counted.
    255   1.1       leo 	 */
    256   1.2       leo 	otick = MFP->mf_tbdr;
    257   1.1       leo 
    258   1.1       leo 	/*
    259   1.1       leo 	 * Calculate ((n * TIMER_FREQ) / 1e6) using explicit assembler code so
    260   1.1       leo 	 * we can take advantage of the intermediate 64-bit quantity to prevent
    261   1.1       leo 	 * loss of significance.
    262   1.1       leo 	 */
    263   1.1       leo 	n -= 5;
    264   1.1       leo 	if(n < 0)
    265   1.1       leo 		return;
    266   1.1       leo 	{
    267   1.1       leo 	    u_int	temp;
    268   1.1       leo 
    269   1.1       leo 	    __asm __volatile ("mulul %2,%1:%0" : "=d" (n), "=d" (temp)
    270   1.2       leo 					       : "d" (TIMB_FREQ));
    271   1.1       leo 	    __asm __volatile ("divul %1,%2:%0" : "=d" (n)
    272   1.1       leo 					       : "d"(1000000),"d"(temp),"0"(n));
    273   1.1       leo 	}
    274   1.1       leo 
    275   1.1       leo 	while(n > 0) {
    276   1.2       leo 		tick = MFP->mf_tbdr;
    277   1.1       leo 		if(tick > otick)
    278   1.2       leo 			n -= TIMB_LIMIT - (tick - otick);
    279   1.1       leo 		else n -= otick - tick;
    280   1.1       leo 		otick = tick;
    281   1.1       leo 	}
    282   1.1       leo }
    283   1.1       leo 
    284   1.4       leo #ifdef GPROF
    285   1.1       leo /*
    286   1.1       leo  * profclock() is expanded in line in lev6intr() unless profiling kernel.
    287   1.1       leo  * Assumes it is called with clock interrupts blocked.
    288   1.1       leo  */
    289   1.1       leo profclock(pc, ps)
    290   1.1       leo 	caddr_t pc;
    291   1.1       leo 	int ps;
    292   1.1       leo {
    293   1.1       leo 	/*
    294   1.1       leo 	 * Came from user mode.
    295   1.1       leo 	 * If this process is being profiled record the tick.
    296   1.1       leo 	 */
    297   1.1       leo 	if (USERMODE(ps)) {
    298   1.1       leo 		if (p->p_stats.p_prof.pr_scale)
    299   1.1       leo 			addupc(pc, &curproc->p_stats.p_prof, 1);
    300   1.1       leo 	}
    301   1.1       leo 	/*
    302   1.1       leo 	 * Came from kernel (supervisor) mode.
    303   1.1       leo 	 * If we are profiling the kernel, record the tick.
    304   1.1       leo 	 */
    305   1.1       leo 	else if (profiling < 2) {
    306   1.1       leo 		register int s = pc - s_lowpc;
    307   1.1       leo 
    308   1.1       leo 		if (s < s_textsize)
    309   1.1       leo 			kcount[s / (HISTFRACTION * sizeof (*kcount))]++;
    310   1.1       leo 	}
    311   1.1       leo 	/*
    312   1.1       leo 	 * Kernel profiling was on but has been disabled.
    313   1.1       leo 	 * Mark as no longer profiling kernel and if all profiling done,
    314   1.1       leo 	 * disable the clock.
    315   1.1       leo 	 */
    316   1.1       leo 	if (profiling && (profon & PRF_KERNEL)) {
    317   1.1       leo 		profon &= ~PRF_KERNEL;
    318   1.1       leo 		if (profon == PRF_NONE)
    319   1.1       leo 			stopprofclock();
    320   1.1       leo 	}
    321   1.1       leo }
    322   1.1       leo #endif
    323   1.7       leo 
    324   1.7       leo /***********************************************************************
    325   1.7       leo  *                   Real Time Clock support                           *
    326   1.7       leo  ***********************************************************************/
    327   1.7       leo 
    328   1.7       leo u_int mc146818_read(rtc, regno)
    329   1.7       leo void	*rtc;
    330   1.7       leo u_int	regno;
    331   1.7       leo {
    332   1.7       leo 	((struct rtc *)rtc)->rtc_regno = regno;
    333   1.7       leo 	return(((struct rtc *)rtc)->rtc_data & 0377);
    334   1.7       leo }
    335   1.7       leo 
    336   1.7       leo void mc146818_write(rtc, regno, value)
    337   1.7       leo void	*rtc;
    338   1.7       leo u_int	regno, value;
    339   1.7       leo {
    340   1.7       leo 	((struct rtc *)rtc)->rtc_regno = regno;
    341   1.7       leo 	((struct rtc *)rtc)->rtc_data  = value;
    342   1.7       leo }
    343   1.1       leo 
    344   1.1       leo /*
    345   1.1       leo  * Initialize the time of day register, based on the time base which is, e.g.
    346   1.1       leo  * from a filesystem.
    347   1.1       leo  */
    348   1.9       leo void
    349   1.1       leo inittodr(base)
    350   1.1       leo time_t base;
    351   1.1       leo {
    352   1.1       leo 	u_long timbuf = base;	/* assume no battery clock exists */
    353   1.1       leo 
    354   1.1       leo 	timbuf = gettod();
    355   1.1       leo 
    356   1.1       leo 	if(timbuf < base) {
    357  1.13  christos 		printf("WARNING: bad date in battery clock\n");
    358   1.1       leo 		timbuf = base;
    359   1.1       leo 	}
    360   1.1       leo 
    361   1.1       leo 	/* Battery clock does not store usec's, so forget about it. */
    362  1.11       leo 	time.tv_sec  = timbuf;
    363  1.11       leo 	time.tv_usec = 0;
    364   1.1       leo }
    365   1.1       leo 
    366   1.9       leo void
    367   1.1       leo resettodr()
    368   1.1       leo {
    369   1.1       leo 	if(settod(time.tv_sec) == 1)
    370   1.1       leo 		return;
    371  1.13  christos 	printf("Cannot set battery backed clock\n");
    372   1.1       leo }
    373   1.1       leo 
    374   1.1       leo static	char	dmsize[12] =
    375   1.1       leo {
    376   1.1       leo 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
    377   1.1       leo };
    378   1.1       leo 
    379   1.1       leo static	char	ldmsize[12] =
    380   1.1       leo {
    381   1.1       leo 	31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
    382   1.1       leo };
    383   1.1       leo 
    384   1.1       leo static u_long
    385   1.1       leo gettod()
    386   1.1       leo {
    387   1.3       leo 	int		i, sps;
    388   1.3       leo 	u_long		new_time = 0;
    389   1.3       leo 	char		*msize;
    390   1.3       leo 	mc_todregs	clkregs;
    391   1.3       leo 
    392   1.3       leo 	sps = splhigh();
    393   1.3       leo 	MC146818_GETTOD(RTC, &clkregs);
    394   1.3       leo 	splx(sps);
    395   1.1       leo 
    396   1.9       leo 	if(clkregs[MC_SEC] > 59)
    397   1.8       leo 		return(0);
    398   1.9       leo 	if(clkregs[MC_MIN] > 59)
    399   1.8       leo 		return(0);
    400   1.9       leo 	if(clkregs[MC_HOUR] > 23)
    401   1.1       leo 		return(0);
    402   1.3       leo 	if(range_test(clkregs[MC_DOM], 1, 31))
    403   1.1       leo 		return(0);
    404   1.3       leo 	if (range_test(clkregs[MC_MONTH], 1, 12))
    405   1.1       leo 		return(0);
    406   1.9       leo 	if(clkregs[MC_YEAR] > (2000 - GEMSTARTOFTIME))
    407   1.1       leo 		return(0);
    408   1.3       leo 	clkregs[MC_YEAR] += GEMSTARTOFTIME;
    409   1.1       leo 
    410   1.3       leo 	for(i = BSDSTARTOFTIME; i < clkregs[MC_YEAR]; i++) {
    411   1.1       leo 		if(is_leap(i))
    412   1.1       leo 			new_time += 366;
    413   1.1       leo 		else new_time += 365;
    414   1.1       leo 	}
    415   1.1       leo 
    416   1.3       leo 	msize = is_leap(clkregs[MC_YEAR]) ? ldmsize : dmsize;
    417   1.3       leo 	for(i = 0; i < (clkregs[MC_MONTH] - 1); i++)
    418   1.1       leo 		new_time += msize[i];
    419   1.3       leo 	new_time += clkregs[MC_DOM] - 1;
    420   1.3       leo 	new_time *= SECS_DAY;
    421   1.3       leo 	new_time += (clkregs[MC_HOUR] * 3600) + (clkregs[MC_MIN] * 60);
    422   1.3       leo 	return(new_time + clkregs[MC_SEC]);
    423   1.1       leo }
    424   1.1       leo 
    425   1.1       leo static int
    426   1.1       leo settod(newtime)
    427   1.1       leo u_long	newtime;
    428   1.1       leo {
    429   1.1       leo 	register long	days, rem, year;
    430   1.1       leo 	register char	*ml;
    431   1.3       leo 		 int	sps, sec, min, hour, month;
    432   1.3       leo 	mc_todregs	clkregs;
    433   1.1       leo 
    434   1.3       leo 	/* Number of days since Jan. 1 'BSDSTARTOFTIME'	*/
    435   1.1       leo 	days = newtime / SECS_DAY;
    436   1.1       leo 	rem  = newtime % SECS_DAY;
    437   1.1       leo 
    438   1.1       leo 	/*
    439   1.1       leo 	 * Calculate sec, min, hour
    440   1.1       leo 	 */
    441   1.1       leo 	hour = rem / SECS_HOUR;
    442   1.1       leo 	rem %= SECS_HOUR;
    443   1.1       leo 	min  = rem / 60;
    444   1.1       leo 	sec  = rem % 60;
    445   1.1       leo 
    446   1.1       leo 	/*
    447   1.1       leo 	 * Figure out the year. Day in year is left in 'days'.
    448   1.1       leo 	 */
    449   1.3       leo 	year = BSDSTARTOFTIME;
    450   1.1       leo 	while(days >= (rem = is_leap(year) ? 366 : 365)) {
    451   1.3       leo 		++year;
    452   1.3       leo 		days -= rem;
    453   1.1       leo 	}
    454   1.1       leo 
    455   1.1       leo 	/*
    456   1.1       leo 	 * Determine the month
    457   1.1       leo 	 */
    458   1.1       leo 	ml = is_leap(year) ? ldmsize : dmsize;
    459   1.1       leo 	for(month = 0; days >= ml[month]; ++month)
    460   1.1       leo 		days -= ml[month];
    461   1.1       leo 
    462   1.1       leo 	/*
    463   1.1       leo 	 * Now that everything is calculated, program the RTC
    464   1.1       leo 	 */
    465   1.3       leo 	mc146818_write(RTC, MC_REGA, MC_BASE_32_KHz);
    466   1.3       leo 	mc146818_write(RTC, MC_REGB, MC_REGB_24HR | MC_REGB_BINARY);
    467   1.3       leo 	sps = splhigh();
    468   1.3       leo 	MC146818_GETTOD(RTC, &clkregs);
    469   1.3       leo 	clkregs[MC_SEC]   = sec;
    470   1.3       leo 	clkregs[MC_MIN]   = min;
    471   1.3       leo 	clkregs[MC_HOUR]  = hour;
    472   1.3       leo 	clkregs[MC_DOM]   = days+1;
    473   1.3       leo 	clkregs[MC_MONTH] = month+1;
    474   1.3       leo 	clkregs[MC_YEAR]  = year - GEMSTARTOFTIME;
    475   1.3       leo 	MC146818_PUTTOD(RTC, &clkregs);
    476   1.3       leo 	splx(sps);
    477   1.1       leo 
    478   1.1       leo 	return(1);
    479   1.1       leo }
    480