summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/i386/go32/clock/rtc.c
blob: 6a28c229adceeb63c8acad274a2a5b2d88926e7e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/* 
 *  $Id$
 */

#define IO_RTC		0x70	/* RTC */

#define RTC_SEC		0x00	/* seconds */
#define RTC_SECALRM	0x01	/* seconds alarm */
#define RTC_MIN		0x02	/* minutes */
#define RTC_MINALRM	0x03	/* minutes alarm */
#define RTC_HRS		0x04	/* hours */
#define RTC_HRSALRM	0x05	/* hours alarm */
#define RTC_WDAY	0x06	/* week day */
#define RTC_DAY		0x07	/* day of month */
#define RTC_MONTH	0x08	/* month of year */
#define RTC_YEAR	0x09	/* month of year */
#define RTC_STATUSA	0x0a	/* status register A */
#define  RTCSA_TUP	 0x80	/* time update, don't look now */

#define RTC_STATUSB	0x0b	/* status register B */

#define RTC_INTR	0x0c	/* status register C (R) interrupt source */
#define  RTCIR_UPDATE	 0x10	/* update intr */
#define  RTCIR_ALARM	 0x20	/* alarm intr */
#define  RTCIR_PERIOD	 0x40	/* periodic intr */
#define  RTCIR_INT	 0x80	/* interrupt output signal */

#define RTC_STATUSD	0x0d	/* status register D (R) Lost Power */
#define  RTCSD_PWR	 0x80	/* clock lost power */

#define RTC_DIAG	0x0e	/* status register E - bios diagnostic */
#define RTCDG_BITS	"\020\010clock_battery\007ROM_cksum\006config_unit\005memory_size\004fixed_disk\003invalid_time"

#define RTC_CENTURY	0x32	/* current century - increment in Dec99 */



#include <rtems.h>
#include <memory.h>

void init_rtc( void )
{
    int s;

	/* initialize brain-dead battery powered clock */
	outport_byte( IO_RTC, RTC_STATUSA );
	outport_byte( IO_RTC+1, 0x26 );
	outport_byte( IO_RTC, RTC_STATUSB );
	outport_byte( IO_RTC+1, 2 );

	outport_byte( IO_RTC, RTC_DIAG );
	inport_byte( IO_RTC+1, s );
#if 0
	if (s) printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
#endif
}


/* convert 2 digit BCD number */
static int bcd( unsigned int i )
{
	return ((i/16)*10 + (i%16));
}

/* convert years to seconds (from 1970) */
static unsigned long ytos( int y )
{
	int i;
	unsigned long ret;

	ret = 0;
	for(i = 1970; i < y; i++) {
		if (i % 4) ret += 365*24*60*60;
		else ret += 366*24*60*60;
	}
	return ret;
}

/* convert months to seconds */
static unsigned long mtos( int m, int leap )
{
	int i;
	unsigned long ret;

	ret = 0;
	for(i=1;i<m;i++) {
		switch(i){
		case 1: case 3: case 5: case 7: case 8: case 10: case 12:
			ret += 31*24*60*60;
			break;
		case 4: case 6: case 9: case 11:
			ret += 30*24*60*60;
			break;
		case 2:
			if (leap)
			    ret += 29*24*60*60;
			else
			    ret += 28*24*60*60;
		}
	}
	return ret;
}


static inline unsigned int rtcin( unsigned int what )
{
    unsigned int r;
    outport_byte( IO_RTC, what );
    inport_byte( IO_RTC+1, r );
    return r;
}


/*
 * Initialize the time of day register, based on the time base which is, e.g.
 * from a filesystem.
 */
long rtc_read( rtems_time_of_day * tod )
{
        int sa;
	unsigned long sec = 0;

	memset( tod, 0, sizeof *tod );

	/* do we have a realtime clock present? (otherwise we loop below) */
	sa = rtcin(RTC_STATUSA);
	if (sa == 0xff || sa == 0)
	    return -1;

	/* ready for a read? */
	while ((sa&RTCSA_TUP) == RTCSA_TUP)
	    sa = rtcin(RTC_STATUSA);

	tod->year	= bcd(rtcin(RTC_YEAR)) + 1900;	/* year	  */
	if (tod->year < 1970)	tod->year += 100;	
	tod->month	= bcd(rtcin(RTC_MONTH));	/* month   */
	tod->day	= bcd(rtcin(RTC_DAY));		/* day	   */
	(void)		  bcd(rtcin(RTC_WDAY));		/* weekday */
	tod->hour	= bcd(rtcin(RTC_HRS));		/* hour    */
	tod->minute	= bcd(rtcin(RTC_MIN));		/* minutes */
	tod->second	= bcd(rtcin(RTC_SEC));		/* seconds */
	tod->ticks	= 0;
#if 0
	sec = ytos( tod->year );
	sec += mtos( tod->month, tod->year % 4 == 0 );
	sec += tod->day * 24*60*60;
	sec += tod->hour * 60*60;			/* hour    */
	sec += tod->minute * 60;			/* minutes */
	sec += tod->second;				/* seconds */
#else
	sec = 0;
#endif
	return sec;
}



/* from djgpp: include before rtems.h to avoid conflicts */
#undef delay
#include <dos.h>

void rtc_set_dos_date( void )
{
    int s;
    struct date date;
    struct time time;

    /* initialize brain-dead battery powered clock */
    outport_byte( IO_RTC, RTC_STATUSA );
    outport_byte( IO_RTC+1, 0x26 );
    outport_byte( IO_RTC, RTC_STATUSB );
    outport_byte( IO_RTC+1, 2 );

    outport_byte( IO_RTC, RTC_DIAG );
    inport_byte( IO_RTC+1, s );
    if (s)  {
#if 0
	printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
#else
	return;
#endif
    }

    /* check for presence of clock */
    s = rtcin(RTC_STATUSA);
    if ( s == 0xff  ||  s == 0 )  {
#if 0
	printf( "Real-time clock not found\n" );
#endif
	return;
    }

    /* ready for a read? */
    while ((s & RTCSA_TUP) == RTCSA_TUP)
	s = rtcin(RTC_STATUSA);

    date.da_year	= bcd(rtcin(RTC_YEAR)) + 1900;	/* year	  */
    if ( date.da_year < 1970)	date.da_year += 100;
    date.da_year	-= 1980;
    date.da_mon		= bcd(rtcin(RTC_MONTH));	/* month   */
    date.da_day		= bcd(rtcin(RTC_DAY));		/* day	   */

    (void)bcd(rtcin(RTC_WDAY));		/* weekday */

    time.ti_hour	= bcd(rtcin(RTC_HRS));		/* hour    */
    time.ti_min		= bcd(rtcin(RTC_MIN));		/* minutes */
    time.ti_sec		= bcd(rtcin(RTC_SEC));		/* seconds */
    time.ti_hund	= 0;

    setdate( & date );
    settime( & time );
}