2 * Copyright (c) 1992, 1993, 1996
3 * Berkeley Software Design, Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Berkeley Software
18 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * BSDI cmos.c,v 2.3 1996/04/08 19:32:20 bostic Exp
32 * $FreeBSD: src/usr.bin/doscmd/cmos.c,v 1.2.2.2 2002/04/25 11:04:50 tg Exp $
33 * $DragonFly: src/usr.bin/doscmd/cmos.c,v 1.2 2003/06/17 04:29:25 dillon Exp $
38 #define ALARM_ON ((unsigned char) 0x20)
39 #define FAST_TIMER ((unsigned char) 0x40)
42 #define HOUR_SIZE (MIN_SIZE * 60)
43 #define DAY_SIZE (HOUR_SIZE * 24)
46 #define SEC_MS 1000000
47 #define FAST_TICK_BSD 0x3D00
62 static unsigned char cmos_last_port_70
= 0;
63 static unsigned char cmos_data
[0x40] = {
64 0x00, /* 0x00 Current Second */
65 0x00, /* 0x01 Alarm Second */
66 0x00, /* 0x02 Current minute */
67 0x00, /* 0x03 Alarm minute */
68 0x00, /* 0x04 Current hour */
69 0x00, /* 0x05 Alarm hour */
70 0x00, /* 0x06 Current week day */
71 0x00, /* 0x07 Current day */
72 0x00, /* 0x08 Current month */
73 0x00, /* 0x09 Current year */
74 0x26, /* 0x0A Status register A */
75 0x02, /* 0x0B Status register B */
76 0x00, /* 0x0C Status register C */
77 0x80, /* 0x0D Status register D */
78 0x00, /* 0x0E Diagnostic status */
79 0x00, /* 0x0F Shutdown Code */
80 0x00, /* 0x10 Drive types (1 FDHD disk) */
81 0x00, /* 0x11 Fixed disk 0 type */
82 0x00, /* 0x12 Fixed disk 1 type */
84 0x00, /* Installed equipment */
87 int day_in_year
[12] = {
88 0, Jan
, Feb
, Mar
, Apr
, May
, Jun
, Jul
, Aug
, Sep
, Oct
, Nov
91 /* consumed by dos.c */
92 time_t delta_clock
= 0;
95 static struct timeval fast_clock
;
98 static struct timeval glob_clock
;
99 static int cmos_alarm_time
= 0;
100 static int cmos_alarm_daytime
= 0;
103 day_in_mon_year(int mon
, int year
)
105 return day_in_year
[mon
] + (mon
> 2 && (year
% 4 == 0));
112 return n
%10 + ((n
/10)<<4);
119 return (n
& 0xF) + (n
>> 4) * 10;
123 ** inb() from clock ports.
125 ** 0x70 is scratchpad/register select
129 cmos_inb(int portnum
)
131 unsigned char ret_val
= 0;
134 struct tm tm
= { .tm_sec
= 0 };
139 ret_val
= cmos_last_port_70
;
142 cmos_reg
= cmos_last_port_70
& 0x3f;
143 if (cmos_reg
< 0xa) {
144 gettimeofday(&glob_clock
, &tz
);
145 now
= glob_clock
.tv_sec
+ delta_clock
;
146 tm
= *localtime(&now
);
150 ret_val
= to_BCD(tm
.tm_sec
);
153 ret_val
= to_BCD(tm
.tm_min
);
156 ret_val
= to_BCD(tm
.tm_hour
);
159 ret_val
= to_BCD(tm
.tm_wday
);
162 ret_val
= to_BCD(tm
.tm_mday
);
165 ret_val
= to_BCD(tm
.tm_mon
+ 1);
168 ret_val
= to_BCD((tm
.tm_year
+ 1900) % 100);
171 ret_val
= cmos_data
[cmos_reg
];
180 cmos_outb(int portnum
, unsigned char byte
)
186 struct tm tm
= { .tm_sec
= 0 };
191 cmos_last_port_70
= byte
;
194 cmos_reg
= cmos_last_port_70
& 0x3f;
195 if (cmos_reg
< 0xa) {
196 gettimeofday(&glob_clock
, &tz
);
197 now
= glob_clock
.tv_sec
+ delta_clock
;
198 tm
= *localtime(&now
);
202 delta_clock
+= SEC_SIZE
* (from_BCD(byte
) - tm
.tm_sec
);
205 cmos_alarm_daytime
+=
206 SEC_SIZE
* (from_BCD(byte
) - from_BCD(cmos_data
[1]));
209 delta_clock
+= MIN_SIZE
* (from_BCD(byte
) - tm
.tm_min
);
212 cmos_alarm_daytime
+=
213 MIN_SIZE
* (from_BCD(byte
) - from_BCD(cmos_data
[3]));
216 delta_clock
+= HOUR_SIZE
* (from_BCD(byte
) - tm
.tm_hour
);
219 cmos_alarm_daytime
+=
220 HOUR_SIZE
* (from_BCD(byte
) - from_BCD(cmos_data
[5]));
223 delta_clock
+= DAY_SIZE
* (from_BCD(byte
) - tm
.tm_mday
);
226 delta_clock
+= DAY_SIZE
*
227 (day_in_mon_year(from_BCD(byte
), tm
.tm_year
) -
228 day_in_mon_year(tm
.tm_mon
+ 1, tm
.tm_year
));
231 year
= from_BCD(byte
);
232 delta_clock
+= DAY_SIZE
* (YEAR_DAY
* (year
- tm
.tm_year
)
233 + (year
/4 - tm
.tm_year
/4));
236 cmos_data
[0xc] = byte
;
237 if (byte
& ALARM_ON
) {
238 debug(D_ALWAYS
, "Alarm turned on\n");
239 time00
= glob_clock
.tv_sec
+ delta_clock
-
240 (tm
.tm_sec
+ MIN_SIZE
* tm
.tm_min
241 + HOUR_SIZE
* tm
.tm_hour
);
242 cmos_alarm_time
= time00
+ cmos_alarm_daytime
;
243 if (cmos_alarm_time
< (glob_clock
.tv_sec
+ delta_clock
))
244 cmos_alarm_time
+= DAY_SIZE
;
246 if (byte
& FAST_TIMER
) {
247 debug(D_ALWAYS
, "Fast timer turned on\n");
248 fast_clock
= glob_clock
;
253 cmos_data
[cmos_reg
] = byte
;
268 numflops
= nfloppies
;
269 cmos_data
[0x10] = (search_floppy(0) << 4) | search_floppy(1);
271 if (numflops
) /* floppy drives present + numflops */
272 cmos_data
[0x14] = ((numflops
- 1) << 6) | 1;
274 cmos_data
[0x15] = 0x80; /* base memory 640k */
275 cmos_data
[0x16] = 0x2;
276 for (i
=0x10; i
<=0x2d; i
++)
277 checksum
+= cmos_data
[i
];
278 cmos_data
[0x2e] = checksum
>>8; /* High byte */
279 cmos_data
[0x2f] = checksum
& 0xFF; /* Low byte */
281 cmos_data
[0x32] = 0x19; /* Century in BCD ; temporary */
283 for (i
= 1; i
< 12; i
++){
284 day_in_year
[i
] += day_in_year
[i
-1];
287 define_input_port_handler(0x70, cmos_inb
);
288 define_input_port_handler(0x71, cmos_inb
);
289 define_output_port_handler(0x70, cmos_outb
);
290 define_output_port_handler(0x71, cmos_outb
);