From f47aa04a30b2784cc62df1af692612299670924f Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Fri, 12 Jan 2007 16:35:04 +0000 Subject: [PATCH] . removed readclock command and cmos driver. . replaced by a readclock 'driver' that runs once, a re-imported version of the minix 2.0.4 readclock command. . this has also restored cmos writing. . readclock wrapper script calls service command to run /bin/readclock.drv once. --- commands/ibm/Makefile | 13 - commands/ibm/readclock.c | 226 --------------- commands/scripts/MAKEDEV.sh | 8 +- commands/scripts/Makefile | 4 + commands/scripts/readclock.sh | 5 + drivers/Makefile | 2 +- drivers/cmos/cmos.c | 283 ------------------ drivers/{cmos => readclock}/Makefile | 25 +- drivers/readclock/readclock.c | 412 +++++++++++++++++++++++++++ etc/Makefile | 2 +- etc/drivers.conf | 4 +- etc/rc | 1 - 12 files changed, 435 insertions(+), 550 deletions(-) delete mode 100755 commands/ibm/readclock.c create mode 100644 commands/scripts/readclock.sh delete mode 100644 drivers/cmos/cmos.c rename drivers/{cmos => readclock}/Makefile (54%) create mode 100644 drivers/readclock/readclock.c diff --git a/commands/ibm/Makefile b/commands/ibm/Makefile index f251b80a8..95337f1a6 100755 --- a/commands/ibm/Makefile +++ b/commands/ibm/Makefile @@ -20,7 +20,6 @@ ALL = \ partition \ playwave \ postmort \ - readclock \ recwave \ repartition \ screendump \ @@ -76,10 +75,6 @@ postmort: postmort.c $(CCLD) -o $@ $? install -S 4kw $@ -readclock: readclock.c - $(CCLD) -o $@ $? - install -S 4kw $@ - recwave: recwave.c $(CCLD) -o $@ $? install -S 16kw $@ @@ -111,13 +106,11 @@ install: \ /usr/bin/partition \ /usr/bin/playwave \ /usr/bin/postmort \ - /usr/bin/readclock \ /usr/bin/recwave \ /usr/bin/repartition \ /usr/bin/screendump \ /usr/bin/sdump \ /bin/loadkeys \ - /bin/readclock \ /usr/bin/atnormalize: atnormalize install -cs -o bin $? $@ @@ -158,9 +151,6 @@ install: \ /usr/bin/postmort: postmort install -cs -o bin $? $@ -/usr/bin/readclock: readclock - install -cs -o bin $? $@ - /usr/bin/recwave: recwave install -cs -o bin $? $@ @@ -176,8 +166,5 @@ install: \ /bin/loadkeys: /usr/bin/loadkeys install -lcs $? $@ -/bin/readclock: /usr/bin/readclock - install -lcs $? $@ - clean: rm -rf $(ALL) a.out core diff --git a/commands/ibm/readclock.c b/commands/ibm/readclock.c deleted file mode 100755 index f4a51864e..000000000 --- a/commands/ibm/readclock.c +++ /dev/null @@ -1,226 +0,0 @@ -/* setime - set the system time from the real time clock - Authors: T. Holm & E. Froese - Adapted by: Jorrit .N. Herder */ - -/************************************************************************/ -/* Readclock was updated for security reasons: openeing /dev/mem no */ -/* longer automatically grants I/O privileges to the calling process */ -/* so that the CMOS' clock could not be read from this program. The */ -/* new approach is to rely on the FS to do the CMOS I/O, via the new */ -/* system call CMOSTIME (which only reads the current clock value and */ -/* cannot update the CMOS clock). */ -/* The original readclock.c is still available under backup.c. */ -/************************************************************************/ -/* */ -/* readclock.c */ -/* */ -/* Read the clock value from the 64 byte CMOS RAM */ -/* area, then set system time. */ -/* */ -/* If the machine ID byte is 0xFC or 0xF8, the device */ -/* /dev/mem exists and can be opened for reading, */ -/* and no errors in the CMOS RAM are reported by the */ -/* RTC, then the time is read from the clock RAM */ -/* area maintained by the RTC. */ -/* */ -/* The clock RAM values are decoded and fed to mktime */ -/* to make a time_t value, then stime(2) is called. */ -/* */ -/* This fails if: */ -/* */ -/* If the machine ID does not match 0xFC or 0xF8 (no */ -/* error message.) */ -/* */ -/* If the machine ID is 0xFC or 0xF8 and /dev/mem */ -/* is missing, or cannot be accessed. */ -/* */ -/* If the RTC reports errors in the CMOS RAM. */ -/* */ -/************************************************************************/ -/* origination 1987-Dec-29 efth */ -/* robustness 1990-Oct-06 C. Sylvain */ -/* incorp. B. Evans ideas 1991-Jul-06 C. Sylvain */ -/* set time & calibrate 1992-Dec-17 Kees J. Bot */ -/* clock timezone 1993-Oct-10 Kees J. Bot */ -/* set CMOS clock 1994-Jun-12 Kees J. Bot */ -/* removed set CMOS 2004-Sep-06 Jorrit N. Herder */ -/************************************************************************/ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_RETRIES 1 - -int nflag = 0; /* Tell what, but don't do it. */ -int y2kflag = 0; /* Interpret 1980 as 2000 for clock with Y2K bug. */ - -char clocktz[128]; /* Timezone of the clock. */ - -#define MACH_ID_ADDR 0xFFFFE /* BIOS Machine ID at FFFF:000E */ - -#define PC_AT 0xFC /* Machine ID byte for PC/AT, - PC/XT286, and PS/2 Models 50, 60 */ -#define PS_386 0xF8 /* Machine ID byte for PS/2 Model 80 */ - -/* Manufacturers usually use the ID value of the IBM model they emulate. - * However some manufacturers, notably HP and COMPAQ, have had different - * ideas in the past. - * - * Machine ID byte information source: - * _The Programmer's PC Sourcebook_ by Thom Hogan, - * published by Microsoft Press - */ - -void errmsg(char *s); -int bcd_to_dec(int n); -int dec_to_bcd(int n); -void usage(void); - -#define CMOS_DEV "/dev/cmos" - -PUBLIC int main(int argc, char **argv) -{ - int fd; - struct tm time1; - struct tm time2; - struct tm tmnow; - char date[64]; - time_t now, rtc; - int i, s, mem; - unsigned char mach_id, cmos_state; - struct sysgetenv sysgetenv; - message m; - int request; - - - /* Process options. */ - while (argc > 1) { - char *p = *++argv; - - if (*p++ != '-') usage(); - - while (*p != 0) { - switch (*p++) { - case 'n': nflag = 1; break; - case '2': y2kflag = 1; break; - default: usage(); - } - } - argc--; - } - -#if DEAD_CODE - /* The hardware clock may run in a different time zone, likely GMT or - * winter time. Select that time zone. - */ - strcpy(clocktz, "TZ="); - sysgetenv.key = "TZ"; - sysgetenv.keylen = 2+1; - sysgetenv.val = clocktz+3; - sysgetenv.vallen = sizeof(clocktz)-3; - if (svrctl(SYSGETENV, &sysgetenv) == 0) { - putenv(clocktz); - tzset(); - } -#endif - - /* Read the CMOS real time clock. */ - for (i = 0; i < MAX_RETRIES; i++) { - - /* sleep, unless first iteration */ - if (i > 0) sleep(5); - - /* Open the CMOS device to read the system time. */ - if ((fd = open(CMOS_DEV, O_RDONLY)) < 0) { - perror(CMOS_DEV); - fprintf(stderr, "Couldn't open CMOS device.\n"); - exit(1); - } - request = (y2kflag) ? CIOCGETTIME : CIOCGETTIMEY2K; - if ((s=ioctl(fd, request, (void *) &time1)) < 0) { - perror("ioctl"); - fprintf(stderr, "Couldn't do CMOS ioctl.\n"); - exit(1); - } - close(fd); - - now = time(NULL); - - time1.tm_isdst = -1; /* Do timezone calculations. */ - time2 = time1; - - rtc= mktime(&time1); /* Transform to a time_t. */ - if (rtc != -1) { - break; - } - - fprintf(stderr, -"readclock: Invalid time read from CMOS RTC: %d-%02d-%02d %02d:%02d:%02d\n", - time2.tm_year+1900, time2.tm_mon+1, time2.tm_mday, - time2.tm_hour, time2.tm_min, time2.tm_sec); - } - if (i >= MAX_RETRIES) exit(1); - - /* Now set system time. */ - if (nflag) { - printf("stime(%lu)\n", (unsigned long) rtc); - } else { - if (stime(&rtc) < 0) { - errmsg( "Not allowed to set time." ); - exit(1); - } - } - tmnow = *localtime(&rtc); - if (strftime(date, sizeof(date), - "%a %b %d %H:%M:%S %Z %Y", &tmnow) != 0) { - if (date[8] == '0') date[8]= ' '; -#if 0 - printf("%s [CMOS read via FS, see command/ibm/readclock.c]\n", date); -#endif - } - exit(0); -} - -void errmsg(char *s) -{ - static char *prompt = "readclock: "; - - fprintf(stderr, "%s%s\n", prompt, s); - prompt = ""; -} - - -int bcd_to_dec(int n) -{ - return ((n >> 4) & 0x0F) * 10 + (n & 0x0F); -} - -int dec_to_bcd(int n) -{ - return ((n / 10) << 4) | (n % 10); -} - -void usage(void) -{ - fprintf(stderr, "Usage: settime [-n2]\n"); - exit(1); -} diff --git a/commands/scripts/MAKEDEV.sh b/commands/scripts/MAKEDEV.sh index 12e6d4182..efc547298 100755 --- a/commands/scripts/MAKEDEV.sh +++ b/commands/scripts/MAKEDEV.sh @@ -19,7 +19,7 @@ case $#:$1 in ttypa ttypb ttypc ttypd ttype ttypf \ ttyq0 ttyq1 ttyq2 ttyq3 ttyq4 ttyq5 ttyq6 ttyq7 ttyq8 ttyq9 \ ttyqa ttyqb ttyqc ttyqd ttyqe ttyqf \ - eth klog random cmos rescue + eth klog random rescue ;; 0:|1:-\?) cat >&2 < -#include -#include -#include -#include - -extern int errno; /* error number for PM calls */ - -FORWARD _PROTOTYPE( int gettime, (int who, int y2kflag, vir_bytes dst_time, int safe)); -FORWARD _PROTOTYPE( void reply, (int reply, int replyee, int proc, cp_grant_id_t, int s)); - -FORWARD _PROTOTYPE( int read_register, (int register_address)); -FORWARD _PROTOTYPE( int get_cmostime, (struct tm *tmp, int y2kflag)); -FORWARD _PROTOTYPE( int dec_to_bcd, (int dec)); -FORWARD _PROTOTYPE( int bcd_to_dec, (int bcd)); - -/*===========================================================================* - * main * - *===========================================================================*/ -PUBLIC void main(void) -{ - message m; - int y2kflag; - int result; - int suspended = NONE; - cp_grant_id_t susp_grant = GRANT_INVALID; - int s; - - while(TRUE) { - int safe = 0; - - /* Get work. */ - if (OK != (s=receive(ANY, &m))) - panic("CMOS", "attempt to receive work failed", s); - - /* Handle request. */ - switch(m.m_type) { - - case DEV_OPEN: - case DEV_CLOSE: - case CANCEL: - reply(TASK_REPLY, m.m_source, m.IO_ENDPT, GRANT_INVALID, OK); - break; - - case DEV_PING: - notify(m.m_source); - break; - case DEV_IOCTL_S: - safe=1; - /* Fall through. */ - case DEV_IOCTL: - - /* Probably best to SUSPEND the caller, CMOS I/O has nasty timeouts. - * This way we don't block the rest of the system. First check if - * another process is already suspended. We cannot handle multiple - * requests at a time. - */ - if (suspended != NONE) { - reply(TASK_REPLY, m.m_source, m.IO_ENDPT, GRANT_INVALID, EBUSY); - break; - } - suspended = m.IO_ENDPT; - susp_grant = (cp_grant_id_t) m.IO_GRANT; - reply(TASK_REPLY, m.m_source, m.IO_ENDPT, susp_grant, SUSPEND); - - switch(m.REQUEST) { - case CIOCGETTIME: /* get CMOS time */ - case CIOCGETTIMEY2K: - y2kflag = (m.REQUEST == CIOCGETTIME) ? 0 : 1; - result = gettime(m.IO_ENDPT, y2kflag, (vir_bytes) m.ADDRESS, safe); - break; - case CIOCSETTIME: - case CIOCSETTIMEY2K: - default: /* unsupported ioctl */ - result = ENOSYS; - } - - /* Request completed. Tell the caller to check our status. */ - notify(m.m_source); - break; - - case DEV_STATUS: - - /* The FS calls back to get our status. Revive the suspended - * processes and return the status of reading the CMOS. - */ - if (suspended == NONE) - reply(DEV_NO_STATUS, m.m_source, NONE, GRANT_INVALID, OK); - else - reply(DEV_REVIVE, m.m_source, suspended, susp_grant, result); - suspended = NONE; - break; - - case SYN_ALARM: /* shouldn't happen */ - case SYS_SIG: /* ignore system events */ - continue; - - default: - reply(TASK_REPLY, m.m_source, m.IO_ENDPT, GRANT_INVALID, EINVAL); - } - } -} - -/*===========================================================================* - * reply * - *===========================================================================*/ -PRIVATE void reply(int code, int replyee, int process, cp_grant_id_t grantid, int status) -{ - message m; - int s; - - m.m_type = code; /* TASK_REPLY or REVIVE */ - m.REP_STATUS = status; /* result of device operation */ - m.REP_ENDPT = process; /* which user made the request */ - m.REP_IO_GRANT = grantid; /* I/O grant on which to unSUSPEND */ - if (OK != (s=send(replyee, &m))) - panic("CMOS", "sending reply failed", s); -} - -/*===========================================================================* - * gettime * - *===========================================================================*/ -PRIVATE int gettime(int who, int y2kflag, vir_bytes dst_time, int safe) -{ - unsigned char mach_id, cmos_state; - struct tm time1; - int i, s; - - /* First obtain the machine ID to see if we can read the CMOS clock. Only - * for PS_386 and PC_AT this is possible. Otherwise, return an error. - */ - s = sys_readbios( MACHINE_ID_ADDR, &mach_id, MACHINE_ID_SIZE); - if (s != 0) { - printf("gettime: sys_readbios failed: %d\n", s); - return EINVAL; - } - if (mach_id != PS_386_MACHINE && mach_id != PC_AT_MACHINE) { - printf("gettime: machine ID unknown. ID byte = %02x.\n", mach_id); - return(EFAULT); - } - - /* Now check the CMOS' state to see if we can read a proper time from it. - * If the state is crappy, return an error. - */ - cmos_state = read_register(CMOS_STATUS); - if (cmos_state & (CS_LOST_POWER | CS_BAD_CHKSUM | CS_BAD_TIME)) { - printf( "IS: CMOS RAM error(s) found. State = 0x%02x\n", cmos_state ); - if (cmos_state & CS_LOST_POWER) - printf("IS: RTC lost power. Reset CMOS RAM with SETUP." ); - if (cmos_state & CS_BAD_CHKSUM) - printf("IS: CMOS RAM checksum is bad. Run SETUP." ); - if (cmos_state & CS_BAD_TIME) - printf("IS: Time invalid in CMOS RAM. Reset clock." ); - return(EFAULT); - } - - /* Everything seems to be OK. Read the CMOS real time clock and copy the - * result back to the caller. - */ - if (get_cmostime(&time1, y2kflag) != 0) - return(EFAULT); - - /* Copy result back, safely or not. */ - if(safe) { - sys_safecopyto(who, dst_time, 0, (vir_bytes) &time1, - sizeof(struct tm), D); - } else { - sys_datacopy(SELF, (vir_bytes) &time1, - who, dst_time, sizeof(struct tm)); - } - - return(OK); -} - -PRIVATE int get_cmostime(struct tm *t, int y2kflag) -{ -/* Update the structure pointed to by time with the current time as read - * from CMOS RAM of the RTC. If necessary, the time is converted into a - * binary format before being stored in the structure. - */ - int osec, n; - unsigned long i; - clock_t t0,t1; - - /* Start a timer to keep us from getting stuck on a dead clock. */ - getuptime(&t0); - do { - osec = -1; - n = 0; - do { - getuptime(&t1); - if (t1-t0 > 5*HZ) { - printf("readclock: CMOS clock appears dead\n"); - return(1); - } - - /* Clock update in progress? */ - if (read_register(RTC_REG_A) & RTC_A_UIP) continue; - - t->tm_sec = read_register(RTC_SEC); - if (t->tm_sec != osec) { - /* Seconds changed. First from -1, then because the - * clock ticked, which is what we're waiting for to - * get a precise reading. - */ - osec = t->tm_sec; - n++; - } - } while (n < 2); - - /* Read the other registers. */ - t->tm_min = read_register(RTC_MIN); - t->tm_hour = read_register(RTC_HOUR); - t->tm_mday = read_register(RTC_MDAY); - t->tm_mon = read_register(RTC_MONTH); - t->tm_year = read_register(RTC_YEAR); - - /* Time stable? */ - } while (read_register(RTC_SEC) != t->tm_sec - || read_register(RTC_MIN) != t->tm_min - || read_register(RTC_HOUR) != t->tm_hour - || read_register(RTC_MDAY) != t->tm_mday - || read_register(RTC_MONTH) != t->tm_mon - || read_register(RTC_YEAR) != t->tm_year); - - if ((read_register(RTC_REG_B) & RTC_B_DM_BCD) == 0) { - /* Convert BCD to binary (default RTC mode). */ - t->tm_year = bcd_to_dec(t->tm_year); - t->tm_mon = bcd_to_dec(t->tm_mon); - t->tm_mday = bcd_to_dec(t->tm_mday); - t->tm_hour = bcd_to_dec(t->tm_hour); - t->tm_min = bcd_to_dec(t->tm_min); - t->tm_sec = bcd_to_dec(t->tm_sec); - } - t->tm_mon--; /* Counts from 0. */ - - /* Correct the year, good until 2080. */ - if (t->tm_year < 80) t->tm_year += 100; - - if (y2kflag) { - /* Clock with Y2K bug, interpret 1980 as 2000, good until 2020. */ - if (t->tm_year < 100) t->tm_year += 20; - } - return 0; -} - -PRIVATE int read_register(int reg_addr) -{ -/* Read a single CMOS register value. */ - unsigned long r; - sys_outb(RTC_INDEX, reg_addr); - sys_inb(RTC_IO, &r); - return r; -} - -PRIVATE int bcd_to_dec(int n) -{ - return ((n >> 4) & 0x0F) * 10 + (n & 0x0F); -} - -PRIVATE int dec_to_bcd(int n) -{ - return ((n / 10) << 4) | (n % 10); -} - diff --git a/drivers/cmos/Makefile b/drivers/readclock/Makefile similarity index 54% rename from drivers/cmos/Makefile rename to drivers/readclock/Makefile index 8be22f40b..04a252a61 100644 --- a/drivers/cmos/Makefile +++ b/drivers/readclock/Makefile @@ -1,25 +1,17 @@ -# Makefile for the CMOS driver -DRIVER = cmos - -# directories -u = /usr -i = $u/include -s = $i/sys -m = $i/minix -b = $i/ibm -d = .. +# Makefile for readclock 'driver' +DRIVER = readclock.drv # programs, flags, etc. MAKE = exec make CC = exec cc -CFLAGS = -I$i $(CPROFILE) -LDFLAGS = -i -L../libdriver -LIBS = -lsysutil -lsys -ldriver +CFLAGS=-D_MINIX=1 -D_POSIX_SOURCE=1 -D_SYSTEM=1 +LDFLAGS = -i +LIBS = -lsysutil -lsys -OBJ = cmos.o +OBJ = readclock.o # build local binary -all build: $(DRIVER) +all build: $(DRIVER) $(DRIVER): $(OBJ) $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) install -S 8k $(DRIVER) @@ -33,9 +25,8 @@ install: /sbin/$(DRIVER) clean: rm -f $(DRIVER) *.o *.bak - depend: - /usr/bin/mkdep "$(CC) -E $(CPPFLAGS)" *.c ../libdriver/*.c > .depend + /usr/bin/mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend # Include generated dependencies. include .depend diff --git a/drivers/readclock/readclock.c b/drivers/readclock/readclock.c new file mode 100644 index 000000000..b2cb6b2da --- /dev/null +++ b/drivers/readclock/readclock.c @@ -0,0 +1,412 @@ +/* readclock - read the real time clock Authors: T. Holm & E. Froese + * + * Changed to be user-space driver. + */ + +/************************************************************************/ +/* */ +/* readclock.c */ +/* */ +/* Read the clock value from the 64 byte CMOS RAM */ +/* area, then set system time. */ +/* */ +/* If the machine ID byte is 0xFC or 0xF8, the device */ +/* /dev/mem exists and can be opened for reading, */ +/* and no errors in the CMOS RAM are reported by the */ +/* RTC, then the time is read from the clock RAM */ +/* area maintained by the RTC. */ +/* */ +/* The clock RAM values are decoded and fed to mktime */ +/* to make a time_t value, then stime(2) is called. */ +/* */ +/* This fails if: */ +/* */ +/* If the machine ID does not match 0xFC or 0xF8 (no */ +/* error message.) */ +/* */ +/* If the machine ID is 0xFC or 0xF8 and /dev/mem */ +/* is missing, or cannot be accessed. */ +/* */ +/* If the RTC reports errors in the CMOS RAM. */ +/* */ +/************************************************************************/ +/* origination 1987-Dec-29 efth */ +/* robustness 1990-Oct-06 C. Sylvain */ +/* incorp. B. Evans ideas 1991-Jul-06 C. Sylvain */ +/* set time & calibrate 1992-Dec-17 Kees J. Bot */ +/* clock timezone 1993-Oct-10 Kees J. Bot */ +/* set CMOS clock 1994-Jun-12 Kees J. Bot */ +/************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int nflag = 0; /* Tell what, but don't do it. */ +int wflag = 0; /* Set the CMOS clock. */ +int Wflag = 0; /* Also set the CMOS clock register bits. */ +int y2kflag = 0; /* Interpret 1980 as 2000 for clock with Y2K bug. */ + +char clocktz[128]; /* Timezone of the clock. */ + +#define MACH_ID_ADDR 0xFFFFE /* BIOS Machine ID at FFFF:000E */ + +#define PC_AT 0xFC /* Machine ID byte for PC/AT, + PC/XT286, and PS/2 Models 50, 60 */ +#define PS_386 0xF8 /* Machine ID byte for PS/2 Model 80 */ + +/* Manufacturers usually use the ID value of the IBM model they emulate. + * However some manufacturers, notably HP and COMPAQ, have had different + * ideas in the past. + * + * Machine ID byte information source: + * _The Programmer's PC Sourcebook_ by Thom Hogan, + * published by Microsoft Press + */ + +void errmsg(char *s); +void get_time(struct tm *t); +int read_register(int reg_addr); +void set_time(struct tm *t); +void write_register(int reg_addr, int value); +int bcd_to_dec(int n); +int dec_to_bcd(int n); +void usage(void); + +int main(int argc, char **argv) +{ + struct tm time1; + struct tm time2; + struct tm tmnow; + char date[64]; + time_t now, rtc; + int i, s; + unsigned char mach_id, cmos_state; + struct sysgetenv sysgetenv; + + if((s=sys_readbios(MACH_ID_ADDR, &mach_id, sizeof(mach_id))) != OK) { + printf("readclock: sys_readbios failed: %d.\n", s); + exit(1); + } + + if (mach_id != PS_386 && mach_id != PC_AT) { + errmsg("Machine ID unknown." ); + printf("Machine ID byte = %02x\n", mach_id ); + + exit(1); + } + + cmos_state = read_register(CMOS_STATUS); + + if (cmos_state & (CS_LOST_POWER | CS_BAD_CHKSUM | CS_BAD_TIME)) { + errmsg( "CMOS RAM error(s) found..." ); + printf("CMOS state = 0x%02x\n", cmos_state ); + + if (cmos_state & CS_LOST_POWER) + errmsg( "RTC lost power. Reset CMOS RAM with SETUP." ); + if (cmos_state & CS_BAD_CHKSUM) + errmsg( "CMOS RAM checksum is bad. Run SETUP." ); + if (cmos_state & CS_BAD_TIME) + errmsg( "Time invalid in CMOS RAM. Reset clock." ); + exit(1); + } + + /* Process options. */ + while (argc > 1) { + char *p = *++argv; + + if (*p++ != '-') usage(); + + while (*p != 0) { + switch (*p++) { + case 'n': nflag = 1; break; + case 'w': wflag = 1; break; + case 'W': Wflag = 1; break; + case '2': y2kflag = 1; break; + default: usage(); + } + } + argc--; + } + if (Wflag) wflag = 1; /* -W implies -w */ + +#if 0 + /* The hardware clock may run in a different time zone, likely GMT or + * winter time. Select that time zone. + */ + strcpy(clocktz, "TZ="); + sysgetenv.key = "TZ"; + sysgetenv.keylen = 2+1; + sysgetenv.val = clocktz+3; + sysgetenv.vallen = sizeof(clocktz)-3; + if (svrctl(SYSGETENV, &sysgetenv) == 0) { + putenv(clocktz); + tzset(); + } +#endif + + /* Read the CMOS real time clock. */ + for (i = 0; i < 10; i++) { + get_time(&time1); + now = time(NULL); + + time1.tm_isdst = -1; /* Do timezone calculations. */ + time2 = time1; + + rtc= mktime(&time1); /* Transform to a time_t. */ + if (rtc != -1) break; + + printf( +"readclock: Invalid time read from CMOS RTC: %d-%02d-%02d %02d:%02d:%02d\n", + time2.tm_year+1900, time2.tm_mon+1, time2.tm_mday, + time2.tm_hour, time2.tm_min, time2.tm_sec); + sleep(5); + } + if (i == 10) exit(1); + + if (!wflag) { + /* Set system time. */ + if (nflag) { + printf("stime(%lu)\n", (unsigned long) rtc); + } else { + if (stime(&rtc) < 0) { + errmsg( "Not allowed to set time." ); + exit(1); + } + } + tmnow = *localtime(&rtc); + if (strftime(date, sizeof(date), + "%a %b %d %H:%M:%S %Z %Y", &tmnow) != 0) { + if (date[8] == '0') date[8]= ' '; + printf("%s\n", date); + } + } else { + /* Set the CMOS clock to the system time. */ + tmnow = *localtime(&now); + if (nflag) { + printf("%04d-%02d-%02d %02d:%02d:%02d\n", + tmnow.tm_year + 1900, + tmnow.tm_mon + 1, + tmnow.tm_mday, + tmnow.tm_hour, + tmnow.tm_min, + tmnow.tm_sec); + } else { + set_time(&tmnow); + } + } + exit(0); +} + +void errmsg(char *s) +{ + static char *prompt = "readclock: "; + + printf("%s%s\n", prompt, s); + prompt = ""; +} + + +/***********************************************************************/ +/* */ +/* get_time( time ) */ +/* */ +/* Update the structure pointed to by time with the current time */ +/* as read from CMOS RAM of the RTC. */ +/* If necessary, the time is converted into a binary format before */ +/* being stored in the structure. */ +/* */ +/***********************************************************************/ + +int dead; +void timeout(int sig) { dead= 1; } + +void get_time(struct tm *t) +{ + int osec, n; + unsigned long i; + struct sigaction sa; + + /* Start a timer to keep us from getting stuck on a dead clock. */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = timeout; + sigaction(SIGALRM, &sa, NULL); + dead = 0; + alarm(5); + + do { + osec = -1; + n = 0; + do { + if (dead) { + printf("readclock: CMOS clock appears dead\n"); + exit(1); + } + + /* Clock update in progress? */ + if (read_register(RTC_REG_A) & RTC_A_UIP) continue; + + t->tm_sec = read_register(RTC_SEC); + if (t->tm_sec != osec) { + /* Seconds changed. First from -1, then because the + * clock ticked, which is what we're waiting for to + * get a precise reading. + */ + osec = t->tm_sec; + n++; + } + } while (n < 2); + + /* Read the other registers. */ + t->tm_min = read_register(RTC_MIN); + t->tm_hour = read_register(RTC_HOUR); + t->tm_mday = read_register(RTC_MDAY); + t->tm_mon = read_register(RTC_MONTH); + t->tm_year = read_register(RTC_YEAR); + + /* Time stable? */ + } while (read_register(RTC_SEC) != t->tm_sec + || read_register(RTC_MIN) != t->tm_min + || read_register(RTC_HOUR) != t->tm_hour + || read_register(RTC_MDAY) != t->tm_mday + || read_register(RTC_MONTH) != t->tm_mon + || read_register(RTC_YEAR) != t->tm_year); + + if ((read_register(RTC_REG_B) & RTC_B_DM_BCD) == 0) { + /* Convert BCD to binary (default RTC mode). */ + t->tm_year = bcd_to_dec(t->tm_year); + t->tm_mon = bcd_to_dec(t->tm_mon); + t->tm_mday = bcd_to_dec(t->tm_mday); + t->tm_hour = bcd_to_dec(t->tm_hour); + t->tm_min = bcd_to_dec(t->tm_min); + t->tm_sec = bcd_to_dec(t->tm_sec); + } + t->tm_mon--; /* Counts from 0. */ + + /* Correct the year, good until 2080. */ + if (t->tm_year < 80) t->tm_year += 100; + + if (y2kflag) { + /* Clock with Y2K bug, interpret 1980 as 2000, good until 2020. */ + if (t->tm_year < 100) t->tm_year += 20; + } +} + + +int read_register(int reg_addr) +{ + u32_t r; + + if(sys_outb(RTC_INDEX, reg_addr) != OK) { + printf("cmos: outb failed of %x\n", RTC_INDEX); + exit(1); + } + if(sys_inb(RTC_IO, &r) != OK) { + printf("cmos: inb failed of %x (index %x) failed\n", RTC_IO, reg_addr); + exit(1); + } + return r; +} + + + +/***********************************************************************/ +/* */ +/* set_time( time ) */ +/* */ +/* Set the CMOS RTC to the time found in the structure. */ +/* */ +/***********************************************************************/ + +void set_time(struct tm *t) +{ + int regA, regB; + + if (Wflag) { + /* Set A and B registers to their proper values according to the AT + * reference manual. (For if it gets messed up, but the BIOS doesn't + * repair it.) + */ + write_register(RTC_REG_A, RTC_A_DV_OK | RTC_A_RS_DEF); + write_register(RTC_REG_B, RTC_B_24); + } + + /* Inhibit updates. */ + regB= read_register(RTC_REG_B); + write_register(RTC_REG_B, regB | RTC_B_SET); + + t->tm_mon++; /* Counts from 1. */ + + if (y2kflag) { + /* Set the clock back 20 years to avoid Y2K bug, good until 2020. */ + if (t->tm_year >= 100) t->tm_year -= 20; + } + + if ((regB & 0x04) == 0) { + /* Convert binary to BCD (default RTC mode) */ + t->tm_year = dec_to_bcd(t->tm_year % 100); + t->tm_mon = dec_to_bcd(t->tm_mon); + t->tm_mday = dec_to_bcd(t->tm_mday); + t->tm_hour = dec_to_bcd(t->tm_hour); + t->tm_min = dec_to_bcd(t->tm_min); + t->tm_sec = dec_to_bcd(t->tm_sec); + } + write_register(RTC_YEAR, t->tm_year); + write_register(RTC_MONTH, t->tm_mon); + write_register(RTC_MDAY, t->tm_mday); + write_register(RTC_HOUR, t->tm_hour); + write_register(RTC_MIN, t->tm_min); + write_register(RTC_SEC, t->tm_sec); + + /* Stop the clock. */ + regA= read_register(RTC_REG_A); + write_register(RTC_REG_A, regA | RTC_A_DV_STOP); + + /* Allow updates and restart the clock. */ + write_register(RTC_REG_B, regB); + write_register(RTC_REG_A, regA); +} + + +void write_register(int reg_addr, int value) +{ + if(sys_outb(RTC_INDEX, reg_addr) != OK) { + printf("cmos: outb failed of %x\n", RTC_INDEX); + exit(1); + } + if(sys_outb(RTC_IO, value) != OK) { + printf("cmos: outb failed of %x (index %x)\n", RTC_IO, reg_addr); + exit(1); + } +} + +int bcd_to_dec(int n) +{ + return ((n >> 4) & 0x0F) * 10 + (n & 0x0F); +} + +int dec_to_bcd(int n) +{ + return ((n / 10) << 4) | (n % 10); +} + +void usage(void) +{ + printf("Usage: readclock [-nwW2]\n"); + exit(1); +} diff --git a/etc/Makefile b/etc/Makefile index 2bbb49fe5..331e02d72 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -1,7 +1,7 @@ ETC=/etc/ USRETC=/usr/etc/ -FILES1=fstab group hostname.file inet.conf motd.install mtab passwd profile protocols rc services termcap ttytab utmp rc.cd binary_sizes binary_sizes.big binary_sizes.xxl rc.rescue syslog.conf rc.daemons.dist rs.single make.conf +FILES1=fstab group hostname.file inet.conf motd.install mtab passwd profile protocols rc services termcap ttytab utmp rc.cd binary_sizes binary_sizes.big binary_sizes.xxl rc.rescue syslog.conf rc.daemons.dist rs.single make.conf drivers.conf FILES2=shadow FILES3=daily dhcptags.conf rc diff --git a/etc/drivers.conf b/etc/drivers.conf index 1e5f1eede..978d462db 100644 --- a/etc/drivers.conf +++ b/etc/drivers.conf @@ -73,16 +73,18 @@ driver random ; }; -driver cmos +driver readclock.drv { io 70:2; system DEVIO # 21 TIMES # 25 SAFECOPYTO # 32 + SAFECOPYFROM # 32 SETGRANT # 34 READBIOS # 35 ; + uid 0; }; driver is diff --git a/etc/rc b/etc/rc index 5a91a19e0..2578ad5a2 100755 --- a/etc/rc +++ b/etc/rc @@ -49,7 +49,6 @@ start) test -f /etc/keymap && loadkeys /etc/keymap up is -period 5HZ - up cmos -dev /dev/cmos -period 5HZ echo . # Set timezone.