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