205 lines
4.3 KiB
C
205 lines
4.3 KiB
C
/* this provides a device interface to the realtime clock
|
|
used on the A3000.
|
|
|
|
To support different clocks: the config file defines a
|
|
realtime clock "rtclock". Write your own driver that if
|
|
matched by existing hardware returns 1 from its init
|
|
function, and set the function pointer "gettod" to
|
|
a function returning the number of seconds elapsed since
|
|
1970-1-1.
|
|
|
|
TODO: could add read-write interface to turn this into
|
|
a real /dev/rtclock device, that would allow reading
|
|
and setting of the clock very easily. */
|
|
|
|
#include "rtclocka.h"
|
|
#if NRTCLOCKA > 0
|
|
|
|
#include "sys/param.h"
|
|
#include "sys/systm.h"
|
|
#include "sys/buf.h"
|
|
#include "sys/dkstat.h"
|
|
#include "sys/disklabel.h"
|
|
#include "sys/malloc.h"
|
|
#include "sys/proc.h"
|
|
#include "sys/reboot.h"
|
|
#include "sys/file.h"
|
|
|
|
#include "device.h"
|
|
#include "rtclocka_var.h"
|
|
|
|
int rtclockainit (register struct amiga_device *ad);
|
|
|
|
static long rtgettod ();
|
|
static int rtsettod ();
|
|
|
|
/* amiga/clock.c calls thru this vector, if it is set, to read
|
|
the realtime clock */
|
|
extern long (*gettod)();
|
|
extern int (*settod)();
|
|
|
|
/* since there's only one such clock on the A3000, we can
|
|
savely store its address in a static variable */
|
|
static struct rtclock3000 *rt = 0;
|
|
|
|
struct driver rtclockadriver = {
|
|
rtclockainit, "rtclock"
|
|
};
|
|
|
|
|
|
int
|
|
rtclockainit (register struct amiga_device *ad)
|
|
{
|
|
/* verify we're indeed present */
|
|
if (ad->amiga_addr)
|
|
{
|
|
rt = (struct rtclock3000 *) ad->amiga_addr;
|
|
if (rtgettod ())
|
|
{
|
|
gettod = rtgettod;
|
|
settod = rtsettod;
|
|
printf ("Realtime clock A3000\n");
|
|
return 1;
|
|
}
|
|
else
|
|
printf ("Realtime clock A3000 malfunctioning, ignored.\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int month_days[12] = {
|
|
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
|
};
|
|
|
|
static long
|
|
rtgettod ()
|
|
{
|
|
register int i;
|
|
register u_long tmp;
|
|
int year, month, day, hour, min, sec;
|
|
|
|
/* hold clock */
|
|
rt->control1 = CONTROL1_HOLD_CLOCK;
|
|
|
|
/* read it */
|
|
sec = rt->second1 * 10 + rt->second2;
|
|
min = rt->minute1 * 10 + rt->minute2;
|
|
hour = rt->hour1 * 10 + rt->hour2;
|
|
day = rt->day1 * 10 + rt->day2;
|
|
month = rt->month1 * 10 + rt->month2;
|
|
year = rt->year1 * 10 + rt->year2 + 1900;
|
|
|
|
/* let it run again.. */
|
|
rt->control1 = CONTROL1_FREE_CLOCK;
|
|
|
|
#if 0
|
|
printf ("rt: sec=%d, min=%d, hour=%d, day=%d, mon=%d, year=%d\n",
|
|
sec, min, hour, day, month, year);
|
|
#endif
|
|
|
|
range_test(hour, 0, 23);
|
|
range_test(day, 1, 31);
|
|
range_test(month, 1, 12);
|
|
range_test(year, STARTOFTIME, 2000);
|
|
|
|
tmp = 0;
|
|
|
|
for (i = STARTOFTIME; i < year; i++)
|
|
tmp += days_in_year(i);
|
|
if (leapyear(year) && month > FEBRUARY)
|
|
tmp++;
|
|
|
|
for (i = 1; i < month; i++)
|
|
tmp += days_in_month(i);
|
|
|
|
tmp += (day - 1);
|
|
tmp = ((tmp * 24 + hour) * 60 + min) * 60 + sec;
|
|
|
|
return tmp;
|
|
}
|
|
|
|
|
|
int
|
|
rtsettod (tim)
|
|
long tim;
|
|
{
|
|
/* I don't know if setting the clock is analogous
|
|
to reading it, I don't have demo-code for setting.
|
|
just give it a try.. */
|
|
|
|
register int i;
|
|
register long hms, day;
|
|
u_char sec1, sec2;
|
|
u_char min1, min2;
|
|
u_char hour1, hour2;
|
|
u_char day1, day2;
|
|
u_char mon1, mon2;
|
|
u_char year1, year2;
|
|
|
|
/* there seem to be problems with the bitfield addressing
|
|
currently used.. */
|
|
return 0;
|
|
|
|
if (! rt)
|
|
return 0;
|
|
|
|
/* prepare values to be written to clock */
|
|
day = tim / SECDAY;
|
|
hms = tim % SECDAY;
|
|
|
|
|
|
hour2 = hms / 3600;
|
|
hour1 = hour2 / 10;
|
|
hour2 %= 10;
|
|
|
|
min2 = (hms % 3600) / 60;
|
|
min1 = min2 / 10;
|
|
min2 %= 10;
|
|
|
|
|
|
sec2 = (hms % 3600) % 60;
|
|
sec1 = sec2 / 10;
|
|
sec2 %= 10;
|
|
|
|
/* Number of years in days */
|
|
for (i = STARTOFTIME - 1900; day >= days_in_year(i); i++)
|
|
day -= days_in_year(i);
|
|
year1 = i / 10;
|
|
year2 = i % 10;
|
|
|
|
/* Number of months in days left */
|
|
if (leapyear(i))
|
|
days_in_month(FEBRUARY) = 29;
|
|
for (i = 1; day >= days_in_month(i); i++)
|
|
day -= days_in_month(i);
|
|
days_in_month(FEBRUARY) = 28;
|
|
|
|
mon1 = i / 10;
|
|
mon2 = i % 10;
|
|
|
|
/* Days are what is left over (+1) from all that. */
|
|
day ++;
|
|
day1 = day / 10;
|
|
day2 = day % 10;
|
|
|
|
rt->control1 = CONTROL1_HOLD_CLOCK;
|
|
rt->second1 = sec1;
|
|
rt->second2 = sec2;
|
|
rt->minute1 = min1;
|
|
rt->minute2 = min2;
|
|
rt->hour1 = hour1;
|
|
rt->hour2 = hour2;
|
|
rt->day1 = day1;
|
|
rt->day2 = day2;
|
|
rt->month1 = mon1;
|
|
rt->month2 = mon2;
|
|
rt->year1 = year1;
|
|
rt->year2 = year2;
|
|
rt->control2 = CONTROL1_FREE_CLOCK;
|
|
|
|
return 1;
|
|
}
|
|
#endif /* NRTCLOCKA */
|