mandoc(1): Update to 1.9.13.
[dragonfly.git] / usr.bin / doscmd / cmos.c
blob578d0ab2acae4914a72191fcf2acac6ad5d61c68
1 /*
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
7 * are met:
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
16 * Design, Inc.
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
28 * SUCH DAMAGE.
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 $
36 #include "doscmd.h"
38 #define ALARM_ON ((unsigned char) 0x20)
39 #define FAST_TIMER ((unsigned char) 0x40)
40 #define SEC_SIZE 1
41 #define MIN_SIZE 60
42 #define HOUR_SIZE (MIN_SIZE * 60)
43 #define DAY_SIZE (HOUR_SIZE * 24)
44 #define YEAR_DAY 365
46 #define SEC_MS 1000000
47 #define FAST_TICK_BSD 0x3D00
49 #define Jan 31
50 #define Feb 28
51 #define Mar 31
52 #define Apr 30
53 #define May 31
54 #define Jun 30
55 #define Jul 31
56 #define Aug 31
57 #define Sep 31
58 #define Oct 31
59 #define Nov 30
60 #define Dec 31
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 */
83 0x00,
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;
94 /* locals */
95 static struct timeval fast_clock;
96 static int fast_tick;
98 static struct timeval glob_clock;
99 static int cmos_alarm_time = 0;
100 static int cmos_alarm_daytime = 0;
102 static inline int
103 day_in_mon_year(int mon, int year)
105 return day_in_year[mon] + (mon > 2 && (year % 4 == 0));
108 static inline int
109 to_BCD (int n)
111 n &= 0xFF;
112 return n%10 + ((n/10)<<4);
115 static inline int
116 from_BCD (int n)
118 n &= 0xFF;
119 return (n & 0xF) + (n >> 4) * 10;
123 ** inb() from clock ports.
125 ** 0x70 is scratchpad/register select
126 ** 0x71 is data
128 static unsigned char
129 cmos_inb(int portnum)
131 unsigned char ret_val = 0;
132 int cmos_reg;
133 struct timezone tz;
134 struct tm tm = { .tm_sec = 0 };
135 time_t now;
137 switch (portnum) {
138 case 0x70:
139 ret_val = cmos_last_port_70;
140 break;
141 case 0x71:
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);
148 switch (cmos_reg) {
149 case 0:
150 ret_val = to_BCD(tm.tm_sec);
151 break;
152 case 2:
153 ret_val = to_BCD(tm.tm_min);
154 break;
155 case 4:
156 ret_val = to_BCD(tm.tm_hour);
157 break;
158 case 6:
159 ret_val = to_BCD(tm.tm_wday);
160 break;
161 case 7:
162 ret_val = to_BCD(tm.tm_mday);
163 break;
164 case 8:
165 ret_val = to_BCD(tm.tm_mon + 1);
166 break;
167 case 9:
168 ret_val = to_BCD((tm.tm_year + 1900) % 100);
169 break;
170 default:
171 ret_val = cmos_data[cmos_reg];
172 break;
174 break;
176 return (ret_val);
179 static void
180 cmos_outb(int portnum, unsigned char byte)
182 int cmos_reg;
183 int year;
184 int time00;
185 struct timezone tz;
186 struct tm tm = { .tm_sec = 0 };
187 time_t now;
189 switch (portnum) {
190 case 0x70:
191 cmos_last_port_70 = byte;
192 break;
193 case 0x71:
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);
200 switch (cmos_reg) {
201 case 0:
202 delta_clock += SEC_SIZE * (from_BCD(byte) - tm.tm_sec);
203 break;
204 case 1:
205 cmos_alarm_daytime +=
206 SEC_SIZE * (from_BCD(byte) - from_BCD(cmos_data[1]));
207 break;
208 case 2:
209 delta_clock += MIN_SIZE * (from_BCD(byte) - tm.tm_min);
210 break;
211 case 3:
212 cmos_alarm_daytime +=
213 MIN_SIZE * (from_BCD(byte) - from_BCD(cmos_data[3]));
214 break;
215 case 4:
216 delta_clock += HOUR_SIZE * (from_BCD(byte) - tm.tm_hour);
217 break;
218 case 5:
219 cmos_alarm_daytime +=
220 HOUR_SIZE * (from_BCD(byte) - from_BCD(cmos_data[5]));
221 break;
222 case 7:
223 delta_clock += DAY_SIZE * (from_BCD(byte) - tm.tm_mday);
224 break;
225 case 8:
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));
229 break;
230 case 9:
231 year = from_BCD(byte);
232 delta_clock += DAY_SIZE * (YEAR_DAY * (year - tm.tm_year)
233 + (year/4 - tm.tm_year/4));
234 break;
235 case 0xB:
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;
249 fast_tick = 0;
251 break;
253 cmos_data[cmos_reg] = byte;
254 break;
259 void
260 cmos_init(void)
262 int numflops = 0;
263 int checksum = 0;
264 int i;
266 cmos_data[0x0e] = 0;
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);