partition \
playwave \
postmort \
- readclock \
recwave \
repartition \
screendump \
$(CCLD) -o $@ $?
install -S 4kw $@
-readclock: readclock.c
- $(CCLD) -o $@ $?
- install -S 4kw $@
-
recwave: recwave.c
$(CCLD) -o $@ $?
install -S 16kw $@
/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 $? $@
/usr/bin/postmort: postmort
install -cs -o bin $? $@
-/usr/bin/readclock: readclock
- install -cs -o bin $? $@
-
/usr/bin/recwave: recwave
install -cs -o bin $? $@
/bin/loadkeys: /usr/bin/loadkeys
install -lcs $? $@
-/bin/readclock: /usr/bin/readclock
- install -lcs $? $@
-
clean:
rm -rf $(ALL) a.out core
+++ /dev/null
-/* 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 <minix/callnr.h>
-#include <minix/config.h>
-#include <minix/type.h>
-#include <minix/const.h>
-#include <minix/com.h>
-#include <minix/syslib.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioc_cmos.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <errno.h>
-#include <signal.h>
-#include <minix/portio.h>
-#include <ibm/cmos.h>
-#include <sys/svrctl.h>
-
-#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);
-}
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 <<EOF
audio mixer # Make audio devices
klog # Make /dev/klog
random # Make /dev/random, /dev/urandom
- cmos # Make /dev/cmos
kbd # Make /dev/kbd
kbdaux # Make /dev/kbdaux
rescue # Make /dev/rescue
$e mknod urandom c 16 0; $e chmod 644 urandom
$e chgrp operator random urandom
;;
- cmos)
- # cmos device (set/get system time).
- $e mknod cmos c 17 0
- $e chmod 600 cmos
- ;;
rescue)
# rescue device
$e mknod rescue b 9 0
/usr/bin/makewhatis \
/usr/bin/mkdep \
/usr/bin/mkdist \
+ /bin/readclock \
/bin/setup \
/usr/bin/binsizes \
/usr/bin/rotate \
/usr/bin/rotate: rotate.sh
install -m 755 -c -o bin $? $@
+/bin/readclock: readclock.sh
+ install -m 755 -c -o bin $? $@
+
/bin/setup: setup.sh
install -m 755 -c -o bin $? $@
--- /dev/null
+#!/bin/sh
+if [ $# -gt 0 ]
+then ARGS="-args $@"
+fi
+/bin/service up /sbin/readclock.drv -config /etc/drivers.conf -script /etc/rs.single $ARGS
cd ./dpeth && $(MAKE) $@
cd ./log && $(MAKE) $@
cd ./bios_wini && $(MAKE) $@
- cd ./cmos && $(MAKE) $@
cd ./random && $(MAKE) $@
+ cd ./readclock && $(MAKE) $@
cd ./dp8390 && $(MAKE) $@
cd ./sb16 && $(MAKE) $@
cd ./lance && $(MAKE) $@
+++ /dev/null
-/* This file contains a device driver that can access the CMOS chip to
- * get or set the system time. It drives the special file:
- *
- * /dev/cmos - CMOS chip
- *
- * Changes:
- * Aug 04, 2005 Created. Read CMOS time. (Jorrit N. Herder)
- *
- * 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
- */
-
-#include "../drivers.h"
-#include <sys/ioc_cmos.h>
-#include <time.h>
-#include <ibm/cmos.h>
-#include <ibm/bios.h>
-#include <minix/safecopies.h>
-
-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);
-}
-
-# 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)
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
--- /dev/null
+/* 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 <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+#include <minix/type.h>
+#include <minix/syslib.h>
+#include <minix/com.h>
+#include <minix/portio.h>
+#include <ibm/cmos.h>
+#include <sys/svrctl.h>
+
+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);
+}
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
;
};
-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
test -f /etc/keymap && loadkeys /etc/keymap
up is -period 5HZ
- up cmos -dev /dev/cmos -period 5HZ
echo .
# Set timezone.