subelman@ttidca.TTI.COM (Ed Subelman) (06/03/87)
My XT Clone 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 the programs posted on this group to read an AST card and set the minix date at boot time. They failed miserably. I then poked around the program that came with my machine and figured out how to read the clock. I also figured out why you need to read the hard card more than once to get the time right. See the comments. Until the shell can handle shar files, this file should be cut into two pieces: timedate.c and port_io.s. --------- begin of timedate.c -------------- cut here -------- /* timedate.c - get date and time from Multi I/O Card * and print on standard out. Format is MMDDYYHHMMSS * as required by "date". * Should be run in /etc/rc as: date `/usr/bin/timedate` * Compile as: cc -o timedate timedate.c port_io.s * * Author: Ed Subelman 5/87 */ #include <stdio.h> struct tm { int year; int month; int day; int hour; int min; int sec; }; /* ports for the hard clock; first is the index, next is the data */ #define CLK_CNTL 0x033A #define CLK_COMD 0x0338 /* registers on the hard clock; data returned in lowest 4 bits */ #define SEC_1s 0x50 #define SEC_10s 0x51 #define MIN_1s 0x52 #define MIN_10s 0x53 #define HR_1s 0x54 #define HR_10s 0x55 #define WK_DAY 0x56 #define DAY_1s 0x57 #define DAY_10s 0x58 #define MON_1s 0x59 #define MON_10s 0x5A #define YR_1s 0x5B #define YR_10s 0x5C /* Commands for index port. I just disassembled the program that came with the card. Seems to work */ #define COM0 0x00 #define COM1 0x10 #define COM2 0x40 /* Bit masks */ #define LOW_4 0x0f #define LOW_2 0x03 #define AM_PM 0x04 #define TRIES 10 /* number of times to read clock */ main(argc, argv) int argc; char *argv[]; { struct tm tm1; struct tm tm2; int i; /* try several times to read the clock. This is needed to avoid the following sequence of events: time is 03:59:59.99 you read the hour: 03 the hard clock ticks: time is 04:00:00.00 you read the minutes: 00. You are off by 1 hour! */ for (i = 0; i < TRIES; i++) { read_clk(&tm1); /* read the clock twice */ read_clk(&tm2); if (tm1.year == tm2.year /* and compare the results */ && tm1.month == tm2.month && tm1.day == tm2.day && tm1.hour == tm2.hour && tm1.min == tm2.min && tm1.sec == tm2.sec) { printf("%02d%02d%02d%02d%02d%02d\n", tm1.month, tm1.day, tm1.year, tm1.hour, tm1.min, tm1.sec); exit(0); /* normal termination */ } } /* too many errors in reading the clock give up */ fprintf(stderr, "%s: hard clock unstable\n", argv[0]); fflush(stderr); _cleanup(); exit(1); } /* read the hard clock and fill values into a tm structure */ read_clk(tp) struct tm *tp; { int tmp; port_out(CLK_CNTL, COM1); /* prepare clock */ port_out(CLK_COMD, COM2); tp->year = get_val(YR_10s) * 10 + get_val(YR_1s); tp->month = get_val(MON_10s) * 10 + get_val(MON_1s); tp->day = (get_val(DAY_10s) & LOW_2) * 10 + get_val(DAY_1s); /* Card runs on 12 hour clock. Must convert to 24 hour */ tmp = get_val(HR_10s); /* save AM/PM indicator */ tp->hour = (tmp & LOW_2) * 10 + get_val(HR_1s); if (tp->hour == 12) tp->hour = 0; if (tmp & AM_PM) tp->hour += 12; tp->min = get_val(MIN_10s) * 10 + get_val(MIN_1s); tp->sec = get_val(SEC_10s) * 10 + get_val(SEC_1s); port_out(CLK_COMD, COM2); /* restart clock? */ port_out(CLK_COMD, COM0); port_out(CLK_CNTL, COM0); } /* get_val() - read a register from the hard clock */ int get_val(reg) int reg; { int val; port_out(CLK_COMD, reg); /* index on the register desired */ port_in (CLK_COMD, &val); /* and get the value of the reg */ return (val & LOW_4); /* make sure lower 4 bits only */ } ------------ begin of port_io.s ----------- cut here -------- | this file was grafted from klib88.s .globl _port_out, _port_in |*===========================================================================* |* port_out * |*===========================================================================* | port_out(port, value) writes 'value' on the I/O port 'port'. _port_out: push bx | save bx mov bx,sp | index off bx push ax | save ax push dx | save dx mov dx,4(bx) | dx = port mov ax,6(bx) | ax = value out | output 1 byte pop dx | restore dx pop ax | restore ax pop bx | restore bx ret | return to caller |*===========================================================================* |* port_in * |*===========================================================================* | port_in(port, &value) reads from port 'port' and puts the result in 'value'. _port_in: push bx | save bx mov bx,sp | index off bx push ax | save ax push dx | save dx mov dx,4(bx) | dx = port in | input 1 byte xorb ah,ah | clear ah mov bx,6(bx) | fetch address where byte is to go mov (bx),ax | return byte to caller in param pop dx | restore dx pop ax | restore ax pop bx | restore bx ret | return to caller ------------ end of port_io.s ------- cut here --------- -- Ed Subelman {csun|philabs|psivax|trwrb}!ttidca!subelman Citicorp(+)TTI (213) 450-9111, x2972 3100 Ocean Park Blvd., Santa Monica, CA 90405