[comp.os.minix] another real-time clock utility

MEGEVAND%CGEUGE51.BITNET@cunyvm.cuny.edu (02/02/88)

        Hello,

        My XT Clone also has a Calendar/Clock on a card labelled "Multi I/O"
that also contains the Floppy Disk controller, a parallel port, a serial port
and a joystick controller port.

        I tried to use three programs posted on this group to read the battery
backup clock: One was for the AT clock. Another was for an AST card, and the
last was for another Multi-I/O card. None of the three worked.

        So, as the other guys, I debugged my own card program, and was soon able
to read the date and time from the card and set the minix date at boot time.

        Here is a shar file: This is my contribution in case someone uses the
same card as me.

================================================================================
E-Mail:                             ||            Denis Megevand
           megevand@cgeuge51.bitnet ||           Geneva Observatory
=================================== ||           51 ch. des Maillettes
soon to be                          ||          CH-1290 SAUVERNY
           megevand@cgeuge54.bitnet ||                  SWITZERLAND
================================================================================

--------------------------- cut here ------------------------------------------
#
# This is a shar archive, extract it with sh, not csh.
# The rest of this file will extract:
# Makefile, timedate.c, port_io.s
#
echo x - Makefile
gres '^X' '' > Makefile << '/'
X#makefile for "timedate"
X
Xall:
X       cc -F -o /usr/bin/timedate timedate.c port_io.s
X
X
/
echo x - timedate.c
gres '^X' '' > timedate.c << '/'
X/* timedate.c  - get date and time from a Multi I/O Card
X * and print on standard out. Format is MMDDYYHHMMSS
X * as required by "date".
X * Should be run in /etc/rc as:  date `/usr/bin/timedate`
X * Compile as: cc -F -o timedate timedate.c port_io.s
X *
X * Author: Denis Megevand - January 1988
X *        (adapted from other utilities)
X */
X
X#include <stdio.h>
X
Xstruct tm {
X        int year;
X        int month;
X        int day;
X        int hour;
X        int min;
X        int sec;
X};
X
X/* Ports for the hard clock:
X * You need to read both ports until bit0 of result is 0
X * before getting date.
X */
X
X#define CLK_PORT        0x0377
X#define CLK_STATUS      0x5377
X
X/* Data ports on the hard clock:
X * Data returned is two BCD digits
X */
X
X#define SECONDS         0x0B77
X#define MINUTES         0x0F77
X#define HOURS           0x1377
X#define DAY             0x1B77
X#define MONTH           0x1F77
X
X/* Data ports on the hard clock:
X * Data returned is encoded as 11xx11xx
X */
X
X#define YEAR_LOW        0x2777
X#define YEAR_HIGH       0x2377
X
X/* Bit masks */
X
X#define BIT_0           0x01
X#define BITS1_0         0x03
X#define BITS3_2         0x0C
X#define BITS3_0         0x0F
X#define BITS5_4         0x30
X#define BITS7_6         0xC0
X#define BITS7_4         0xF0
X
X/* Maximum number of times to read clock */
X
X#define TRIES           10
X
X
Xmain(argc, argv)
X        int argc;
X        char *argv[];
X{
X        struct tm tm1;
X        struct tm tm2;
X        int i;
X
X/* Try several times to read the clock.*/
X
X        for (i = 0; i < TRIES; i++)
X        {
X                read_clk(&tm1);                 /* read the clock twice */
X                read_clk(&tm2);
X
X                if (   tm1.year  == tm2.year    /* and compare the results */
X                    && tm1.month == tm2.month
X                    && tm1.day   == tm2.day
X                    && tm1.hour  == tm2.hour
X                    && tm1.min   == tm2.min
X                    && tm1.sec   == tm2.sec)
X                {
X                        printf("%02d%02d%02d%02d%02d%02d\n",
X                                tm1.month, tm1.day, tm1.year,
X                                tm1.hour,  tm1.min, tm1.sec);
X                        exit(0);                /* normal termination */
X                }
X        }
X
X/* too many errors in reading the clock give up */
X
X        fprintf(stderr, "%s: hard clock unstable\n", argv[0]);
X        fflush(stderr);
X        _cleanup();
X        exit(1);
X}
X
X/* read the hard clock and fill values into a tm structure */
X
Xread_clk(tp)
X        struct tm *tp;
X{
X        int tmp;
X
X        do {
X             port_in(CLK_PORT, &tmp);       /* prepare clock */
X             port_in(CLK_STATUS, &tmp);
X        } while (tmp & BIT_0 != 0);
X
X        tp->year  = 80 + get_val(YEAR_HIGH) * 4 + get_val(YEAR_LOW);
X        tp->month = get_BCD(MONTH);
X        tp->day   = get_BCD(DAY);
X        tp->hour  = get_BCD(HOURS);
X        tp->min   = get_BCD(MINUTES);
X        tp->sec   = get_BCD(SECONDS);
X
X}
X
X/* get_val() - read a encoded register from the hard clock */
X
Xint get_val(reg)
X
X        int reg;
X
X{
X        int val;
X
X        port_in (reg, &val);       /* get the value of the reg */
X
X        return ((val & BITS1_0) + ((val / 4) & BITS3_2));
X
X}
X
X/* get_BCD() - read a BCD register from the hard clock */
X
Xint get_BCD(reg)
X
X        int reg;
X
X{
X        int val;
X
X        port_in (reg, &val);       /* get the value of the reg */
X
X        return ((val & BITS7_4) / 16 * 10 + (val  & BITS3_0));
X
X}
X
/
echo x - port_io.s
gres '^X' '' > port_io.s << '/'
X| this file was grafted from klib88.s
X
X.globl _port_out, _port_in
X
X
X
X|*===========================================================================*
X|*                              port_out   *
X|*===========================================================================*
X| port_out(port, value) writes 'value' on the I/O port 'port'.
X
X_port_out:
X        push bx                 | save bx
X        mov bx,sp               | index off bx
X        push ax                 | save ax
X        push dx                 | save dx
X        mov dx,4(bx)            | dx = port
X        mov ax,6(bx)            | ax = value
X        out                     | output 1 byte
X        pop dx                  | restore dx
X        pop ax                  | restore ax
X        pop bx                  | restore bx
X        ret                     | return to caller
X
X
X|*===========================================================================*
X|*                              port_in   *
X|*===========================================================================*
X| port_in(port, &value) reads from port 'port' and puts the result in 'value'.
X_port_in:
X        push bx                 | save bx
X        mov bx,sp               | index off bx
X        push ax                 | save ax
X        push dx                 | save dx
X        mov dx,4(bx)            | dx = port
X        in                      | input 1 byte
X        xorb ah,ah              | clear ah
X        mov bx,6(bx)            | fetch address where byte is to go
X        mov (bx),ax             | return byte to caller in param
X        pop dx                  | restore dx
X        pop ax                  | restore ax
X        pop bx                  | restore bx
X        ret                     | return to caller
/