From bb57bf63385166ee242a4b6bf66fbdfcc3a14ff2 Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Thu, 25 Apr 2024 16:48:04 -0600 Subject: [PATCH 1/6] Replace clock.c with @Mellvik's version --- elkscmd/sys_utils/clock.c | 680 +++++++++++++++++++++++++------------- 1 file changed, 445 insertions(+), 235 deletions(-) diff --git a/elkscmd/sys_utils/clock.c b/elkscmd/sys_utils/clock.c index 58e07f12b..23dcdfc50 100644 --- a/elkscmd/sys_utils/clock.c +++ b/elkscmd/sys_utils/clock.c @@ -1,4 +1,3 @@ -#include /* for CONFIG_ options */ #include #include #include @@ -10,8 +9,6 @@ #include #include -#define ELKS 1 - /* V1.0 * CMOS clock manipulation - Charles Hedrick, hedrick@cs.rutgers.edu, Apr 1992 * @@ -21,6 +18,7 @@ * clock [-u] -a - set system time from cmos clock, adjust the time to * correct for systematic error, and put it back to the cmos. * -u indicates cmos clock is kept in universal time + * [check the usage() function for an updated list of options] * * The program is designed to run setuid, since we need to be able to * write the CMOS port. @@ -139,106 +137,208 @@ * And since the long code is so slow, the program just locks. * * v1.6 Work with RTC localtime as well as UTC + * + * v1.7 (april 2024 hs/@mellvik TLVC): Add support for ASTCLOCK + * (AST SixPackPlus), seemingly the common choice in pre-AT + * systems. Supports both NS and Ricoh chips. */ #define errmsg(str) write(STDERR_FILENO, str, sizeof(str) - 1) #define errstr(str) write(STDERR_FILENO, str, strlen(str)) +#define CMOS_CMDREG 0x70 +#define CMOS_IOREG 0x71 + +#define AST_CMDREG 0x2C0 +#define AST_IOREG 0x2C1 + +#define AST_RETRY 1000 + +/* for Nat Semi chip */ +#define AST_NS_MSEC 0x01 +#define AST_NS_SEC 0x02 +#define AST_NS_MIN 0x03 /* get minute cntr */ +#define AST_NS_HRS 0x04 /* get hour cntr */ +#define AST_NS_DOW 0x05 /* day of week */ +#define AST_NS_DOM 0x06 /* day of month */ +#define AST_NS_MON 0x07 /* month of year */ +#define AST_NS_YEAR 0x0A /* year, counts from 1980 */ +#define AST_NS_STAT 0x14 /* get status bit */ +#define AST_NS_CRST 0x12 /* clear counters */ +#define AST_NS_GO 0x15 /* clear subsec counters */ + +/* for Ricoh chip */ +#define AST_RI_SEC 0 +#define AST_RI_MIN 2 +#define AST_RI_HRS 4 +#define AST_RI_DOW 6 /* one reg, the others are two (BCD) */ +#define AST_RI_DOM 7 +#define AST_RI_MON 9 +#define AST_RI_YEAR 11 + +#define AST_CHIPTYPE 0x0D /* Distinguish between Ricoh and NS chip via + * this register */ + /* Globals */ -int readit = 0; -int writeit = 0; -int setit = 0; -int universal = 0; +int readit = 0; +int writeit = 0; +int setit = 0; +int universal = 0; +int astclock = 0; +int verbose = 0; + +#ifdef CONFIG_ARCH_PC98 +void pc98_settime(struct tm *, unsigned char *); +void pc98_gettime(struct tm *, unsigned char *); +void pc98_write_calendar(unsigned int, unsigned int); +void pc98_read_calendar(unsigned int, unsigned int); +#else +void ast_settime(struct tm *); +void ast_gettime(struct tm *); +void cmos_settime(struct tm *); +void cmos_gettime(struct tm *); +#endif + +/* #define AST_TEST */ int usage(void) { - errmsg("clock [-u] -r|w|s\n"); + errmsg("clock [-u] -r|w|s|v|A\n"); errmsg(" r: read and print CMOS clock\n"); errmsg(" w: write CMOS clock from system time\n"); errmsg(" s: set system time from CMOS clock\n"); errmsg(" u: CMOS clock is in universal time\n"); + errmsg(" v: verbose mode\n"); + errmsg(" A: assume ASTCLOCK type RTC, increase verbosity\n"); exit(1); } -#ifdef CONFIG_ARCH_8018X + unsigned char cmos_read(unsigned char reg) { - register unsigned char ret; - clr_irq (); - ret = inb_p (CONFIG_8018X_RTC + reg); - set_irq (); - return ret; + register unsigned char ret; + + clr_irq(); + outb_p(reg | 0x80, 0x70); + ret = inb_p(0x71); + set_irq(); + return ret; } void cmos_write(unsigned char reg, unsigned char val) { - clr_irq (); - outb_p (val, CONFIG_8018X_RTC + reg); - set_irq (); + clr_irq(); + outb_p(reg | 0x80, 0x70); + outb_p(val, 0x71); + set_irq(); } -#else -unsigned char cmos_read(unsigned char reg) + +int cmos_read_bcd(int addr) { - register unsigned char ret; - clr_irq (); - outb_p (reg | 0x80, 0x70); - ret = inb_p (0x71); - set_irq (); - return ret; + int b; + + b = cmos_read(addr); + return (b & 15) + (b >> 4) * 10; } -void cmos_write(unsigned char reg, unsigned char val) +void cmos_write_bcd(int addr, int value) { - clr_irq (); - outb_p (reg | 0x80, 0x70); - outb_p (val, 0x71); - set_irq (); + cmos_write(addr, ((value / 10) << 4) + value % 10); } -#endif -int cmos_read_bcd (int addr) +/* PROBE to verify existence: Read CMOS status register A, check + * for sanity (0x26), ignore the UpdateInProgress flag (bit 7, comes and goes). + * Then write 0 to status reg D, which is read only, and read it back. + * Should always return 0x80. Bit 7 indicates RAM/TIME/battery OK, the + * other bits are always zero. Return true if found. + * + * [Alternative method: Read all 4 status regs. If they're all the same + * there's nothing there. For reference, on physical systems the readback is 0x48, + * on emulators 0xff] + */ +int cmos_probe(void) { - int b; - b = cmos_read (addr); - return (b & 15) + (b >> 4) * 10; + cmos_write(0xd, 0); + if (((cmos_read(0xa) & 0x7f) == 0x26) && cmos_read(0xd)) + return 1; + //printf("CMOS status A %x, B %x, C %x, D %x\n", cmos_read(0xa), cmos_read(0xb), + //cmos_read(0xc), cmos_read(0xd)); + return 0; } -void cmos_write_bcd(int addr, int value) +void ast_putreg(unsigned char reg, unsigned char val) { - cmos_write (addr, ((value / 10) << 4) + value % 10); + clr_irq(); + outb_p(reg, AST_CMDREG); + outb_p(val, AST_IOREG); + set_irq(); } -#ifdef CONFIG_ARCH_PC98 -void read_calendar(unsigned int tm_seg, unsigned int tm_offset) +void ast_putbcd(int addr, int value) +{ + ast_putreg(addr, ((value / 10) << 4) + value % 10); +} + +/* The Ricoh has 4 bit addressing only, BCD values are in adjacent addresses */ +void ast_put_rbcd(int addr, int value) { - __asm__ volatile ("mov %0,%%es;" - "mov $0,%%ah;" - "int $0x1C;" - : - :"a" (tm_seg), "b" (tm_offset) - :"%es", "memory", "cc"); + ast_putreg(addr, value % 10); + ast_putreg(addr + 1, value / 10); +} +int ast_getreg(int reg) +{ + outb(reg, AST_CMDREG); + return (inb(AST_IOREG)); } -void write_calendar(unsigned int tm_seg, unsigned int tm_offset) +int ast_getbcd(int reg) { - __asm__ volatile ("mov %0,%%es;" - "mov $1,%%ah;" - "int $0x1C;" - : - :"a" (tm_seg), "b" (tm_offset) - :"%es", "memory", "cc"); + int val = ast_getreg(reg); + return ((val & 15) + (val >> 4) * 10); } -int bcd_hex(unsigned char bcd_data) +int ast_get_rbcd(int reg) { - return (bcd_data & 15) + (bcd_data >> 4) * 10; + return ((ast_getreg(reg) & 0xf) + (ast_getreg(reg + 1) & 0xf) * 10); } -int hex_bcd(int hex_data) +/* + * Per the AST app note, bit 1 in reg D may be used to determine which chip we're using. + * This bit will always return 0 on the Ricoh, on the NS it's RAM and we'll read back what we write. + * Returns 0 if Ricoh chip, 2 if NS chip, -1 if neither. + */ +int ast_chiptype(void) +{ + int tmp = (ast_getreg(AST_CHIPTYPE) & 0xf) | 2; + + /* 86box - when told to emulate ASTCLOCK, returns 2 from all registers */ + /* Otherwise (all hw) returns 0xff */ + + if ((ast_getreg(1) + ast_getreg(2) + ast_getreg(3) + ast_getreg(4)) / 4 == ast_getreg(1)) + return -1; + + ast_putreg(AST_CHIPTYPE, tmp); + return (ast_getreg(AST_CHIPTYPE) & 0x2); +} + +#ifdef AST_TEST +void show_astclock(void) { - return ((hex_data / 10) << 4) + hex_data % 10; + if (ast_chiptype()) { + printf("AST clock (NS): %d/%d/%d - %02d:%02d:%02d.%d\n", ast_getbcd(AST_NS_DOM), ast_getbcd(AST_NS_MON), + ast_getreg(AST_NS_YEAR) + 1980, ast_getbcd(AST_NS_HRS), ast_getbcd(AST_NS_MIN), + ast_getbcd(AST_NS_SEC), ast_getbcd(AST_NS_MSEC)); + printf("Other regs 00:%d, 01:%d, 05:%d, 08:%d, 09:%d\n", ast_getreg(0), ast_getreg(1), ast_getreg(5), + ast_getreg(8), ast_getreg(9)); + } else { + printf("AST clock (Ricoh): %d/%d/%d - %02d:%02d:%02d\n", ast_get_rbcd(AST_RI_DOM), + ast_get_rbcd(AST_RI_MON), ast_get_rbcd(AST_RI_YEAR) + 1980, ast_get_rbcd(AST_RI_HRS), + ast_get_rbcd(AST_RI_MIN), ast_get_rbcd(AST_RI_SEC)); + } } +#else +#define show_astclock(x) #endif /* our own happy mktime() replacement, with the following drawbacks: */ @@ -247,143 +347,129 @@ int hex_bcd(int hex_data) /* doesn't return the local time */ time_t utc_mktime(struct tm *t) { - static int mday[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - int year_ofs; - int i; + static int mday[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + int year_ofs, i; time_t ret; - /* calculate seconds from years */ + /* calculate seconds from years */ year_ofs = t->tm_year - 70; ret = year_ofs * (365L * 24L * 60L * 60L); - /* calculate seconds from leap days */ + /* calculate seconds from leap days */ ret += ((year_ofs + 1) >> 2) * (24L * 60L * 60L); - /* caluclate seconds from months */ - for (i=0; itm_mon; i++) { + /* caluclate seconds from months */ + for (i = 0; i < t->tm_mon; i++) { ret += mday[i] * (24L * 60L * 60L); } - /* add in this year's leap day, if any */ + /* add in this year's leap day, if any */ if (((t->tm_year & 3) == 0) && (t->tm_mon > 1)) { ret += (24L * 60L * 60L); } - /* calculate seconds from days in this month */ + /* calculate seconds from days in this month */ ret += (t->tm_mday - 1) * (24L * 60L * 60L); - /* calculate seconds from hours today */ + /* calculate seconds from hours today */ ret += t->tm_hour * (60L * 60L); - /* calculate seconds from minutes this hour */ + /* calculate seconds from minutes this hour */ ret += t->tm_min * 60L; - /* finally, add in seconds */ + /* finally, add in seconds */ ret += t->tm_sec; - /* return the result */ + /* return the result */ return ret; } int main(int argc, char **argv) { - struct tm tm; - time_t systime; - int arg; - unsigned char save_control, save_freq_select; + struct tm tm; + time_t systime; + int arg; #ifdef CONFIG_ARCH_PC98 - unsigned char timebuf[6]; - unsigned char __far *timeaddr; - unsigned int tm_seg; - unsigned int tm_offset; - - timeaddr = (unsigned char __far *) timebuf; - tm_seg = ((long) timeaddr) >> 16; - tm_offset = ((long) timeaddr) & 0xFFFF; + unsigned char timebuf[6]; + unsigned char __far *timeaddr; + unsigned int tm_seg; + unsigned int tm_offset; + + timeaddr = (unsigned char __far *)timebuf; + tm_seg = ((long)timeaddr) >> 16; + tm_offset = ((long)timeaddr) & 0xFFFF; #endif - while ((arg = getopt (argc, argv, "rwsuv")) != -1) - { - switch (arg) - { + while ((arg = getopt(argc, argv, "rwsuvA")) != -1) { + switch (arg) { case 'r': - readit = 1; - break; + readit = 1; + break; case 'w': - writeit = 1; - break; + writeit = 1; + break; case 's': - setit = 1; - break; + setit = 1; + break; case 'u': - universal = 1; - break; + universal = 1; + break; + case 'A': + astclock = 1; + break; + case 'v': + verbose = 1; + break; default: - usage (); + usage(); + } + } + + if (!cmos_probe()) { + if (ast_chiptype() < 0) { + printf("No RTC found on system, not setting date and time\n"); + exit(1); + } else { + if (verbose) + printf("No CMOS clock found, assuming AST\n"); + astclock = 1; + show_astclock(); } } - if (readit + writeit + setit > 1) - usage (); /* only allow one of these */ + if (readit + writeit + setit > 1) + usage(); /* only allow one of these */ - if (!(readit | writeit | setit )) /* default to read */ - readit = 1; + if (!(readit | writeit | setit)) /* default to read */ + readit = 1; - if (readit || setit) - { + if (readit || setit) { #ifdef CONFIG_ARCH_PC98 - read_calendar(tm_seg, tm_offset); - tm.tm_sec = bcd_hex(timebuf[5]); - tm.tm_min = bcd_hex(timebuf[4]); - tm.tm_hour = bcd_hex(timebuf[3]); - tm.tm_wday = bcd_hex(timebuf[1] & 0xF); - tm.tm_mday = bcd_hex(timebuf[2]); - tm.tm_mon = timebuf[1] >> 4; - tm.tm_year = bcd_hex(timebuf[0]); + pc98_read_calendar(tm_seg, tm_offset); + pc98_gettime(&tm, timebuf); #else -/* The purpose of the "do" loop is called "low-risk programming" */ -/* In theory it should never run more than once */ - do - { - tm.tm_sec = cmos_read_bcd (0); - tm.tm_min = cmos_read_bcd (2); - tm.tm_hour = cmos_read_bcd (4); - tm.tm_wday = cmos_read_bcd (6); - tm.tm_mday = cmos_read_bcd (7); - tm.tm_mon = cmos_read_bcd (8); - tm.tm_year = cmos_read_bcd (9); - } - while (tm.tm_sec != cmos_read_bcd (0)); -#endif - if (tm.tm_year < 70) - tm.tm_year += 100; /* 70..99 => 1970..1999, 0..69 => 2000..2069 */ - tm.tm_mon--; /* DOS uses 1 base */ -#ifndef CONFIG_ARCH_PC98 - tm.tm_wday -= 3; /* DOS uses 3 - 9 for week days */ + if (astclock) + ast_gettime(&tm); + else + cmos_gettime(&tm); #endif - tm.tm_isdst = -1; /* don't know whether it's daylight */ + tm.tm_mon--; /* DOS uses 1 base */ + tm.tm_isdst = -1; /* don't know whether it's daylight */ } - if (readit || setit) - { + if (readit || setit) { /* * utc_mktime() assumes we're in Greenwich, England. If the CMOS * clock isn't in GMT, we need to adjust. */ - systime = utc_mktime(&tm); - if (!universal) { -#if ELKS - tzset(); /* read TZ= env string and set timezone var */ - systime += timezone; -#else - struct timezone tz; - gettimeofday(NULL, &tz); - systime += tz.tz_minuteswest * 60L; -#endif - } + systime = utc_mktime(&tm); + if (!universal) { + tzset(); /* read TZ= env string and set timezone var */ + systime += timezone; + } #if 0 /* * mktime() assumes we're giving it local time. If the CMOS clock @@ -391,117 +477,241 @@ int main(int argc, char **argv) * called implicitly by the time code, but only the first time. When * changing the environment variable, better call tzset() explicitly. */ - if (universal) - { - char *zone; - zone = (char *) getenv ("TZ"); /* save original time zone */ - (void) putenv ("TZ="); - tzset (); - systime = mktime (&tm); - /* now put back the original zone */ - if (zone) - { - - char *zonebuf; - zonebuf = malloc (strlen (zone) + 4); - strcpy (zonebuf, "TZ="); - strcpy (zonebuf+3, zone); - putenv (zonebuf); - free (zonebuf); + if (universal) { + char *zone; + + zone = (char *)getenv("TZ"); /* save original time zone */ + (void)putenv("TZ="); + tzset(); + systime = mktime(&tm); + /* now put back the original zone */ + if (zone) { + char *zonebuf; + + zonebuf = malloc(strlen(zone) + 4); + strcpy(zonebuf, "TZ="); + strcpy(zonebuf + 3, zone); + putenv(zonebuf); + free(zonebuf); + } else { /* wasn't one, so clear it */ + putenv("TZ"); } - else - { /* wasn't one, so clear it */ - putenv ("TZ"); - } - tzset (); - } - else - { - systime = mktime (&tm); - } -#endif /* 0 */ + tzset(); + } else + systime = mktime(&tm); +#endif /* 0 */ } - if (readit) - { - char *p = ctime(&systime); - write(STDOUT_FILENO, p, strlen(p)); + if (readit) { + char *p = ctime(&systime); + if (verbose) + printf("From %s: ", astclock ? "ASTclock" : "CMOS"); + printf("%s", p); + //write(STDOUT_FILENO, p, strlen(p)); } - if (setit) - { - struct timeval tv; - struct timezone tz; + if (setit) { + struct timeval tv; + struct timezone tz; -/* program is designed to run setuid, be secure! */ + /* program is designed to run setuid, be secure! */ - if (getuid () != 0) - { - errmsg("Sorry, must be root to set time\n"); - exit (2); + if (getuid() != 0) { + errmsg("Sorry, must be root to set time\n"); + exit(2); } - tv.tv_sec = systime; - tv.tv_usec = 0; -#if ELKS - /* system time is offset by TZ variable for now, localtime handled in C library*/ - tz.tz_minuteswest = 0; - tz.tz_dsttime = DST_NONE; -#else - tz.tz_minuteswest = timezone / 60; - tz.tz_dsttime = daylight; -#endif + tv.tv_sec = systime; + tv.tv_usec = 0; + + /* + * system time is offset by TZ variable for now, localtime handled in + * C library + */ + tz.tz_minuteswest = 0; + tz.tz_dsttime = DST_NONE; - if (settimeofday (&tv, &tz) != 0) - { - errmsg("Unable to set time -- probably you are not root\n"); - exit (1); + if (settimeofday(&tv, &tz) != 0) { + errmsg("Unable to set time -- probably you are not root\n"); + exit(1); } } - if (writeit) - { - struct tm *tmp; - systime = time (NULL); - if (universal) - tmp = gmtime (&systime); - else - tmp = localtime (&systime); - - clr_irq(); + if (writeit) { + struct tm *tmp; + systime = time(NULL); + if (universal) + tmp = gmtime(&systime); + else + tmp = localtime(&systime); #ifdef CONFIG_ARCH_PC98 - timebuf[5] = hex_bcd(tmp->tm_sec); - timebuf[4] = hex_bcd(tmp->tm_min); - timebuf[3] = hex_bcd(tmp->tm_hour); - timebuf[1] = hex_bcd(tmp->tm_wday); - timebuf[2] = hex_bcd(tmp->tm_mday); - timebuf[1] = (timebuf[1] & 0xF) + ((tmp->tm_mon + 1) << 4); - if (tmp->tm_year >= 100) - timebuf[0] = hex_bcd(tmp->tm_year-100); - else - timebuf[0] = hex_bcd(tmp->tm_year); - - write_calendar(tm_seg, tm_offset); + pc98_settime(tmp, timebuf); + pc98_write_calendar(tm_seg, tm_offset); #else - save_control = cmos_read (11); /* tell the clock it's being set */ - cmos_write (11, (save_control | 0x80)); - save_freq_select = cmos_read (10); /* stop and reset prescaler */ - cmos_write (10, (save_freq_select | 0x70)); - - cmos_write_bcd (0, tmp->tm_sec); - cmos_write_bcd (2, tmp->tm_min); - cmos_write_bcd (4, tmp->tm_hour); - cmos_write_bcd (6, tmp->tm_wday + 3); - cmos_write_bcd (7, tmp->tm_mday); - cmos_write_bcd (8, tmp->tm_mon + 1); - cmos_write_bcd (9, tmp->tm_year); - - cmos_write (10, save_freq_select); - cmos_write (11, save_control); + if (astclock) + ast_settime(tmp); + else + cmos_settime(tmp); #endif - set_irq(); } - return 0; + return 0; +} + +#ifndef CONFIG_ARCH_PC98 + +/* set time from AST SixPakPlus type RTC */ +void ast_gettime(struct tm *tm) +{ + int wait = AST_RETRY; + + if (ast_chiptype()) { + + do { /* NS clock chip */ + tm->tm_sec = ast_getbcd(AST_NS_SEC); + tm->tm_min = ast_getbcd(AST_NS_MIN); + tm->tm_hour = ast_getbcd(AST_NS_HRS); + tm->tm_wday = ast_getbcd(AST_NS_DOW); + tm->tm_mday = ast_getbcd(AST_NS_DOM); + tm->tm_mon = ast_getbcd(AST_NS_MON); + tm->tm_year = ast_getreg(AST_NS_YEAR); + } while (ast_getreg(AST_NS_STAT) && wait--); + + } else { /* Ricoh clock chip */ + + tm->tm_sec = ast_get_rbcd(AST_RI_SEC); + tm->tm_min = ast_get_rbcd(AST_RI_MIN); + tm->tm_hour = ast_get_rbcd(AST_RI_HRS); + tm->tm_wday = ast_getreg(AST_RI_DOW); + tm->tm_mday = ast_get_rbcd(AST_RI_DOM); + tm->tm_mon = ast_get_rbcd(AST_RI_MON); + tm->tm_year = ast_get_rbcd(AST_RI_YEAR); + } + tm->tm_year += 80 /* AST clock starts @ 1980 */ ; +} + +/* set time from AT style CMOS RTC (mc146818) */ +void cmos_gettime(struct tm *tm) +{ + do { + tm->tm_sec = cmos_read_bcd(0); + tm->tm_min = cmos_read_bcd(2); + tm->tm_hour = cmos_read_bcd(4); + tm->tm_wday = cmos_read_bcd(6); + tm->tm_mday = cmos_read_bcd(7); + tm->tm_mon = cmos_read_bcd(8); + tm->tm_year = cmos_read_bcd(9); + } while (tm->tm_sec != cmos_read_bcd(0)); + + if (tm->tm_year < 70) + tm->tm_year += 100; /* 70..99 => 1970..1999, 0..69 => 2000..2069 */ +} + +void ast_settime(struct tm *tmp) +{ + if (ast_chiptype()) { + ast_putreg(AST_NS_CRST, 0xff); /* clear counters */ + ast_putbcd(AST_NS_SEC, tmp->tm_sec); + ast_putbcd(AST_NS_MIN, tmp->tm_min); + ast_putbcd(AST_NS_HRS, tmp->tm_hour); + ast_putbcd(AST_NS_DOW, tmp->tm_wday); + ast_putbcd(AST_NS_DOM, tmp->tm_mday); + ast_putbcd(AST_NS_MON, tmp->tm_mon + 1); + ast_putreg(AST_NS_YEAR, tmp->tm_year - 80); + } else { + /* + * no precautions (the Ricoh has 1 sec visible resolution, very DOS + * oriented. The ADJ bit does not do what you might think it does. + */ + ast_put_rbcd(AST_RI_SEC, tmp->tm_sec); + ast_put_rbcd(AST_RI_MIN, tmp->tm_min); + ast_put_rbcd(AST_RI_HRS, tmp->tm_hour); + ast_putreg(AST_RI_DOW, tmp->tm_wday); + ast_put_rbcd(AST_RI_DOM, tmp->tm_mday); + ast_put_rbcd(AST_RI_MON, tmp->tm_mon + 1); + ast_put_rbcd(AST_RI_YEAR, tmp->tm_year - 80); + } +} + +void cmos_settime(struct tm *tmp) +{ + unsigned char save_control, save_freq_select; + + save_control = cmos_read(11); /* tell the clock it's being set */ + cmos_write(11, (save_control | 0x80)); + save_freq_select = cmos_read(10); /* stop and reset prescaler */ + cmos_write(10, (save_freq_select | 0x70)); + + cmos_write_bcd(0, tmp->tm_sec); + cmos_write_bcd(2, tmp->tm_min); + cmos_write_bcd(4, tmp->tm_hour); + cmos_write_bcd(6, tmp->tm_wday + 3); + cmos_write_bcd(7, tmp->tm_mday); + cmos_write_bcd(8, tmp->tm_mon + 1); + cmos_write_bcd(9, tmp->tm_year); + + cmos_write(10, save_freq_select); + cmos_write(11, save_control); } + +#else + +void pc98_read_calendar(unsigned int tm_seg, unsigned int tm_offset) +{ + __asm__ volatile ("mov %0,%%es;" + "mov $0,%%ah;" + "int $0x1C;" + : + :"a" (tm_seg), "b"(tm_offset) + :"%es", "memory", "cc"); + +} + +void pc98_write_calendar(unsigned int tm_seg, unsigned int tm_offset) +{ + __asm__ volatile ("mov %0,%%es;" + "mov $1,%%ah;" + "int $0x1C;" + : + :"a" (tm_seg), "b"(tm_offset) + :"%es", "memory", "cc"); + +} + +int bcd_hex(unsigned char bcd_data) +{ + return (bcd_data & 15) + (bcd_data >> 4) * 10; +} + +int hex_bcd(int hex_data) +{ + return ((hex_data / 10) << 4) + hex_data % 10; +} + +void pc98_gettime(struct tm *tm, unsigned char *timebuf) +{ + tm->tm_sec = bcd_hex(timebuf[5]); + tm->tm_min = bcd_hex(timebuf[4]); + tm->tm_hour = bcd_hex(timebuf[3]); + tm->tm_wday = bcd_hex(timebuf[1] & 0xF); + tm->tm_mday = bcd_hex(timebuf[2]); + tm->tm_mon = timebuf[1] >> 4; + tm->tm_year = bcd_hex(timebuf[0]); + tm->tm_wday -= 3; /* DOS uses 3 - 9 for week days */ +} + +void pc98_settime(struct tm *tmp, unsigned char *timebuf) +{ + timebuf[5] = hex_bcd(tmp->tm_sec); + timebuf[4] = hex_bcd(tmp->tm_min); + timebuf[3] = hex_bcd(tmp->tm_hour); + timebuf[1] = hex_bcd(tmp->tm_wday); + timebuf[2] = hex_bcd(tmp->tm_mday); + timebuf[1] = (timebuf[1] & 0xF) + ((tmp->tm_mon + 1) << 4); + if (tmp->tm_year >= 100) + timebuf[0] = hex_bcd(tmp->tm_year - 100); + else + timebuf[0] = hex_bcd(tmp->tm_year); +} +#endif From b345642297a457c37ad583af29ed3de37d5c66cd Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Thu, 25 Apr 2024 16:49:22 -0600 Subject: [PATCH 2/6] Retab --- elkscmd/sys_utils/clock.c | 466 +++++++++++++++++++------------------- 1 file changed, 233 insertions(+), 233 deletions(-) diff --git a/elkscmd/sys_utils/clock.c b/elkscmd/sys_utils/clock.c index 23dcdfc50..242c3285a 100644 --- a/elkscmd/sys_utils/clock.c +++ b/elkscmd/sys_utils/clock.c @@ -146,57 +146,57 @@ #define errmsg(str) write(STDERR_FILENO, str, sizeof(str) - 1) #define errstr(str) write(STDERR_FILENO, str, strlen(str)) -#define CMOS_CMDREG 0x70 -#define CMOS_IOREG 0x71 +#define CMOS_CMDREG 0x70 +#define CMOS_IOREG 0x71 -#define AST_CMDREG 0x2C0 -#define AST_IOREG 0x2C1 +#define AST_CMDREG 0x2C0 +#define AST_IOREG 0x2C1 -#define AST_RETRY 1000 +#define AST_RETRY 1000 /* for Nat Semi chip */ -#define AST_NS_MSEC 0x01 -#define AST_NS_SEC 0x02 -#define AST_NS_MIN 0x03 /* get minute cntr */ -#define AST_NS_HRS 0x04 /* get hour cntr */ -#define AST_NS_DOW 0x05 /* day of week */ -#define AST_NS_DOM 0x06 /* day of month */ -#define AST_NS_MON 0x07 /* month of year */ -#define AST_NS_YEAR 0x0A /* year, counts from 1980 */ -#define AST_NS_STAT 0x14 /* get status bit */ -#define AST_NS_CRST 0x12 /* clear counters */ -#define AST_NS_GO 0x15 /* clear subsec counters */ +#define AST_NS_MSEC 0x01 +#define AST_NS_SEC 0x02 +#define AST_NS_MIN 0x03 /* get minute cntr */ +#define AST_NS_HRS 0x04 /* get hour cntr */ +#define AST_NS_DOW 0x05 /* day of week */ +#define AST_NS_DOM 0x06 /* day of month */ +#define AST_NS_MON 0x07 /* month of year */ +#define AST_NS_YEAR 0x0A /* year, counts from 1980 */ +#define AST_NS_STAT 0x14 /* get status bit */ +#define AST_NS_CRST 0x12 /* clear counters */ +#define AST_NS_GO 0x15 /* clear subsec counters */ /* for Ricoh chip */ -#define AST_RI_SEC 0 -#define AST_RI_MIN 2 -#define AST_RI_HRS 4 -#define AST_RI_DOW 6 /* one reg, the others are two (BCD) */ -#define AST_RI_DOM 7 -#define AST_RI_MON 9 -#define AST_RI_YEAR 11 +#define AST_RI_SEC 0 +#define AST_RI_MIN 2 +#define AST_RI_HRS 4 +#define AST_RI_DOW 6 /* one reg, the others are two (BCD) */ +#define AST_RI_DOM 7 +#define AST_RI_MON 9 +#define AST_RI_YEAR 11 -#define AST_CHIPTYPE 0x0D /* Distinguish between Ricoh and NS chip via - * this register */ +#define AST_CHIPTYPE 0x0D /* Distinguish between Ricoh and NS chip via + * this register */ /* Globals */ -int readit = 0; -int writeit = 0; -int setit = 0; -int universal = 0; -int astclock = 0; -int verbose = 0; +int readit = 0; +int writeit = 0; +int setit = 0; +int universal = 0; +int astclock = 0; +int verbose = 0; #ifdef CONFIG_ARCH_PC98 -void pc98_settime(struct tm *, unsigned char *); -void pc98_gettime(struct tm *, unsigned char *); -void pc98_write_calendar(unsigned int, unsigned int); -void pc98_read_calendar(unsigned int, unsigned int); +void pc98_settime(struct tm *, unsigned char *); +void pc98_gettime(struct tm *, unsigned char *); +void pc98_write_calendar(unsigned int, unsigned int); +void pc98_read_calendar(unsigned int, unsigned int); #else -void ast_settime(struct tm *); -void ast_gettime(struct tm *); -void cmos_settime(struct tm *); -void cmos_gettime(struct tm *); +void ast_settime(struct tm *); +void ast_gettime(struct tm *); +void cmos_settime(struct tm *); +void cmos_gettime(struct tm *); #endif /* #define AST_TEST */ @@ -234,7 +234,7 @@ void cmos_write(unsigned char reg, unsigned char val) int cmos_read_bcd(int addr) { - int b; + int b; b = cmos_read(addr); return (b & 15) + (b >> 4) * 10; @@ -248,7 +248,7 @@ void cmos_write_bcd(int addr, int value) /* PROBE to verify existence: Read CMOS status register A, check * for sanity (0x26), ignore the UpdateInProgress flag (bit 7, comes and goes). * Then write 0 to status reg D, which is read only, and read it back. - * Should always return 0x80. Bit 7 indicates RAM/TIME/battery OK, the + * Should always return 0x80. Bit 7 indicates RAM/TIME/battery OK, the * other bits are always zero. Return true if found. * * [Alternative method: Read all 4 status regs. If they're all the same @@ -259,9 +259,9 @@ int cmos_probe(void) { cmos_write(0xd, 0); if (((cmos_read(0xa) & 0x7f) == 0x26) && cmos_read(0xd)) - return 1; + return 1; //printf("CMOS status A %x, B %x, C %x, D %x\n", cmos_read(0xa), cmos_read(0xb), - //cmos_read(0xc), cmos_read(0xd)); + //cmos_read(0xc), cmos_read(0xd)); return 0; } @@ -293,7 +293,7 @@ int ast_getreg(int reg) int ast_getbcd(int reg) { - int val = ast_getreg(reg); + int val = ast_getreg(reg); return ((val & 15) + (val >> 4) * 10); } @@ -310,13 +310,13 @@ int ast_get_rbcd(int reg) */ int ast_chiptype(void) { - int tmp = (ast_getreg(AST_CHIPTYPE) & 0xf) | 2; + int tmp = (ast_getreg(AST_CHIPTYPE) & 0xf) | 2; /* 86box - when told to emulate ASTCLOCK, returns 2 from all registers */ /* Otherwise (all hw) returns 0xff */ if ((ast_getreg(1) + ast_getreg(2) + ast_getreg(3) + ast_getreg(4)) / 4 == ast_getreg(1)) - return -1; + return -1; ast_putreg(AST_CHIPTYPE, tmp); return (ast_getreg(AST_CHIPTYPE) & 0x2); @@ -326,15 +326,15 @@ int ast_chiptype(void) void show_astclock(void) { if (ast_chiptype()) { - printf("AST clock (NS): %d/%d/%d - %02d:%02d:%02d.%d\n", ast_getbcd(AST_NS_DOM), ast_getbcd(AST_NS_MON), - ast_getreg(AST_NS_YEAR) + 1980, ast_getbcd(AST_NS_HRS), ast_getbcd(AST_NS_MIN), - ast_getbcd(AST_NS_SEC), ast_getbcd(AST_NS_MSEC)); - printf("Other regs 00:%d, 01:%d, 05:%d, 08:%d, 09:%d\n", ast_getreg(0), ast_getreg(1), ast_getreg(5), - ast_getreg(8), ast_getreg(9)); + printf("AST clock (NS): %d/%d/%d - %02d:%02d:%02d.%d\n", ast_getbcd(AST_NS_DOM), ast_getbcd(AST_NS_MON), + ast_getreg(AST_NS_YEAR) + 1980, ast_getbcd(AST_NS_HRS), ast_getbcd(AST_NS_MIN), + ast_getbcd(AST_NS_SEC), ast_getbcd(AST_NS_MSEC)); + printf("Other regs 00:%d, 01:%d, 05:%d, 08:%d, 09:%d\n", ast_getreg(0), ast_getreg(1), ast_getreg(5), + ast_getreg(8), ast_getreg(9)); } else { - printf("AST clock (Ricoh): %d/%d/%d - %02d:%02d:%02d\n", ast_get_rbcd(AST_RI_DOM), - ast_get_rbcd(AST_RI_MON), ast_get_rbcd(AST_RI_YEAR) + 1980, ast_get_rbcd(AST_RI_HRS), - ast_get_rbcd(AST_RI_MIN), ast_get_rbcd(AST_RI_SEC)); + printf("AST clock (Ricoh): %d/%d/%d - %02d:%02d:%02d\n", ast_get_rbcd(AST_RI_DOM), + ast_get_rbcd(AST_RI_MON), ast_get_rbcd(AST_RI_YEAR) + 1980, ast_get_rbcd(AST_RI_HRS), + ast_get_rbcd(AST_RI_MIN), ast_get_rbcd(AST_RI_SEC)); } } #else @@ -360,12 +360,12 @@ time_t utc_mktime(struct tm *t) /* caluclate seconds from months */ for (i = 0; i < t->tm_mon; i++) { - ret += mday[i] * (24L * 60L * 60L); + ret += mday[i] * (24L * 60L * 60L); } /* add in this year's leap day, if any */ if (((t->tm_year & 3) == 0) && (t->tm_mon > 1)) { - ret += (24L * 60L * 60L); + ret += (24L * 60L * 60L); } /* calculate seconds from days in this month */ @@ -388,7 +388,7 @@ int main(int argc, char **argv) { struct tm tm; time_t systime; - int arg; + int arg; #ifdef CONFIG_ARCH_PC98 unsigned char timebuf[6]; @@ -402,62 +402,62 @@ int main(int argc, char **argv) #endif while ((arg = getopt(argc, argv, "rwsuvA")) != -1) { - switch (arg) { - case 'r': - readit = 1; - break; - case 'w': - writeit = 1; - break; - case 's': - setit = 1; - break; - case 'u': - universal = 1; - break; - case 'A': - astclock = 1; - break; - case 'v': - verbose = 1; - break; - default: - usage(); - } + switch (arg) { + case 'r': + readit = 1; + break; + case 'w': + writeit = 1; + break; + case 's': + setit = 1; + break; + case 'u': + universal = 1; + break; + case 'A': + astclock = 1; + break; + case 'v': + verbose = 1; + break; + default: + usage(); + } } if (!cmos_probe()) { - if (ast_chiptype() < 0) { - printf("No RTC found on system, not setting date and time\n"); - exit(1); - } else { - if (verbose) - printf("No CMOS clock found, assuming AST\n"); - astclock = 1; - show_astclock(); - } + if (ast_chiptype() < 0) { + printf("No RTC found on system, not setting date and time\n"); + exit(1); + } else { + if (verbose) + printf("No CMOS clock found, assuming AST\n"); + astclock = 1; + show_astclock(); + } } if (readit + writeit + setit > 1) - usage(); /* only allow one of these */ + usage(); /* only allow one of these */ - if (!(readit | writeit | setit)) /* default to read */ - readit = 1; + if (!(readit | writeit | setit)) /* default to read */ + readit = 1; if (readit || setit) { #ifdef CONFIG_ARCH_PC98 - pc98_read_calendar(tm_seg, tm_offset); - pc98_gettime(&tm, timebuf); + pc98_read_calendar(tm_seg, tm_offset); + pc98_gettime(&tm, timebuf); #else - if (astclock) - ast_gettime(&tm); - else - cmos_gettime(&tm); + if (astclock) + ast_gettime(&tm); + else + cmos_gettime(&tm); #endif - tm.tm_mon--; /* DOS uses 1 base */ - tm.tm_isdst = -1; /* don't know whether it's daylight */ + tm.tm_mon--; /* DOS uses 1 base */ + tm.tm_isdst = -1; /* don't know whether it's daylight */ } if (readit || setit) { @@ -465,11 +465,11 @@ int main(int argc, char **argv) * utc_mktime() assumes we're in Greenwich, England. If the CMOS * clock isn't in GMT, we need to adjust. */ - systime = utc_mktime(&tm); - if (!universal) { - tzset(); /* read TZ= env string and set timezone var */ - systime += timezone; - } + systime = utc_mktime(&tm); + if (!universal) { + tzset(); /* read TZ= env string and set timezone var */ + systime += timezone; + } #if 0 /* * mktime() assumes we're giving it local time. If the CMOS clock @@ -477,83 +477,83 @@ int main(int argc, char **argv) * called implicitly by the time code, but only the first time. When * changing the environment variable, better call tzset() explicitly. */ - if (universal) { - char *zone; - - zone = (char *)getenv("TZ"); /* save original time zone */ - (void)putenv("TZ="); - tzset(); - systime = mktime(&tm); - /* now put back the original zone */ - if (zone) { - char *zonebuf; - - zonebuf = malloc(strlen(zone) + 4); - strcpy(zonebuf, "TZ="); - strcpy(zonebuf + 3, zone); - putenv(zonebuf); - free(zonebuf); - } else { /* wasn't one, so clear it */ - putenv("TZ"); - } - tzset(); - } else - systime = mktime(&tm); -#endif /* 0 */ + if (universal) { + char *zone; + + zone = (char *)getenv("TZ"); /* save original time zone */ + (void)putenv("TZ="); + tzset(); + systime = mktime(&tm); + /* now put back the original zone */ + if (zone) { + char *zonebuf; + + zonebuf = malloc(strlen(zone) + 4); + strcpy(zonebuf, "TZ="); + strcpy(zonebuf + 3, zone); + putenv(zonebuf); + free(zonebuf); + } else { /* wasn't one, so clear it */ + putenv("TZ"); + } + tzset(); + } else + systime = mktime(&tm); +#endif /* 0 */ } if (readit) { - char *p = ctime(&systime); - if (verbose) - printf("From %s: ", astclock ? "ASTclock" : "CMOS"); - printf("%s", p); - //write(STDOUT_FILENO, p, strlen(p)); + char *p = ctime(&systime); + if (verbose) + printf("From %s: ", astclock ? "ASTclock" : "CMOS"); + printf("%s", p); + //write(STDOUT_FILENO, p, strlen(p)); } if (setit) { - struct timeval tv; - struct timezone tz; + struct timeval tv; + struct timezone tz; - /* program is designed to run setuid, be secure! */ + /* program is designed to run setuid, be secure! */ - if (getuid() != 0) { - errmsg("Sorry, must be root to set time\n"); - exit(2); - } + if (getuid() != 0) { + errmsg("Sorry, must be root to set time\n"); + exit(2); + } - tv.tv_sec = systime; - tv.tv_usec = 0; + tv.tv_sec = systime; + tv.tv_usec = 0; - /* - * system time is offset by TZ variable for now, localtime handled in - * C library - */ - tz.tz_minuteswest = 0; - tz.tz_dsttime = DST_NONE; + /* + * system time is offset by TZ variable for now, localtime handled in + * C library + */ + tz.tz_minuteswest = 0; + tz.tz_dsttime = DST_NONE; - if (settimeofday(&tv, &tz) != 0) { - errmsg("Unable to set time -- probably you are not root\n"); - exit(1); - } + if (settimeofday(&tv, &tz) != 0) { + errmsg("Unable to set time -- probably you are not root\n"); + exit(1); + } } if (writeit) { - struct tm *tmp; - systime = time(NULL); - if (universal) - tmp = gmtime(&systime); - else - tmp = localtime(&systime); + struct tm *tmp; + systime = time(NULL); + if (universal) + tmp = gmtime(&systime); + else + tmp = localtime(&systime); #ifdef CONFIG_ARCH_PC98 - pc98_settime(tmp, timebuf); - pc98_write_calendar(tm_seg, tm_offset); + pc98_settime(tmp, timebuf); + pc98_write_calendar(tm_seg, tm_offset); #else - if (astclock) - ast_settime(tmp); - else - cmos_settime(tmp); + if (astclock) + ast_settime(tmp); + else + cmos_settime(tmp); #endif } return 0; @@ -568,25 +568,25 @@ void ast_gettime(struct tm *tm) if (ast_chiptype()) { - do { /* NS clock chip */ - tm->tm_sec = ast_getbcd(AST_NS_SEC); - tm->tm_min = ast_getbcd(AST_NS_MIN); - tm->tm_hour = ast_getbcd(AST_NS_HRS); - tm->tm_wday = ast_getbcd(AST_NS_DOW); - tm->tm_mday = ast_getbcd(AST_NS_DOM); - tm->tm_mon = ast_getbcd(AST_NS_MON); - tm->tm_year = ast_getreg(AST_NS_YEAR); - } while (ast_getreg(AST_NS_STAT) && wait--); - - } else { /* Ricoh clock chip */ - - tm->tm_sec = ast_get_rbcd(AST_RI_SEC); - tm->tm_min = ast_get_rbcd(AST_RI_MIN); - tm->tm_hour = ast_get_rbcd(AST_RI_HRS); - tm->tm_wday = ast_getreg(AST_RI_DOW); - tm->tm_mday = ast_get_rbcd(AST_RI_DOM); - tm->tm_mon = ast_get_rbcd(AST_RI_MON); - tm->tm_year = ast_get_rbcd(AST_RI_YEAR); + do { /* NS clock chip */ + tm->tm_sec = ast_getbcd(AST_NS_SEC); + tm->tm_min = ast_getbcd(AST_NS_MIN); + tm->tm_hour = ast_getbcd(AST_NS_HRS); + tm->tm_wday = ast_getbcd(AST_NS_DOW); + tm->tm_mday = ast_getbcd(AST_NS_DOM); + tm->tm_mon = ast_getbcd(AST_NS_MON); + tm->tm_year = ast_getreg(AST_NS_YEAR); + } while (ast_getreg(AST_NS_STAT) && wait--); + + } else { /* Ricoh clock chip */ + + tm->tm_sec = ast_get_rbcd(AST_RI_SEC); + tm->tm_min = ast_get_rbcd(AST_RI_MIN); + tm->tm_hour = ast_get_rbcd(AST_RI_HRS); + tm->tm_wday = ast_getreg(AST_RI_DOW); + tm->tm_mday = ast_get_rbcd(AST_RI_DOM); + tm->tm_mon = ast_get_rbcd(AST_RI_MON); + tm->tm_year = ast_get_rbcd(AST_RI_YEAR); } tm->tm_year += 80 /* AST clock starts @ 1980 */ ; } @@ -595,42 +595,42 @@ void ast_gettime(struct tm *tm) void cmos_gettime(struct tm *tm) { do { - tm->tm_sec = cmos_read_bcd(0); - tm->tm_min = cmos_read_bcd(2); - tm->tm_hour = cmos_read_bcd(4); - tm->tm_wday = cmos_read_bcd(6); - tm->tm_mday = cmos_read_bcd(7); - tm->tm_mon = cmos_read_bcd(8); - tm->tm_year = cmos_read_bcd(9); + tm->tm_sec = cmos_read_bcd(0); + tm->tm_min = cmos_read_bcd(2); + tm->tm_hour = cmos_read_bcd(4); + tm->tm_wday = cmos_read_bcd(6); + tm->tm_mday = cmos_read_bcd(7); + tm->tm_mon = cmos_read_bcd(8); + tm->tm_year = cmos_read_bcd(9); } while (tm->tm_sec != cmos_read_bcd(0)); if (tm->tm_year < 70) - tm->tm_year += 100; /* 70..99 => 1970..1999, 0..69 => 2000..2069 */ + tm->tm_year += 100; /* 70..99 => 1970..1999, 0..69 => 2000..2069 */ } void ast_settime(struct tm *tmp) { if (ast_chiptype()) { - ast_putreg(AST_NS_CRST, 0xff); /* clear counters */ - ast_putbcd(AST_NS_SEC, tmp->tm_sec); - ast_putbcd(AST_NS_MIN, tmp->tm_min); - ast_putbcd(AST_NS_HRS, tmp->tm_hour); - ast_putbcd(AST_NS_DOW, tmp->tm_wday); - ast_putbcd(AST_NS_DOM, tmp->tm_mday); - ast_putbcd(AST_NS_MON, tmp->tm_mon + 1); - ast_putreg(AST_NS_YEAR, tmp->tm_year - 80); + ast_putreg(AST_NS_CRST, 0xff); /* clear counters */ + ast_putbcd(AST_NS_SEC, tmp->tm_sec); + ast_putbcd(AST_NS_MIN, tmp->tm_min); + ast_putbcd(AST_NS_HRS, tmp->tm_hour); + ast_putbcd(AST_NS_DOW, tmp->tm_wday); + ast_putbcd(AST_NS_DOM, tmp->tm_mday); + ast_putbcd(AST_NS_MON, tmp->tm_mon + 1); + ast_putreg(AST_NS_YEAR, tmp->tm_year - 80); } else { - /* - * no precautions (the Ricoh has 1 sec visible resolution, very DOS - * oriented. The ADJ bit does not do what you might think it does. - */ - ast_put_rbcd(AST_RI_SEC, tmp->tm_sec); - ast_put_rbcd(AST_RI_MIN, tmp->tm_min); - ast_put_rbcd(AST_RI_HRS, tmp->tm_hour); - ast_putreg(AST_RI_DOW, tmp->tm_wday); - ast_put_rbcd(AST_RI_DOM, tmp->tm_mday); - ast_put_rbcd(AST_RI_MON, tmp->tm_mon + 1); - ast_put_rbcd(AST_RI_YEAR, tmp->tm_year - 80); + /* + * no precautions (the Ricoh has 1 sec visible resolution, very DOS + * oriented. The ADJ bit does not do what you might think it does. + */ + ast_put_rbcd(AST_RI_SEC, tmp->tm_sec); + ast_put_rbcd(AST_RI_MIN, tmp->tm_min); + ast_put_rbcd(AST_RI_HRS, tmp->tm_hour); + ast_putreg(AST_RI_DOW, tmp->tm_wday); + ast_put_rbcd(AST_RI_DOM, tmp->tm_mday); + ast_put_rbcd(AST_RI_MON, tmp->tm_mon + 1); + ast_put_rbcd(AST_RI_YEAR, tmp->tm_year - 80); } } @@ -638,9 +638,9 @@ void cmos_settime(struct tm *tmp) { unsigned char save_control, save_freq_select; - save_control = cmos_read(11); /* tell the clock it's being set */ + save_control = cmos_read(11); /* tell the clock it's being set */ cmos_write(11, (save_control | 0x80)); - save_freq_select = cmos_read(10); /* stop and reset prescaler */ + save_freq_select = cmos_read(10); /* stop and reset prescaler */ cmos_write(10, (save_freq_select | 0x70)); cmos_write_bcd(0, tmp->tm_sec); @@ -655,27 +655,27 @@ void cmos_settime(struct tm *tmp) cmos_write(11, save_control); } -#else +#else void pc98_read_calendar(unsigned int tm_seg, unsigned int tm_offset) { __asm__ volatile ("mov %0,%%es;" - "mov $0,%%ah;" - "int $0x1C;" - : - :"a" (tm_seg), "b"(tm_offset) - :"%es", "memory", "cc"); + "mov $0,%%ah;" + "int $0x1C;" + : + :"a" (tm_seg), "b"(tm_offset) + :"%es", "memory", "cc"); } void pc98_write_calendar(unsigned int tm_seg, unsigned int tm_offset) { __asm__ volatile ("mov %0,%%es;" - "mov $1,%%ah;" - "int $0x1C;" - : - :"a" (tm_seg), "b"(tm_offset) - :"%es", "memory", "cc"); + "mov $1,%%ah;" + "int $0x1C;" + : + :"a" (tm_seg), "b"(tm_offset) + :"%es", "memory", "cc"); } @@ -698,20 +698,20 @@ void pc98_gettime(struct tm *tm, unsigned char *timebuf) tm->tm_mday = bcd_hex(timebuf[2]); tm->tm_mon = timebuf[1] >> 4; tm->tm_year = bcd_hex(timebuf[0]); - tm->tm_wday -= 3; /* DOS uses 3 - 9 for week days */ + tm->tm_wday -= 3; /* DOS uses 3 - 9 for week days */ } void pc98_settime(struct tm *tmp, unsigned char *timebuf) { - timebuf[5] = hex_bcd(tmp->tm_sec); - timebuf[4] = hex_bcd(tmp->tm_min); - timebuf[3] = hex_bcd(tmp->tm_hour); - timebuf[1] = hex_bcd(tmp->tm_wday); - timebuf[2] = hex_bcd(tmp->tm_mday); - timebuf[1] = (timebuf[1] & 0xF) + ((tmp->tm_mon + 1) << 4); - if (tmp->tm_year >= 100) - timebuf[0] = hex_bcd(tmp->tm_year - 100); - else - timebuf[0] = hex_bcd(tmp->tm_year); + timebuf[5] = hex_bcd(tmp->tm_sec); + timebuf[4] = hex_bcd(tmp->tm_min); + timebuf[3] = hex_bcd(tmp->tm_hour); + timebuf[1] = hex_bcd(tmp->tm_wday); + timebuf[2] = hex_bcd(tmp->tm_mday); + timebuf[1] = (timebuf[1] & 0xF) + ((tmp->tm_mon + 1) << 4); + if (tmp->tm_year >= 100) + timebuf[0] = hex_bcd(tmp->tm_year - 100); + else + timebuf[0] = hex_bcd(tmp->tm_year); } #endif From fb09e821b740e8deba9e69840b25ec75e5f6410e Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Thu, 25 Apr 2024 16:57:14 -0600 Subject: [PATCH 3/6] Get rid of printf to save 2208 bytes --- elkscmd/sys_utils/clock.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/elkscmd/sys_utils/clock.c b/elkscmd/sys_utils/clock.c index 242c3285a..af87941cc 100644 --- a/elkscmd/sys_utils/clock.c +++ b/elkscmd/sys_utils/clock.c @@ -1,3 +1,4 @@ +#include /* for CONFIG_ options */ #include #include #include @@ -18,7 +19,6 @@ * clock [-u] -a - set system time from cmos clock, adjust the time to * correct for systematic error, and put it back to the cmos. * -u indicates cmos clock is kept in universal time - * [check the usage() function for an updated list of options] * * The program is designed to run setuid, since we need to be able to * write the CMOS port. @@ -145,6 +145,8 @@ #define errmsg(str) write(STDERR_FILENO, str, sizeof(str) - 1) #define errstr(str) write(STDERR_FILENO, str, strlen(str)) +#define outmsg(str) write(STDOUT_FILENO, str, sizeof(str) - 1) +#define outstr(str) write(STDOUT_FILENO, str, strlen(str)) #define CMOS_CMDREG 0x70 #define CMOS_IOREG 0x71 @@ -260,8 +262,6 @@ int cmos_probe(void) cmos_write(0xd, 0); if (((cmos_read(0xa) & 0x7f) == 0x26) && cmos_read(0xd)) return 1; - //printf("CMOS status A %x, B %x, C %x, D %x\n", cmos_read(0xa), cmos_read(0xb), - //cmos_read(0xc), cmos_read(0xd)); return 0; } @@ -428,11 +428,11 @@ int main(int argc, char **argv) if (!cmos_probe()) { if (ast_chiptype() < 0) { - printf("No RTC found on system, not setting date and time\n"); + errmsg("No RTC found on system, not setting date and time\n"); exit(1); } else { if (verbose) - printf("No CMOS clock found, assuming AST\n"); + outmsg("No CMOS clock found, assuming AST\n"); astclock = 1; show_astclock(); } @@ -503,11 +503,8 @@ int main(int argc, char **argv) } if (readit) { - char *p = ctime(&systime); - if (verbose) - printf("From %s: ", astclock ? "ASTclock" : "CMOS"); - printf("%s", p); - //write(STDOUT_FILENO, p, strlen(p)); + char *p = ctime(&systime); + outstr(p); } if (setit) { From 88627fdcf6b14be80632cdbb2b0c35cd040a8fad Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Thu, 25 Apr 2024 17:20:07 -0600 Subject: [PATCH 4/6] Add in 8018X support, reduce executable size, updated man page --- elkscmd/man/man8/clock.8 | 7 ++- elkscmd/sys_utils/clock.c | 126 ++++++++++++++++++++++---------------- 2 files changed, 77 insertions(+), 56 deletions(-) diff --git a/elkscmd/man/man8/clock.8 b/elkscmd/man/man8/clock.8 index 9c97d2557..023a62d86 100644 --- a/elkscmd/man/man8/clock.8 +++ b/elkscmd/man/man8/clock.8 @@ -3,7 +3,7 @@ clock \- Read or modify the hardware clock .SH SYNOPSIS .B clock -.B [\-u] {\-r,\-w,\-s,\-a,\-v} +.B [\-u] {\-r,\-w,\-s,\-A,\-v} .SH DESCRIPTION .BR clock is used to read from or write to the hardware clock, and to @@ -26,8 +26,11 @@ Set the system time from the hardware clock. Set the system time from the hardware clock, adjust for systematic errors, and then write the system time to the hardware clock. .TP +.B "\-A" +Assume AST clock hardware. +.TP .B "\-v" -Print version information and exit. +Verbose mode. .SH EXIT STATUS .TP .I 0 diff --git a/elkscmd/sys_utils/clock.c b/elkscmd/sys_utils/clock.c index af87941cc..158a15bcb 100644 --- a/elkscmd/sys_utils/clock.c +++ b/elkscmd/sys_utils/clock.c @@ -143,6 +143,8 @@ * systems. Supports both NS and Ricoh chips. */ +#define AST_SUPPORT 0 /* =1 to compile in AST hardware support */ + #define errmsg(str) write(STDERR_FILENO, str, sizeof(str) - 1) #define errstr(str) write(STDERR_FILENO, str, strlen(str)) #define outmsg(str) write(STDOUT_FILENO, str, sizeof(str) - 1) @@ -182,12 +184,12 @@ * this register */ /* Globals */ -int readit = 0; -int writeit = 0; -int setit = 0; -int universal = 0; -int astclock = 0; -int verbose = 0; +int readit; +int writeit; +int setit; +int universal; +int astclock; +int verbose; #ifdef CONFIG_ARCH_PC98 void pc98_settime(struct tm *, unsigned char *); @@ -195,26 +197,40 @@ void pc98_gettime(struct tm *, unsigned char *); void pc98_write_calendar(unsigned int, unsigned int); void pc98_read_calendar(unsigned int, unsigned int); #else -void ast_settime(struct tm *); -void ast_gettime(struct tm *); void cmos_settime(struct tm *); void cmos_gettime(struct tm *); #endif -/* #define AST_TEST */ +#if AST_SUPPORT +void ast_settime(struct tm *); +void ast_gettime(struct tm *); +#endif int usage(void) { - errmsg("clock [-u] -r|w|s|v|A\n"); - errmsg(" r: read and print CMOS clock\n"); - errmsg(" w: write CMOS clock from system time\n"); - errmsg(" s: set system time from CMOS clock\n"); - errmsg(" u: CMOS clock is in universal time\n"); - errmsg(" v: verbose mode\n"); - errmsg(" A: assume ASTCLOCK type RTC, increase verbosity\n"); + errmsg("clock [-u] {-r,-w,-s,-v,-A}\n"); exit(1); } +#ifdef CONFIG_ARCH_8018X +unsigned char cmos_read(unsigned char reg) +{ + register unsigned char ret; + clr_irq (); + ret = inb_p (CONFIG_8018X_RTC + reg); + set_irq (); + return ret; +} + +void cmos_write(unsigned char reg, unsigned char val) +{ + clr_irq (); + outb_p (val, CONFIG_8018X_RTC + reg); + set_irq (); +} + +#else + unsigned char cmos_read(unsigned char reg) { register unsigned char ret; @@ -233,6 +249,7 @@ void cmos_write(unsigned char reg, unsigned char val) outb_p(val, 0x71); set_irq(); } +#endif int cmos_read_bcd(int addr) { @@ -265,6 +282,7 @@ int cmos_probe(void) return 0; } +#if AST_SUPPORT void ast_putreg(unsigned char reg, unsigned char val) { clr_irq(); @@ -322,7 +340,7 @@ int ast_chiptype(void) return (ast_getreg(AST_CHIPTYPE) & 0x2); } -#ifdef AST_TEST +#if DEBUG void show_astclock(void) { if (ast_chiptype()) { @@ -340,6 +358,7 @@ void show_astclock(void) #else #define show_astclock(x) #endif +#endif /* our own happy mktime() replacement, with the following drawbacks: */ /* doesn't check boundary conditions */ @@ -426,6 +445,7 @@ int main(int argc, char **argv) } } +#if AST_SUPPORT if (!cmos_probe()) { if (ast_chiptype() < 0) { errmsg("No RTC found on system, not setting date and time\n"); @@ -437,6 +457,7 @@ int main(int argc, char **argv) show_astclock(); } } +#endif if (readit + writeit + setit > 1) usage(); /* only allow one of these */ @@ -450,10 +471,11 @@ int main(int argc, char **argv) pc98_read_calendar(tm_seg, tm_offset); pc98_gettime(&tm, timebuf); #else - +#if AST_SUPPORT if (astclock) ast_gettime(&tm); else +#endif cmos_gettime(&tm); #endif tm.tm_mon--; /* DOS uses 1 base */ @@ -461,10 +483,10 @@ int main(int argc, char **argv) } if (readit || setit) { -/* - * utc_mktime() assumes we're in Greenwich, England. If the CMOS - * clock isn't in GMT, we need to adjust. - */ + /* + * utc_mktime() assumes we're in Greenwich, England. If the CMOS + * clock isn't in GMT, we need to adjust. + */ systime = utc_mktime(&tm); if (!universal) { tzset(); /* read TZ= env string and set timezone var */ @@ -478,23 +500,18 @@ int main(int argc, char **argv) * changing the environment variable, better call tzset() explicitly. */ if (universal) { - char *zone; - - zone = (char *)getenv("TZ"); /* save original time zone */ - (void)putenv("TZ="); + char *zone = (char *)getenv("TZ"); /* save original time zone */ + putenv("TZ="); tzset(); systime = mktime(&tm); /* now put back the original zone */ if (zone) { - char *zonebuf; - - zonebuf = malloc(strlen(zone) + 4); + char zonebuf[256]; strcpy(zonebuf, "TZ="); strcpy(zonebuf + 3, zone); putenv(zonebuf); - free(zonebuf); } else { /* wasn't one, so clear it */ - putenv("TZ"); + putenv("TZ="); } tzset(); } else @@ -512,7 +529,6 @@ int main(int argc, char **argv) struct timezone tz; /* program is designed to run setuid, be secure! */ - if (getuid() != 0) { errmsg("Sorry, must be root to set time\n"); exit(2); @@ -547,17 +563,18 @@ int main(int argc, char **argv) pc98_settime(tmp, timebuf); pc98_write_calendar(tm_seg, tm_offset); #else +#if AST_SUPPORT if (astclock) ast_settime(tmp); else +#endif cmos_settime(tmp); #endif } return 0; } -#ifndef CONFIG_ARCH_PC98 - +#if AST_SUPPORT /* set time from AST SixPakPlus type RTC */ void ast_gettime(struct tm *tm) { @@ -588,23 +605,6 @@ void ast_gettime(struct tm *tm) tm->tm_year += 80 /* AST clock starts @ 1980 */ ; } -/* set time from AT style CMOS RTC (mc146818) */ -void cmos_gettime(struct tm *tm) -{ - do { - tm->tm_sec = cmos_read_bcd(0); - tm->tm_min = cmos_read_bcd(2); - tm->tm_hour = cmos_read_bcd(4); - tm->tm_wday = cmos_read_bcd(6); - tm->tm_mday = cmos_read_bcd(7); - tm->tm_mon = cmos_read_bcd(8); - tm->tm_year = cmos_read_bcd(9); - } while (tm->tm_sec != cmos_read_bcd(0)); - - if (tm->tm_year < 70) - tm->tm_year += 100; /* 70..99 => 1970..1999, 0..69 => 2000..2069 */ -} - void ast_settime(struct tm *tmp) { if (ast_chiptype()) { @@ -630,6 +630,25 @@ void ast_settime(struct tm *tmp) ast_put_rbcd(AST_RI_YEAR, tmp->tm_year - 80); } } +#endif + +#ifndef CONFIG_ARCH_PC98 +/* set time from AT style CMOS RTC (mc146818) */ +void cmos_gettime(struct tm *tm) +{ + do { + tm->tm_sec = cmos_read_bcd(0); + tm->tm_min = cmos_read_bcd(2); + tm->tm_hour = cmos_read_bcd(4); + tm->tm_wday = cmos_read_bcd(6); + tm->tm_mday = cmos_read_bcd(7); + tm->tm_mon = cmos_read_bcd(8); + tm->tm_year = cmos_read_bcd(9); + } while (tm->tm_sec != cmos_read_bcd(0)); + + if (tm->tm_year < 70) + tm->tm_year += 100; /* 70..99 => 1970..1999, 0..69 => 2000..2069 */ +} void cmos_settime(struct tm *tmp) { @@ -653,7 +672,6 @@ void cmos_settime(struct tm *tmp) } #else - void pc98_read_calendar(unsigned int tm_seg, unsigned int tm_offset) { __asm__ volatile ("mov %0,%%es;" @@ -676,12 +694,12 @@ void pc98_write_calendar(unsigned int tm_seg, unsigned int tm_offset) } -int bcd_hex(unsigned char bcd_data) +static int bcd_hex(unsigned char bcd_data) { return (bcd_data & 15) + (bcd_data >> 4) * 10; } -int hex_bcd(int hex_data) +static int hex_bcd(int hex_data) { return ((hex_data / 10) << 4) + hex_data % 10; } From a1b8831b8c753c9998f3d3f3e7720adba9a25d4f Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Thu, 25 Apr 2024 17:47:30 -0600 Subject: [PATCH 5/6] Reorganize AST, CMOS, PC98 RTC routines --- elkscmd/man/man8/clock.8 | 9 +- elkscmd/sys_utils/clock.c | 506 +++++++++++++++++++------------------- 2 files changed, 256 insertions(+), 259 deletions(-) diff --git a/elkscmd/man/man8/clock.8 b/elkscmd/man/man8/clock.8 index 023a62d86..a49fe8a7c 100644 --- a/elkscmd/man/man8/clock.8 +++ b/elkscmd/man/man8/clock.8 @@ -3,7 +3,7 @@ clock \- Read or modify the hardware clock .SH SYNOPSIS .B clock -.B [\-u] {\-r,\-w,\-s,\-A,\-v} +.B [\-u] {\-r,\-w,\-s,\-A} .SH DESCRIPTION .BR clock is used to read from or write to the hardware clock, and to @@ -22,15 +22,8 @@ Write the system time to the hardware clock. .B "\-s" Set the system time from the hardware clock. .TP -.B "\-s" -Set the system time from the hardware clock, adjust for systematic errors, -and then write the system time to the hardware clock. -.TP .B "\-A" Assume AST clock hardware. -.TP -.B "\-v" -Verbose mode. .SH EXIT STATUS .TP .I 0 diff --git a/elkscmd/sys_utils/clock.c b/elkscmd/sys_utils/clock.c index 158a15bcb..7ca843aae 100644 --- a/elkscmd/sys_utils/clock.c +++ b/elkscmd/sys_utils/clock.c @@ -143,46 +143,17 @@ * systems. Supports both NS and Ricoh chips. */ +#ifdef CONFIG_ARCH_IBMPC #define AST_SUPPORT 0 /* =1 to compile in AST hardware support */ +#else +#define AST_SUPPORT 0 +#endif #define errmsg(str) write(STDERR_FILENO, str, sizeof(str) - 1) #define errstr(str) write(STDERR_FILENO, str, strlen(str)) #define outmsg(str) write(STDOUT_FILENO, str, sizeof(str) - 1) #define outstr(str) write(STDOUT_FILENO, str, strlen(str)) -#define CMOS_CMDREG 0x70 -#define CMOS_IOREG 0x71 - -#define AST_CMDREG 0x2C0 -#define AST_IOREG 0x2C1 - -#define AST_RETRY 1000 - -/* for Nat Semi chip */ -#define AST_NS_MSEC 0x01 -#define AST_NS_SEC 0x02 -#define AST_NS_MIN 0x03 /* get minute cntr */ -#define AST_NS_HRS 0x04 /* get hour cntr */ -#define AST_NS_DOW 0x05 /* day of week */ -#define AST_NS_DOM 0x06 /* day of month */ -#define AST_NS_MON 0x07 /* month of year */ -#define AST_NS_YEAR 0x0A /* year, counts from 1980 */ -#define AST_NS_STAT 0x14 /* get status bit */ -#define AST_NS_CRST 0x12 /* clear counters */ -#define AST_NS_GO 0x15 /* clear subsec counters */ - -/* for Ricoh chip */ -#define AST_RI_SEC 0 -#define AST_RI_MIN 2 -#define AST_RI_HRS 4 -#define AST_RI_DOW 6 /* one reg, the others are two (BCD) */ -#define AST_RI_DOM 7 -#define AST_RI_MON 9 -#define AST_RI_YEAR 11 - -#define AST_CHIPTYPE 0x0D /* Distinguish between Ricoh and NS chip via - * this register */ - /* Globals */ int readit; int writeit; @@ -191,174 +162,31 @@ int universal; int astclock; int verbose; +#if defined(CONFIG_ARCH_IBMPC) || defined(CONFIG_ARCH_8018X) +void cmos_settime(struct tm *); +void cmos_gettime(struct tm *); +#endif + #ifdef CONFIG_ARCH_PC98 -void pc98_settime(struct tm *, unsigned char *); -void pc98_gettime(struct tm *, unsigned char *); -void pc98_write_calendar(unsigned int, unsigned int); -void pc98_read_calendar(unsigned int, unsigned int); -#else -void cmos_settime(struct tm *); -void cmos_gettime(struct tm *); +void pc98_settime(struct tm *, unsigned char *); +void pc98_gettime(struct tm *, unsigned char *); +void pc98_write_calendar(unsigned int, unsigned int); +void pc98_read_calendar(unsigned int, unsigned int); #endif #if AST_SUPPORT -void ast_settime(struct tm *); -void ast_gettime(struct tm *); +void ast_settime(struct tm *); +void ast_gettime(struct tm *); +int ast_chiptype(void); +int cmos_probe(void); #endif int usage(void) { - errmsg("clock [-u] {-r,-w,-s,-v,-A}\n"); + errmsg("clock [-u] {-r,-w,-s,-A}\n"); exit(1); } -#ifdef CONFIG_ARCH_8018X -unsigned char cmos_read(unsigned char reg) -{ - register unsigned char ret; - clr_irq (); - ret = inb_p (CONFIG_8018X_RTC + reg); - set_irq (); - return ret; -} - -void cmos_write(unsigned char reg, unsigned char val) -{ - clr_irq (); - outb_p (val, CONFIG_8018X_RTC + reg); - set_irq (); -} - -#else - -unsigned char cmos_read(unsigned char reg) -{ - register unsigned char ret; - - clr_irq(); - outb_p(reg | 0x80, 0x70); - ret = inb_p(0x71); - set_irq(); - return ret; -} - -void cmos_write(unsigned char reg, unsigned char val) -{ - clr_irq(); - outb_p(reg | 0x80, 0x70); - outb_p(val, 0x71); - set_irq(); -} -#endif - -int cmos_read_bcd(int addr) -{ - int b; - - b = cmos_read(addr); - return (b & 15) + (b >> 4) * 10; -} - -void cmos_write_bcd(int addr, int value) -{ - cmos_write(addr, ((value / 10) << 4) + value % 10); -} - -/* PROBE to verify existence: Read CMOS status register A, check - * for sanity (0x26), ignore the UpdateInProgress flag (bit 7, comes and goes). - * Then write 0 to status reg D, which is read only, and read it back. - * Should always return 0x80. Bit 7 indicates RAM/TIME/battery OK, the - * other bits are always zero. Return true if found. - * - * [Alternative method: Read all 4 status regs. If they're all the same - * there's nothing there. For reference, on physical systems the readback is 0x48, - * on emulators 0xff] - */ -int cmos_probe(void) -{ - cmos_write(0xd, 0); - if (((cmos_read(0xa) & 0x7f) == 0x26) && cmos_read(0xd)) - return 1; - return 0; -} - -#if AST_SUPPORT -void ast_putreg(unsigned char reg, unsigned char val) -{ - clr_irq(); - outb_p(reg, AST_CMDREG); - outb_p(val, AST_IOREG); - set_irq(); -} - -void ast_putbcd(int addr, int value) -{ - ast_putreg(addr, ((value / 10) << 4) + value % 10); -} - -/* The Ricoh has 4 bit addressing only, BCD values are in adjacent addresses */ -void ast_put_rbcd(int addr, int value) -{ - ast_putreg(addr, value % 10); - ast_putreg(addr + 1, value / 10); -} - -int ast_getreg(int reg) -{ - outb(reg, AST_CMDREG); - return (inb(AST_IOREG)); -} - -int ast_getbcd(int reg) -{ - int val = ast_getreg(reg); - - return ((val & 15) + (val >> 4) * 10); -} - -int ast_get_rbcd(int reg) -{ - return ((ast_getreg(reg) & 0xf) + (ast_getreg(reg + 1) & 0xf) * 10); -} - -/* - * Per the AST app note, bit 1 in reg D may be used to determine which chip we're using. - * This bit will always return 0 on the Ricoh, on the NS it's RAM and we'll read back what we write. - * Returns 0 if Ricoh chip, 2 if NS chip, -1 if neither. - */ -int ast_chiptype(void) -{ - int tmp = (ast_getreg(AST_CHIPTYPE) & 0xf) | 2; - - /* 86box - when told to emulate ASTCLOCK, returns 2 from all registers */ - /* Otherwise (all hw) returns 0xff */ - - if ((ast_getreg(1) + ast_getreg(2) + ast_getreg(3) + ast_getreg(4)) / 4 == ast_getreg(1)) - return -1; - - ast_putreg(AST_CHIPTYPE, tmp); - return (ast_getreg(AST_CHIPTYPE) & 0x2); -} - -#if DEBUG -void show_astclock(void) -{ - if (ast_chiptype()) { - printf("AST clock (NS): %d/%d/%d - %02d:%02d:%02d.%d\n", ast_getbcd(AST_NS_DOM), ast_getbcd(AST_NS_MON), - ast_getreg(AST_NS_YEAR) + 1980, ast_getbcd(AST_NS_HRS), ast_getbcd(AST_NS_MIN), - ast_getbcd(AST_NS_SEC), ast_getbcd(AST_NS_MSEC)); - printf("Other regs 00:%d, 01:%d, 05:%d, 08:%d, 09:%d\n", ast_getreg(0), ast_getreg(1), ast_getreg(5), - ast_getreg(8), ast_getreg(9)); - } else { - printf("AST clock (Ricoh): %d/%d/%d - %02d:%02d:%02d\n", ast_get_rbcd(AST_RI_DOM), - ast_get_rbcd(AST_RI_MON), ast_get_rbcd(AST_RI_YEAR) + 1980, ast_get_rbcd(AST_RI_HRS), - ast_get_rbcd(AST_RI_MIN), ast_get_rbcd(AST_RI_SEC)); - } -} -#else -#define show_astclock(x) -#endif -#endif /* our own happy mktime() replacement, with the following drawbacks: */ /* doesn't check boundary conditions */ @@ -437,9 +265,6 @@ int main(int argc, char **argv) case 'A': astclock = 1; break; - case 'v': - verbose = 1; - break; default: usage(); } @@ -451,10 +276,8 @@ int main(int argc, char **argv) errmsg("No RTC found on system, not setting date and time\n"); exit(1); } else { - if (verbose) - outmsg("No CMOS clock found, assuming AST\n"); + outmsg("No CMOS clock found, assuming AST\n"); astclock = 1; - show_astclock(); } } #endif @@ -493,12 +316,12 @@ int main(int argc, char **argv) systime += timezone; } #if 0 -/* - * mktime() assumes we're giving it local time. If the CMOS clock - * is in GMT, we have to set up TZ so mktime knows it. tzset() gets - * called implicitly by the time code, but only the first time. When - * changing the environment variable, better call tzset() explicitly. - */ + /* + * mktime() assumes we're giving it local time. If the CMOS clock + * is in GMT, we have to set up TZ so mktime knows it. tzset() gets + * called implicitly by the time code, but only the first time. When + * changing the environment variable, better call tzset() explicitly. + */ if (universal) { char *zone = (char *)getenv("TZ"); /* save original time zone */ putenv("TZ="); @@ -574,65 +397,64 @@ int main(int argc, char **argv) return 0; } -#if AST_SUPPORT -/* set time from AST SixPakPlus type RTC */ -void ast_gettime(struct tm *tm) +/****************************************************************************/ +#if defined(CONFIG_ARCH_IBMPC) || defined(CONFIG_ARCH_8018X) +#define CMOS_CMDREG 0x70 +#define CMOS_IOREG 0x71 + +#ifdef CONFIG_ARCH_IBMPC +unsigned char cmos_read(unsigned char reg) { - int wait = AST_RETRY; + register unsigned char ret; - if (ast_chiptype()) { + clr_irq(); + outb_p(reg | 0x80, 0x70); + ret = inb_p(0x71); + set_irq(); + return ret; +} - do { /* NS clock chip */ - tm->tm_sec = ast_getbcd(AST_NS_SEC); - tm->tm_min = ast_getbcd(AST_NS_MIN); - tm->tm_hour = ast_getbcd(AST_NS_HRS); - tm->tm_wday = ast_getbcd(AST_NS_DOW); - tm->tm_mday = ast_getbcd(AST_NS_DOM); - tm->tm_mon = ast_getbcd(AST_NS_MON); - tm->tm_year = ast_getreg(AST_NS_YEAR); - } while (ast_getreg(AST_NS_STAT) && wait--); +void cmos_write(unsigned char reg, unsigned char val) +{ + clr_irq(); + outb_p(reg | 0x80, 0x70); + outb_p(val, 0x71); + set_irq(); +} +#endif - } else { /* Ricoh clock chip */ +#ifdef CONFIG_ARCH_8018X +unsigned char cmos_read(unsigned char reg) +{ + register unsigned char ret; - tm->tm_sec = ast_get_rbcd(AST_RI_SEC); - tm->tm_min = ast_get_rbcd(AST_RI_MIN); - tm->tm_hour = ast_get_rbcd(AST_RI_HRS); - tm->tm_wday = ast_getreg(AST_RI_DOW); - tm->tm_mday = ast_get_rbcd(AST_RI_DOM); - tm->tm_mon = ast_get_rbcd(AST_RI_MON); - tm->tm_year = ast_get_rbcd(AST_RI_YEAR); - } - tm->tm_year += 80 /* AST clock starts @ 1980 */ ; + clr_irq (); + ret = inb_p (CONFIG_8018X_RTC + reg); + set_irq (); + return ret; } -void ast_settime(struct tm *tmp) +void cmos_write(unsigned char reg, unsigned char val) { - if (ast_chiptype()) { - ast_putreg(AST_NS_CRST, 0xff); /* clear counters */ - ast_putbcd(AST_NS_SEC, tmp->tm_sec); - ast_putbcd(AST_NS_MIN, tmp->tm_min); - ast_putbcd(AST_NS_HRS, tmp->tm_hour); - ast_putbcd(AST_NS_DOW, tmp->tm_wday); - ast_putbcd(AST_NS_DOM, tmp->tm_mday); - ast_putbcd(AST_NS_MON, tmp->tm_mon + 1); - ast_putreg(AST_NS_YEAR, tmp->tm_year - 80); - } else { - /* - * no precautions (the Ricoh has 1 sec visible resolution, very DOS - * oriented. The ADJ bit does not do what you might think it does. - */ - ast_put_rbcd(AST_RI_SEC, tmp->tm_sec); - ast_put_rbcd(AST_RI_MIN, tmp->tm_min); - ast_put_rbcd(AST_RI_HRS, tmp->tm_hour); - ast_putreg(AST_RI_DOW, tmp->tm_wday); - ast_put_rbcd(AST_RI_DOM, tmp->tm_mday); - ast_put_rbcd(AST_RI_MON, tmp->tm_mon + 1); - ast_put_rbcd(AST_RI_YEAR, tmp->tm_year - 80); - } + clr_irq (); + outb_p (val, CONFIG_8018X_RTC + reg); + set_irq (); } #endif -#ifndef CONFIG_ARCH_PC98 +static int cmos_read_bcd(int addr) +{ + int b; + + b = cmos_read(addr); + return (b & 15) + (b >> 4) * 10; +} + +static void cmos_write_bcd(int addr, int value) +{ + cmos_write(addr, ((value / 10) << 4) + value % 10); +} + /* set time from AT style CMOS RTC (mc146818) */ void cmos_gettime(struct tm *tm) { @@ -670,8 +492,10 @@ void cmos_settime(struct tm *tmp) cmos_write(10, save_freq_select); cmos_write(11, save_control); } +#endif -#else +/****************************************************************************/ +#ifdef CONFIG_ARCH_PC98 void pc98_read_calendar(unsigned int tm_seg, unsigned int tm_offset) { __asm__ volatile ("mov %0,%%es;" @@ -730,3 +554,183 @@ void pc98_settime(struct tm *tmp, unsigned char *timebuf) timebuf[0] = hex_bcd(tmp->tm_year); } #endif + +/****************************************************************************/ +#if AST_SUPPORT +#define AST_CMDREG 0x2C0 +#define AST_IOREG 0x2C1 + +#define AST_RETRY 1000 + +/* for Nat Semi chip */ +#define AST_NS_MSEC 0x01 +#define AST_NS_SEC 0x02 +#define AST_NS_MIN 0x03 /* get minute cntr */ +#define AST_NS_HRS 0x04 /* get hour cntr */ +#define AST_NS_DOW 0x05 /* day of week */ +#define AST_NS_DOM 0x06 /* day of month */ +#define AST_NS_MON 0x07 /* month of year */ +#define AST_NS_YEAR 0x0A /* year, counts from 1980 */ +#define AST_NS_STAT 0x14 /* get status bit */ +#define AST_NS_CRST 0x12 /* clear counters */ +#define AST_NS_GO 0x15 /* clear subsec counters */ + +/* for Ricoh chip */ +#define AST_RI_SEC 0 +#define AST_RI_MIN 2 +#define AST_RI_HRS 4 +#define AST_RI_DOW 6 /* one reg, the others are two (BCD) */ +#define AST_RI_DOM 7 +#define AST_RI_MON 9 +#define AST_RI_YEAR 11 + +#define AST_CHIPTYPE 0x0D /* Distinguish between Ricoh and NS chip via + * this register */ +static void ast_putreg(unsigned char reg, unsigned char val) +{ + clr_irq(); + outb_p(reg, AST_CMDREG); + outb_p(val, AST_IOREG); + set_irq(); +} + +static void ast_putbcd(int addr, int value) +{ + ast_putreg(addr, ((value / 10) << 4) + value % 10); +} + +/* The Ricoh has 4 bit addressing only, BCD values are in adjacent addresses */ +static void ast_put_rbcd(int addr, int value) +{ + ast_putreg(addr, value % 10); + ast_putreg(addr + 1, value / 10); +} + +static int ast_getreg(int reg) +{ + outb(reg, AST_CMDREG); + return (inb(AST_IOREG)); +} + +static int ast_getbcd(int reg) +{ + int val = ast_getreg(reg); + + return ((val & 15) + (val >> 4) * 10); +} + +static int ast_get_rbcd(int reg) +{ + return ((ast_getreg(reg) & 0xf) + (ast_getreg(reg + 1) & 0xf) * 10); +} + +/* + * Per the AST app note, bit 1 in reg D may be used to determine which chip we're using. + * This bit will always return 0 on the Ricoh, on the NS it's RAM and we'll read back what we write. + * Returns 0 if Ricoh chip, 2 if NS chip, -1 if neither. + */ +int ast_chiptype(void) +{ + int tmp = (ast_getreg(AST_CHIPTYPE) & 0xf) | 2; + + /* 86box - when told to emulate ASTCLOCK, returns 2 from all registers */ + /* Otherwise (all hw) returns 0xff */ + + if ((ast_getreg(1) + ast_getreg(2) + ast_getreg(3) + ast_getreg(4)) / 4 == ast_getreg(1)) + return -1; + + ast_putreg(AST_CHIPTYPE, tmp); + return (ast_getreg(AST_CHIPTYPE) & 0x2); +} + +#if DEBUG +void show_astclock(void) +{ + if (ast_chiptype()) { + printf("AST clock (NS): %d/%d/%d - %02d:%02d:%02d.%d\n", ast_getbcd(AST_NS_DOM), ast_getbcd(AST_NS_MON), + ast_getreg(AST_NS_YEAR) + 1980, ast_getbcd(AST_NS_HRS), ast_getbcd(AST_NS_MIN), + ast_getbcd(AST_NS_SEC), ast_getbcd(AST_NS_MSEC)); + printf("Other regs 00:%d, 01:%d, 05:%d, 08:%d, 09:%d\n", ast_getreg(0), ast_getreg(1), ast_getreg(5), + ast_getreg(8), ast_getreg(9)); + } else { + printf("AST clock (Ricoh): %d/%d/%d - %02d:%02d:%02d\n", ast_get_rbcd(AST_RI_DOM), + ast_get_rbcd(AST_RI_MON), ast_get_rbcd(AST_RI_YEAR) + 1980, ast_get_rbcd(AST_RI_HRS), + ast_get_rbcd(AST_RI_MIN), ast_get_rbcd(AST_RI_SEC)); + } +} +#endif + +/* set time from AST SixPakPlus type RTC */ +void ast_gettime(struct tm *tm) +{ + int wait = AST_RETRY; + + if (ast_chiptype()) { + + do { /* NS clock chip */ + tm->tm_sec = ast_getbcd(AST_NS_SEC); + tm->tm_min = ast_getbcd(AST_NS_MIN); + tm->tm_hour = ast_getbcd(AST_NS_HRS); + tm->tm_wday = ast_getbcd(AST_NS_DOW); + tm->tm_mday = ast_getbcd(AST_NS_DOM); + tm->tm_mon = ast_getbcd(AST_NS_MON); + tm->tm_year = ast_getreg(AST_NS_YEAR); + } while (ast_getreg(AST_NS_STAT) && wait--); + + } else { /* Ricoh clock chip */ + + tm->tm_sec = ast_get_rbcd(AST_RI_SEC); + tm->tm_min = ast_get_rbcd(AST_RI_MIN); + tm->tm_hour = ast_get_rbcd(AST_RI_HRS); + tm->tm_wday = ast_getreg(AST_RI_DOW); + tm->tm_mday = ast_get_rbcd(AST_RI_DOM); + tm->tm_mon = ast_get_rbcd(AST_RI_MON); + tm->tm_year = ast_get_rbcd(AST_RI_YEAR); + } + tm->tm_year += 80 /* AST clock starts @ 1980 */ ; +} + +void ast_settime(struct tm *tmp) +{ + if (ast_chiptype()) { + ast_putreg(AST_NS_CRST, 0xff); /* clear counters */ + ast_putbcd(AST_NS_SEC, tmp->tm_sec); + ast_putbcd(AST_NS_MIN, tmp->tm_min); + ast_putbcd(AST_NS_HRS, tmp->tm_hour); + ast_putbcd(AST_NS_DOW, tmp->tm_wday); + ast_putbcd(AST_NS_DOM, tmp->tm_mday); + ast_putbcd(AST_NS_MON, tmp->tm_mon + 1); + ast_putreg(AST_NS_YEAR, tmp->tm_year - 80); + } else { + /* + * no precautions (the Ricoh has 1 sec visible resolution, very DOS + * oriented. The ADJ bit does not do what you might think it does. + */ + ast_put_rbcd(AST_RI_SEC, tmp->tm_sec); + ast_put_rbcd(AST_RI_MIN, tmp->tm_min); + ast_put_rbcd(AST_RI_HRS, tmp->tm_hour); + ast_putreg(AST_RI_DOW, tmp->tm_wday); + ast_put_rbcd(AST_RI_DOM, tmp->tm_mday); + ast_put_rbcd(AST_RI_MON, tmp->tm_mon + 1); + ast_put_rbcd(AST_RI_YEAR, tmp->tm_year - 80); + } +} + +/* PROBE to verify existence: Read CMOS status register A, check + * for sanity (0x26), ignore the UpdateInProgress flag (bit 7, comes and goes). + * Then write 0 to status reg D, which is read only, and read it back. + * Should always return 0x80. Bit 7 indicates RAM/TIME/battery OK, the + * other bits are always zero. Return true if found. + * + * [Alternative method: Read all 4 status regs. If they're all the same + * there's nothing there. For reference, on physical systems the readback is 0x48, + * on emulators 0xff] + */ +int cmos_probe(void) +{ + cmos_write(0xd, 0); + if (((cmos_read(0xa) & 0x7f) == 0x26) && cmos_read(0xd)) + return 1; + return 0; +} +#endif /* AST_SUPPORT */ From 3d4e386e0cf6913a9dac209e67b4e332393e87b0 Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Thu, 25 Apr 2024 18:43:13 -0600 Subject: [PATCH 6/6] Fix PC98 clock routine, add do_gettime, do_settime --- elkscmd/rootfs_template/bootopts | 2 +- elkscmd/sys_utils/clock.c | 89 ++++++++++++++++++-------------- 2 files changed, 52 insertions(+), 39 deletions(-) diff --git a/elkscmd/rootfs_template/bootopts b/elkscmd/rootfs_template/bootopts index a2072ac36..0a5a26a46 100644 --- a/elkscmd/rootfs_template/bootopts +++ b/elkscmd/rootfs_template/bootopts @@ -1,5 +1,5 @@ ## max 511 bytes -#TZ=MDT8 +#TZ=MDT6 #LOCALIP=10.0.2.16 #HOSTNAME=elks16 #ne0=12,0x300,,0x80 diff --git a/elkscmd/sys_utils/clock.c b/elkscmd/sys_utils/clock.c index 7ca843aae..f33e3614e 100644 --- a/elkscmd/sys_utils/clock.c +++ b/elkscmd/sys_utils/clock.c @@ -162,6 +162,9 @@ int universal; int astclock; int verbose; +void do_gettime(struct tm *); +void do_settime(struct tm *); + #if defined(CONFIG_ARCH_IBMPC) || defined(CONFIG_ARCH_8018X) void cmos_settime(struct tm *); void cmos_gettime(struct tm *); @@ -237,17 +240,6 @@ int main(int argc, char **argv) time_t systime; int arg; -#ifdef CONFIG_ARCH_PC98 - unsigned char timebuf[6]; - unsigned char __far *timeaddr; - unsigned int tm_seg; - unsigned int tm_offset; - - timeaddr = (unsigned char __far *)timebuf; - tm_seg = ((long)timeaddr) >> 16; - tm_offset = ((long)timeaddr) & 0xFFFF; -#endif - while ((arg = getopt(argc, argv, "rwsuvA")) != -1) { switch (arg) { case 'r': @@ -289,18 +281,7 @@ int main(int argc, char **argv) readit = 1; if (readit || setit) { - -#ifdef CONFIG_ARCH_PC98 - pc98_read_calendar(tm_seg, tm_offset); - pc98_gettime(&tm, timebuf); -#else -#if AST_SUPPORT - if (astclock) - ast_gettime(&tm); - else -#endif - cmos_gettime(&tm); -#endif + do_gettime(&tm); tm.tm_mon--; /* DOS uses 1 base */ tm.tm_isdst = -1; /* don't know whether it's daylight */ } @@ -381,18 +362,7 @@ int main(int argc, char **argv) tmp = gmtime(&systime); else tmp = localtime(&systime); - -#ifdef CONFIG_ARCH_PC98 - pc98_settime(tmp, timebuf); - pc98_write_calendar(tm_seg, tm_offset); -#else -#if AST_SUPPORT - if (astclock) - ast_settime(tmp); - else -#endif - cmos_settime(tmp); -#endif + do_settime(tmp); } return 0; } @@ -402,6 +372,26 @@ int main(int argc, char **argv) #define CMOS_CMDREG 0x70 #define CMOS_IOREG 0x71 +void do_gettime(struct tm *tm) +{ +#if AST_SUPPORT + if (astclock) + ast_gettime(tm); + else +#endif + cmos_gettime(tm); +} + +void do_settime(struct tm *tm) +{ +#if AST_SUPPORT + if (astclock) + ast_settime(tm); + else +#endif + cmos_settime(tm); +} + #ifdef CONFIG_ARCH_IBMPC unsigned char cmos_read(unsigned char reg) { @@ -467,9 +457,9 @@ void cmos_gettime(struct tm *tm) tm->tm_mon = cmos_read_bcd(8); tm->tm_year = cmos_read_bcd(9); } while (tm->tm_sec != cmos_read_bcd(0)); - if (tm->tm_year < 70) - tm->tm_year += 100; /* 70..99 => 1970..1999, 0..69 => 2000..2069 */ + tm->tm_year += 100; /* 70..99 => 1970..1999, 0..69 => 2000..2069 */ + tm->tm_wday -= 3; /* DOS uses 3 - 9 for week days */ } void cmos_settime(struct tm *tmp) @@ -496,6 +486,28 @@ void cmos_settime(struct tm *tmp) /****************************************************************************/ #ifdef CONFIG_ARCH_PC98 +void do_gettime(struct tm *tm) +{ + unsigned char timebuf[6]; + unsigned char __far *timeaddr = (unsigned char __far *)timebuf; + unsigned int tm_seg = ((long)timeaddr) >> 16; + unsigned int tm_offset = ((long)timeaddr) & 0xFFFF; + + pc98_read_calendar(tm_seg, tm_offset); + pc98_gettime(tm, timebuf); +} + +void do_settime(struct tm *tm) +{ + unsigned char timebuf[6]; + unsigned char __far *timeaddr = (unsigned char __far *)timebuf; + unsigned int tm_seg = ((long)timeaddr) >> 16; + unsigned int tm_offset = ((long)timeaddr) & 0xFFFF; + + pc98_settime(tm, timebuf); + pc98_write_calendar(tm_seg, tm_offset); +} + void pc98_read_calendar(unsigned int tm_seg, unsigned int tm_offset) { __asm__ volatile ("mov %0,%%es;" @@ -537,7 +549,8 @@ void pc98_gettime(struct tm *tm, unsigned char *timebuf) tm->tm_mday = bcd_hex(timebuf[2]); tm->tm_mon = timebuf[1] >> 4; tm->tm_year = bcd_hex(timebuf[0]); - tm->tm_wday -= 3; /* DOS uses 3 - 9 for week days */ + if (tm->tm_year < 70) + tm->tm_year += 100; /* 70..99 => 1970..1999, 0..69 => 2000..2069 */ } void pc98_settime(struct tm *tmp, unsigned char *timebuf)