/* DClockChip.c ************************************************************* * * DClockChip ---- Real time clock support routines for DClock. * * Author -------- Olaf 'Olsen' Barthel, MXM * Brabeckstrasse 35 * D-3000 Hannover 71 * * Federal Republic of Germany * * This program truly is in the PUBLIC DOMAIN. Written on a cold * and damp September evening, hoping the next morning would be * better. * * Compiled using Aztec C 5.0b, CygnusEd Professional 2 & ARexx. * ***************************************************************************/ /* Various definitions needed by the datestamp * conversion routine. */ #define MINS_PER_HOUR 60 #define SECS_PER_MIN 60 #define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR) #define SECS_PER_DAY (SECS_PER_HOUR * 24) #define TICS_PER_SEC 50 #define FEB 1 #define DAYS_PER_YEAR 365 #define YEARS_PER_LEAP 4 #define START_YEAR 1978 #define FIRST_LEAP_YEAR 1980 #define LEAP_ADJUST (FIRST_LEAP_YEAR - START_YEAR) #define LEAP_FEB_DAYS 29 #define NORM_FEB_DAYS 28 /* Alias names for clock chip registers. */ #define Clock_Second1 (clock . Second1 & 0xF) #define Clock_Second10 (clock . Second10 & 0xF) #define Clock_Minute1 (clock . Minute1 & 0xF) #define Clock_Minute10 (clock . Minute10 & 0xF) #define Clock_Hour1 (clock . Hour1 & 0xF) #define Clock_Hour10 (clock . Hour10 & 0xF) #define Clock_Day1 (clock . Day1 & 0xF) #define Clock_Day10 (clock . Day10 & 0xF) #define Clock_Month1 (clock . Month1 & 0xF) #define Clock_Month10 (clock . Month10 & 0xF) #define Clock_Year1 (clock . Year1 & 0xF) #define Clock_Year10 (clock . Year10 & 0xF) /* The builtin clock chip (OKI MSM624SRS) consists of * sixteen registers of which each contains four bits * of relevant information. The following structure * tries to come as close to the register map as * possible, even though bitfields would have been * the better approach. Unfortunately Aztec 'C' 5.0b * forces bitfields to be long word aligned rather than * word aligned which causes a whole lot of confusion. */ struct ClockChip { UWORD pad0; volatile UWORD Second1; UWORD pad1; volatile UWORD Second10; UWORD pad2; volatile UWORD Minute1; UWORD pad3; volatile UWORD Minute10; UWORD pad4; volatile UWORD Hour1; UWORD pad5; volatile UWORD Hour10; UWORD pad6; volatile UWORD Day1; UWORD pad7; volatile UWORD Day10; UWORD pad8; volatile UWORD Month1; UWORD pad9; volatile UWORD Month10; UWORD pad10; volatile UWORD Year1; UWORD pad11; volatile UWORD Year10; ULONG pad12; UWORD pad13; volatile UWORD Adjust; }; /* Easy way to access the builtin clock chip. */ #define clock (*((struct ClockChip *)0xdc0000)) /* DateToTimeVal(struct DateTag *Date,struct timeval *TimeVal): * * Converts the contents of a DateTag into a timeval * as used by timer.device. */ VOID DateToTimeVal(struct DateTag *Date,struct timeval *TimeVal) { LONG DaysElapsed,YearsElapsed,LeapYears; SHORT i; /* Number of days in each month. */ static UBYTE Months[12] = { 31,28,31,30, 31,30,31,31, 30,31,30,31 }; /* Is this a leap year? */ if(Date -> Year % YEARS_PER_LEAP) Months[FEB] = NORM_FEB_DAYS; else Months[FEB] = LEAP_FEB_DAYS; /* Calculate elapsed time. */ YearsElapsed = Date -> Year - START_YEAR; LeapYears = (YearsElapsed + LEAP_ADJUST - 1) / YEARS_PER_LEAP; DaysElapsed = (YearsElapsed * DAYS_PER_YEAR) + LeapYears; /* Add the days already passed in this year. */ for(i = 0; i < Date -> Month - 1 ; i++) DaysElapsed += Months[i]; /* Add the days in the current month. */ DaysElapsed += Date -> Day - 1; /* Calculate number of seconds. */ TimeVal -> tv_secs = DaysElapsed * SECS_PER_DAY + (Date -> Hour * MINS_PER_HOUR + Date -> Minute) * SECS_PER_MIN + Date -> Second; TimeVal -> tv_micro = 0; } /* ReadClock(): * * Read the system clock and set the system time * accordingly. */ BYTE ReadClock() { struct MsgPort *TimePort; struct timerequest *TimeRequest; struct DateTag Date; UBYTE LastTick; BYTE Success = FALSE; /* Check the second timer. */ LastTick = Clock_Second1; /* Wait two seconds. */ Delay(TICS_PER_SEC * 2); /* If the value has changed, we have a * clock chip installed. */ if(LastTick != Clock_Second1) { if(TimePort = CreatePort(NULL,0)) { if(TimeRequest = (struct timerequest *)CreateExtIO(TimePort,sizeof(struct timerequest))) { if(!OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,0)) { TimeRequest -> tr_node . io_Command = TR_SETSYSTIME; Forbid(); /* Stop the clock. */ clock . Adjust |= 1; /* Wait for it to calm down. */ while(clock . Adjust & 2); /* Convert the clock entries into a DateTag. */ Date . Year = (Clock_Year10 < 7 ? 10 + Clock_Year10 : Clock_Year10) * 10 + Clock_Year1 + 1900; Date . Month = Clock_Month10 * 10 + Clock_Month1; Date . Day = Clock_Day10 * 10 + Clock_Day1; Date . Hour = Clock_Hour10 * 10 + Clock_Hour1; Date . Minute = Clock_Minute10 * 10 + Clock_Minute1; Date . Second = Clock_Second10 * 10 + Clock_Second1; /* Restart the clock. */ clock . Adjust &= ~1; DateToTimeVal(&Date,&TimeRequest -> tr_time); /* Set the system time. */ DoIO(TimeRequest); Permit(); Success = TRUE; CloseDevice(TimeRequest); } DeleteExtIO(TimeRequest); } DeletePort(TimePort); } } return(Success); }